/
Manifest
/
Real_Texture
Обзор
Документация
Войти
/
Manifest
/
Real_Texture
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
ToolsPythonForSequenceInUE/HideEnv.py
290 строк
13 KB
m.samodurov
init commit for The Invaders
17 фев 2026, 04:57
17 фев 2026, 04:57
4a668d4
Код
Авторство
О чём код?
import unreal import re import math "======================================================================================================" "=================================РЕДАКТИРУЕМЫЕ ПАРАМЕТРЫ==============================================" "======================================================================================================" max_distance = 10000 # В Сантиметрах. Default = 10000. Ограничение по дефолту в 10000 см (100 метров) для Occlusion Culling extent_scale = 1.0 # В десятичных от процента (1.5 = 50%). Default = 1. Коэффициент искусственного увеличения BoxExtent объектов в камере padding_degrees_for_FoV = 0 # В радианах. Default = 0. Добавление падинга по горизонтали и вертикали duration = 10 # В Секундах. Default = 10. Длительность DEBUG-пирамиды. Таймер отсчитывается в stat fps только. Не в ран-тайме всё время висит "Папки для игнорирования в Outliner'е; Запись через r" # TODO: Символ \d+ равносилен регулярке *; IGNORE_FOLDERS = \ [ r"sq\d+_sh\d+_light", #r"Decals", #<- Если надо убрать декали? r"ProxyGeo", r"River", r"City", r"light", ] "Имена объектов (любых) для игнорирования в Outliner'е" IGNORE_NAMES = \ [ "cheba_2_BP", "gena_2_BP", "lariska_BP", "shapoklyak_BP", "galya" ] "Классы объектов по типу для игнорирования в Outliner'е" IGNORE_CLASSES = \ ( unreal.SkeletalMeshActor, #unreal.DecalActor, #<- Если надо убрать декали? unreal.CineCameraActor, unreal.GroupActor, unreal.GeometryCache, ) "======================================================================================================" "=================================ВСПОМОГАТЕЛЬНЫЕ И ОСНОВНЫЕ ФУНКЦИИ===================================" "Вспомогательная функция приведения к единичному вектору, ибо UE не имеет норм функции" def normalize_vector(vec): length = vec.length() if length > 0: return vec / length return vec # Если длина 0, возвращаем оригинал (или Vector(0,0,0) можно, пока хз) "Вспомогательная функция для [DEBUG] Occlusion Culling'а" def draw_camera_frustum(camera, horizontal_fov_deg, aspect_ratio, max_distance=max_distance, duration=duration): world = camera.get_world() cam_location = camera.get_actor_location() cam_rotation = camera.get_actor_rotation() horizontal_fov = math.radians(horizontal_fov_deg) vertical_fov = horizontal_fov / aspect_ratio fov_padding = math.radians(padding_degrees_for_FoV) horizontal_fov += fov_padding vertical_fov += fov_padding yaw_rad = math.radians(cam_rotation.yaw) pitch_rad = math.radians(cam_rotation.pitch) def get_dir_vector(yaw_offset, pitch_offset): yaw = yaw_rad + yaw_offset pitch = pitch_rad + pitch_offset vec = unreal.Vector( math.cos(pitch) * math.cos(yaw), math.cos(pitch) * math.sin(yaw), math.sin(pitch) ) return normalize_vector(vec) half_h_fov = horizontal_fov / 2 half_v_fov = vertical_fov / 2 corners = \ [ get_dir_vector(-half_h_fov, half_v_fov), # верхний левый get_dir_vector( half_h_fov, half_v_fov), # верхний правый get_dir_vector(-half_h_fov, -half_v_fov), # нижний левый get_dir_vector( half_h_fov, -half_v_fov), # нижний правый ] line_color = unreal.LinearColor(1, 0, 0, 1) thickness = 2.0 for corner_dir in corners: end_point = cam_location + corner_dir * max_distance unreal.SystemLibrary.draw_debug_line(world, cam_location, end_point, line_color, duration, thickness) for i in range(4): start = cam_location + corners[i] * max_distance end = cam_location + corners[(i + 1) % 4] * max_distance unreal.SystemLibrary.draw_debug_line(world, start, end, line_color, duration, thickness) """ Вспомогательная функция Occlusion Culling для проверки попадания Bounding Box (AABB по 8 точкам) актора в пределы поля зрения камеры (упрощённый frustum check/project_world_to_screen). Ограничен max_distance """ def is_actor_in_frustum(actor, camera, horizontal_fov_deg, aspect_ratio, max_distance=max_distance): # Получаем BBox и transform камеры origin, box_extent = actor.get_actor_bounds(False) cam_transform = camera.get_actor_transform() # Увеличиваем размер Bounding Box'а (искусственно) box_extent *= extent_scale # Перевод FOV в радианы horizontal_fov = math.radians(horizontal_fov_deg) vertical_fov = horizontal_fov / aspect_ratio # Добавляем небольшой запас к FOV по padding fov_padding = math.radians(padding_degrees_for_FoV) horizontal_fov += fov_padding vertical_fov += fov_padding # Проверяем все 8 углов BBox'а for x in [-1, 1]: for y in [-1, 1]: for z in [-1, 1]: corner = origin + unreal.Vector(x*box_extent.x, y*box_extent.y, z*box_extent.z) # Преобразуем в локальные координаты камеры local_pos = unreal.MathLibrary.inverse_transform_location(cam_transform, corner) # За камерой — игнорируем if local_pos.x < 0: continue # Дальность больше допустимой - игнорируем distance = local_pos.length() if distance > max_distance: continue # Углы между направлением камеры и точкой hor_angle = abs(math.atan2(local_pos.y, local_pos.x)) vert_angle = abs(math.atan2(local_pos.z, local_pos.x)) # Внутри frustum — значит актор видим if hor_angle < horizontal_fov/2 and vert_angle < vertical_fov/2: return True return False """ ================================================ # ОСНОВНАЯ ФУНКЦИЯ ДЛЯ ДУБЛИРОВАНИЯ АКТЁРОВ ================================================ """ def DublicateEnv(): unreal.log_warning("[DublicateEnv] Начало скрипта дублирования") # =============================== # Получаем текущий открытый Level Sequence # =============================== current_sequence = unreal.LevelSequenceEditorBlueprintLibrary.get_focused_level_sequence() if not current_sequence: unreal.log_error("[DublicateEnv] Нет открытого Level Sequence") return else: unreal.log(f"[DublicateEnv] Открытый Level Sequence: {current_sequence.get_name()}") # =============================== # Активируем SubLevel по текущему Sequence # =============================== seq_name = current_sequence.get_name() base_name = seq_name[:-6] if seq_name.endswith("_LSQ_1") else seq_name sublevel_name = base_name + "_LVL_1" level_editor_subsystem = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem) success = level_editor_subsystem.set_current_level_by_name(sublevel_name) if success: unreal.log(f"[DublicateEnv] Активирован уровень: {sublevel_name}") else: unreal.log_error(f"[DublicateEnv] SubLevel {sublevel_name} не найден") return # =============================== # Получаем все актеры активного уровня # =============================== editor_world = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem).get_editor_world() sub_levels = unreal.EditorLevelUtils.get_levels(editor_world) visible_level_paths = set() for level in sub_levels: level_package_name = level.get_package().get_name() streaming_level = unreal.GameplayStatics.get_streaming_level(editor_world, level_package_name) if streaming_level and streaming_level.is_level_visible(): visible_level_paths.add(level_package_name) actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem) all_actors = [ actor for actor in actor_subsystem.get_all_level_actors() if actor.get_level().get_package().get_name() in visible_level_paths ] camera = next((a for a in all_actors if isinstance(a, unreal.CineCameraActor)), None) if not camera: unreal.log_error("[DublicateEnv] Камера не найдена") return unreal.log(f"[DublicateEnv] Найдена камера: {camera.get_actor_label()}") camera_component = camera.get_cine_camera_component() horizontal_fov = camera_component.get_horizontal_field_of_view() aspect_ratio = camera_component.aspect_ratio # =============================== # Создание корневого актора для дубликатов # =============================== existing_root_actor = next((a for a in all_actors if a.get_actor_label() == "Actor_for_Copy"), None) if existing_root_actor: unreal.log_error("[DublicateEnv] Actor_for_Copy уже существует") return root_actor = actor_subsystem.spawn_actor_from_class(unreal.Actor, unreal.Vector(0, 0, 0)) if not root_actor: unreal.log_error("[DublicateEnv] Не удалось создать Actor_for_Copy") return root_actor.set_actor_label("Actor_for_Copy") # Преобразование уровня в LevelStreaming для дальнейшей работы с RootActor (Actor_for_Group) active_streaming_level = None for subLevel in sub_levels: subLevelPackageName = subLevel.get_package().get_name() streamingLevel = unreal.GameplayStatics.get_streaming_level(editor_world, subLevelPackageName) if streamingLevel and streamingLevel.is_level_visible() and subLevelPackageName.endswith(sublevel_name): active_streaming_level = streamingLevel break if not active_streaming_level: unreal.log_error("[DublicateEnv] Не найден активный streaming level") return unreal.EditorLevelUtils.move_actors_to_level([root_actor], active_streaming_level) unreal.log(f"[DublicateEnv] Создан актор: {root_actor.get_actor_label()}") # =============================== # Дублирование актёров # =============================== for actor in all_actors: actor_level_path = actor.get_level().get_package().get_name() folder_path = str(actor.get_folder_path()) if any(re.match(pattern, folder_path) for pattern in IGNORE_FOLDERS): continue if actor.get_actor_label() in IGNORE_NAMES: continue if isinstance(actor, IGNORE_CLASSES): continue if actor_level_path in visible_level_paths and not isinstance(actor, unreal.CineCameraActor): if not is_actor_in_frustum(actor, camera, horizontal_fov, aspect_ratio, max_distance): continue duplicated_actor = actor_subsystem.duplicate_actor(actor, editor_world) if duplicated_actor: duplicated_actor.set_actor_label(actor.get_actor_label() + "_copy") unreal.EditorLevelUtils.move_actors_to_level([duplicated_actor], active_streaming_level) duplicated_actor.attach_to_actor(root_actor, unreal.Name(""), unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False) else: unreal.log_warning(f"[DublicateEnv] Не удалось дублировать актор: {actor.get_name()}") # =============================== # Рисуем дебаг-фрустум # =============================== draw_camera_frustum(camera, horizontal_fov, aspect_ratio) unreal.log_warning("[DublicateEnv] Скрипт дублирования завершён") # ================================================ # MAIN # ================================================ def main(): DublicateEnv() if __name__ == "__main__": main()