Fix light registration handling
This commit is contained in:
parent
6e76b54ddb
commit
8a80af9825
@ -8,10 +8,109 @@ def _is_valid_node(node) -> bool:
|
||||
return bool(node) and hasattr(node, "isEmpty") and (not node.isEmpty())
|
||||
|
||||
|
||||
def _is_light_node(node: NodePath) -> bool:
|
||||
return bool(node) and hasattr(node, "hasTag") and node.hasTag("light_type")
|
||||
|
||||
|
||||
def _is_terrain_node(node: NodePath) -> bool:
|
||||
return bool(node) and hasattr(node, "hasTag") and node.hasTag("tree_item_type") and node.getTag("tree_item_type") == "TERRAIN_NODE"
|
||||
|
||||
|
||||
def _set_light_registration(world, node: NodePath, registered: bool):
|
||||
if not world or not _is_valid_node(node) or not _is_light_node(node):
|
||||
return
|
||||
|
||||
scene_manager = getattr(world, "scene_manager", None)
|
||||
light_type = node.getTag("light_type")
|
||||
light_lists = []
|
||||
if scene_manager:
|
||||
if light_type == "spot_light" and hasattr(scene_manager, "Spotlight"):
|
||||
light_lists.append(scene_manager.Spotlight)
|
||||
elif light_type == "point_light" and hasattr(scene_manager, "Pointlight"):
|
||||
light_lists.append(scene_manager.Pointlight)
|
||||
|
||||
rp_light = node.getPythonTag("rp_light_object") if hasattr(node, "hasPythonTag") and node.hasPythonTag("rp_light_object") else None
|
||||
current_registered = bool(node.getPythonTag("engine_light_registered")) if hasattr(node, "hasPythonTag") and node.hasPythonTag("engine_light_registered") else False
|
||||
|
||||
if registered:
|
||||
for light_list in light_lists:
|
||||
if node not in light_list:
|
||||
light_list.append(node)
|
||||
if not current_registered:
|
||||
try:
|
||||
if rp_light is not None and getattr(world, "render_pipeline", None):
|
||||
world.render_pipeline.add_light(rp_light)
|
||||
elif hasattr(world, "render") and world.render:
|
||||
world.render.setLight(node)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
node.setPythonTag("engine_light_registered", True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
for light_list in light_lists:
|
||||
try:
|
||||
while node in light_list:
|
||||
light_list.remove(node)
|
||||
except Exception:
|
||||
pass
|
||||
if current_registered:
|
||||
try:
|
||||
if rp_light is not None and getattr(world, "render_pipeline", None):
|
||||
world.render_pipeline.remove_light(rp_light)
|
||||
elif hasattr(world, "render") and world.render:
|
||||
world.render.clearLight(node)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
node.setPythonTag("engine_light_registered", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _set_terrain_registration(world, node: NodePath, registered: bool):
|
||||
if not world or not _is_valid_node(node) or not _is_terrain_node(node):
|
||||
return
|
||||
|
||||
terrain_manager = getattr(world, "terrain_manager", None)
|
||||
if not terrain_manager or not hasattr(terrain_manager, "terrains"):
|
||||
return
|
||||
|
||||
terrain_info = None
|
||||
if hasattr(node, "hasPythonTag") and node.hasPythonTag("terrain_info"):
|
||||
terrain_info = node.getPythonTag("terrain_info")
|
||||
else:
|
||||
for info in getattr(terrain_manager, "terrains", []):
|
||||
if info.get("node") == node:
|
||||
terrain_info = info
|
||||
break
|
||||
if terrain_info is not None:
|
||||
try:
|
||||
node.setPythonTag("terrain_info", terrain_info)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if registered:
|
||||
if terrain_info is not None:
|
||||
terrain_info["node"] = node
|
||||
if all(info.get("node") != node for info in terrain_manager.terrains):
|
||||
terrain_manager.terrains.append(terrain_info)
|
||||
return
|
||||
|
||||
try:
|
||||
terrain_manager.terrains = [info for info in terrain_manager.terrains if info.get("node") != node]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _register_scene_node(world, node: NodePath):
|
||||
if not world or not _is_valid_node(node):
|
||||
return
|
||||
scene_manager = getattr(world, "scene_manager", None)
|
||||
_set_light_registration(world, node, True)
|
||||
_set_terrain_registration(world, node, True)
|
||||
if scene_manager and hasattr(scene_manager, "models") and node not in scene_manager.models:
|
||||
scene_manager.models.append(node)
|
||||
try:
|
||||
@ -25,6 +124,8 @@ def _unregister_scene_node(world, node: NodePath):
|
||||
if not world or not node:
|
||||
return
|
||||
scene_manager = getattr(world, "scene_manager", None)
|
||||
_set_light_registration(world, node, False)
|
||||
_set_terrain_registration(world, node, False)
|
||||
if scene_manager and hasattr(scene_manager, "models"):
|
||||
try:
|
||||
while node in scene_manager.models:
|
||||
@ -331,11 +432,11 @@ class DeleteNodeCommand(Command):
|
||||
if node.hasTag("tileset_url"):
|
||||
self.extra_data["tileset_url"] = node.getTag("tileset_url")
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
执行删除操作
|
||||
"""
|
||||
# 从world的相应列表中移除节点引用
|
||||
def execute(self):
|
||||
"""
|
||||
执行删除操作
|
||||
"""
|
||||
# 从world的相应列表中移除节点引用
|
||||
if self.world and hasattr(self.world, 'scene_manager'):
|
||||
scene_manager = self.world.scene_manager
|
||||
if self.node_type == "LIGHT_NODE":
|
||||
@ -353,19 +454,21 @@ class DeleteNodeCommand(Command):
|
||||
if self.node_type.startswith("GUI_") and hasattr(self.world,
|
||||
'gui_elements') and self.node in self.world.gui_elements:
|
||||
self.world.gui_elements.remove(self.node)
|
||||
elif self.node_type == "CESIUM_TILESET_NODE":
|
||||
# 从tilesets列表中移除
|
||||
if hasattr(scene_manager, 'tilesets'):
|
||||
tilesets_to_remove = []
|
||||
for i, tileset_info in enumerate(scene_manager.tilesets):
|
||||
elif self.node_type == "CESIUM_TILESET_NODE":
|
||||
# 从tilesets列表中移除
|
||||
if hasattr(scene_manager, 'tilesets'):
|
||||
tilesets_to_remove = []
|
||||
for i, tileset_info in enumerate(scene_manager.tilesets):
|
||||
if tileset_info.get('node') == self.node:
|
||||
tilesets_to_remove.append(i)
|
||||
for i in reversed(tilesets_to_remove):
|
||||
del scene_manager.tilesets[i]
|
||||
|
||||
# 从场景图中移除节点,使用 detachNode 而不是 removeNode 以便可以撤销
|
||||
if self.node and not self.node.isEmpty():
|
||||
self.node.detachNode()
|
||||
for i in reversed(tilesets_to_remove):
|
||||
del scene_manager.tilesets[i]
|
||||
|
||||
_unregister_scene_node(self.world, self.node)
|
||||
|
||||
# 从场景图中移除节点,使用 detachNode 而不是 removeNode 以便可以撤销
|
||||
if self.node and not self.node.isEmpty():
|
||||
self.node.detachNode()
|
||||
|
||||
def undo(self):
|
||||
"""
|
||||
@ -392,14 +495,16 @@ class DeleteNodeCommand(Command):
|
||||
|
||||
if self.node_type.startswith("GUI_") and hasattr(self.world, 'gui_elements') and self.node not in self.world.gui_elements:
|
||||
self.world.gui_elements.append(self.node)
|
||||
elif self.node_type == "CESIUM_TILESET_NODE":
|
||||
# 简单恢复到 tilesets
|
||||
if hasattr(scene_manager, 'tilesets'):
|
||||
scene_manager.tilesets.append({'node': self.node, 'url': self.extra_data.get('tileset_url', '')})
|
||||
|
||||
print(f"✅ 成功撤销删除操作,节点 {self.node_name} 已恢复")
|
||||
else:
|
||||
print("❌ 无法撤销删除操作,节点引用已丢失")
|
||||
elif self.node_type == "CESIUM_TILESET_NODE":
|
||||
# 简单恢复到 tilesets
|
||||
if hasattr(scene_manager, 'tilesets'):
|
||||
scene_manager.tilesets.append({'node': self.node, 'url': self.extra_data.get('tileset_url', '')})
|
||||
|
||||
_register_scene_node(self.world, self.node)
|
||||
|
||||
print(f"✅ 成功撤销删除操作,节点 {self.node_name} 已恢复")
|
||||
else:
|
||||
print("❌ 无法撤销删除操作,节点引用已丢失")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 撤销删除操作时出错: {e}")
|
||||
|
||||
@ -129,19 +129,20 @@ class TerrainManager:
|
||||
terrain_node.setPythonTag("selectable", True)
|
||||
|
||||
# 保存地形信息(包括高度图的副本)
|
||||
terrain_info = {
|
||||
'terrain': terrain,
|
||||
'node': terrain_node,
|
||||
'heightmap': heightmap_path,
|
||||
'heightfield': height_image, # 保存高度图副本
|
||||
terrain_info = {
|
||||
'terrain': terrain,
|
||||
'node': terrain_node,
|
||||
'heightmap': heightmap_path,
|
||||
'heightfield': height_image, # 保存高度图副本
|
||||
'scale': scale,
|
||||
'name': node_name
|
||||
}
|
||||
|
||||
self.terrains.append(terrain_info)
|
||||
|
||||
parent_name = parent_item.text(0) if parent_item else "root"
|
||||
print(f"✅ 为 {parent_name} 创建高度图地形: {terrain_name}")
|
||||
}
|
||||
|
||||
self.terrains.append(terrain_info)
|
||||
terrain_node.setPythonTag("terrain_info", terrain_info)
|
||||
|
||||
parent_name = parent_item.text(0) if parent_item else "root"
|
||||
print(f"✅ 为 {parent_name} 创建高度图地形: {terrain_name}")
|
||||
|
||||
# 在Qt树形控件中添加对应节点
|
||||
qt_item = None
|
||||
@ -278,19 +279,20 @@ class TerrainManager:
|
||||
terrain_node.setPythonTag("selectable", True)
|
||||
|
||||
# 保存地形信息(包括高度图)
|
||||
terrain_info = {
|
||||
'terrain': terrain,
|
||||
'node': terrain_node,
|
||||
'heightmap': None,
|
||||
'heightfield': height_image, # 保存高度图
|
||||
terrain_info = {
|
||||
'terrain': terrain,
|
||||
'node': terrain_node,
|
||||
'heightmap': None,
|
||||
'heightfield': height_image, # 保存高度图
|
||||
'scale': (size[0], size[1], 50),
|
||||
'name': node_name
|
||||
}
|
||||
|
||||
self.terrains.append(terrain_info)
|
||||
|
||||
parent_name = parent_item.text(0) if parent_item else "root"
|
||||
print(f"✅ 为 {parent_name} 创建平面地形: {terrain_name}")
|
||||
}
|
||||
|
||||
self.terrains.append(terrain_info)
|
||||
terrain_node.setPythonTag("terrain_info", terrain_info)
|
||||
|
||||
parent_name = parent_item.text(0) if parent_item else "root"
|
||||
print(f"✅ 为 {parent_name} 创建平面地形: {terrain_name}")
|
||||
|
||||
# 在Qt树形控件中添加对应节点
|
||||
qt_item = None
|
||||
|
||||
@ -326,6 +326,7 @@ class SceneManagerLightMixin:
|
||||
spotlight_node.setTag("created_by_user", "1")
|
||||
spotlight_node.setTag("element_type", "spotlight")
|
||||
spotlight_node.setPythonTag("rp_light_object", spotlight)
|
||||
spotlight_node.setPythonTag("engine_light_registered", True)
|
||||
self.Spotlight.append(spotlight_node)
|
||||
return spotlight_node
|
||||
else:
|
||||
@ -348,6 +349,7 @@ class SceneManagerLightMixin:
|
||||
spotlight_node.setTag("tree_item_type", "LIGHT_NODE")
|
||||
spotlight_node.setTag("created_by_user", "1")
|
||||
spotlight_node.setTag("element_type", "spotlight")
|
||||
spotlight_node.setPythonTag("engine_light_registered", True)
|
||||
|
||||
# 设置聚光灯方向(向下照射)
|
||||
spotlight_node.lookAt(pos[0], pos[1], pos[2] - 5) # 向下看5个单位
|
||||
@ -414,6 +416,7 @@ class SceneManagerLightMixin:
|
||||
pointlight_node.setTag("created_by_user", "1")
|
||||
pointlight_node.setTag("element_type", "pointlight")
|
||||
pointlight_node.setPythonTag("rp_light_object", pointlight)
|
||||
pointlight_node.setPythonTag("engine_light_registered", True)
|
||||
self.Pointlight.append(pointlight_node)
|
||||
return pointlight_node
|
||||
else:
|
||||
@ -436,6 +439,7 @@ class SceneManagerLightMixin:
|
||||
pointlight_node.setTag("tree_item_type", "LIGHT_NODE")
|
||||
pointlight_node.setTag("created_by_user", "1")
|
||||
pointlight_node.setTag("element_type", "pointlight")
|
||||
pointlight_node.setPythonTag("engine_light_registered", True)
|
||||
|
||||
# 添加到光源列表
|
||||
self.Pointlight.append(pointlight_node)
|
||||
|
||||
@ -19,6 +19,21 @@ class DialogPanels:
|
||||
else:
|
||||
setattr(self.app, name, value)
|
||||
|
||||
def _execute_scene_create_command(self, creator):
|
||||
"""Create a scene node through the shared undo/redo stack."""
|
||||
command_manager = getattr(self, "command_manager", None)
|
||||
if not command_manager:
|
||||
return creator()
|
||||
|
||||
from core.Command_System import CreateNodeCommand
|
||||
|
||||
command = CreateNodeCommand(lambda _parent: creator(), getattr(self, "render", None), world=self)
|
||||
command_manager.execute_command(command)
|
||||
if not command.created_node:
|
||||
command_manager.pop_last_command()
|
||||
return None
|
||||
return command.created_node
|
||||
|
||||
|
||||
def _draw_new_project_dialog(self):
|
||||
"""绘制新建项目对话框"""
|
||||
@ -554,17 +569,20 @@ class DialogPanels:
|
||||
if imgui.button("创建"):
|
||||
try:
|
||||
pos = tuple(self.dialog_params['spotlight_pos'])
|
||||
|
||||
result = self.createSpotLight(pos)
|
||||
|
||||
def create_spotlight():
|
||||
result = self.createSpotLight(pos)
|
||||
if result:
|
||||
light = result.node()
|
||||
if hasattr(light, 'setColor'):
|
||||
color = tuple(self.dialog_params['spotlight_color'])
|
||||
light.setColor(color + (1.0,))
|
||||
if hasattr(light, 'setEnergy'):
|
||||
light.setEnergy(self.dialog_params['spotlight_intensity'])
|
||||
return result
|
||||
|
||||
result = self._execute_scene_create_command(create_spotlight)
|
||||
if result:
|
||||
# 设置颜色和强度
|
||||
light = result.node()
|
||||
if hasattr(light, 'setColor'):
|
||||
color = tuple(self.dialog_params['spotlight_color'])
|
||||
light.setColor(color + (1.0,)) # 添加alpha通道
|
||||
if hasattr(light, 'setEnergy'):
|
||||
light.setEnergy(self.dialog_params['spotlight_intensity'])
|
||||
|
||||
self.add_success_message("聚光灯创建成功")
|
||||
self.show_spot_light_dialog = False
|
||||
else:
|
||||
@ -643,21 +661,23 @@ class DialogPanels:
|
||||
if imgui.button("创建"):
|
||||
try:
|
||||
pos = tuple(self.dialog_params['pointlight_pos'])
|
||||
|
||||
result = self.createPointLight(pos)
|
||||
|
||||
def create_pointlight():
|
||||
result = self.createPointLight(pos)
|
||||
if result:
|
||||
light = result.node()
|
||||
if hasattr(light, 'setColor'):
|
||||
color = tuple(self.dialog_params['pointlight_color'])
|
||||
light.setColor(color + (1.0,))
|
||||
if hasattr(light, 'setEnergy'):
|
||||
light.setEnergy(self.dialog_params['pointlight_intensity'])
|
||||
if hasattr(light, 'setAttenuation'):
|
||||
radius = self.dialog_params['pointlight_radius']
|
||||
light.setAttenuation((1.0, 0.5 / radius, 0.5 / (radius * radius)))
|
||||
return result
|
||||
|
||||
result = self._execute_scene_create_command(create_pointlight)
|
||||
if result:
|
||||
# 设置颜色和强度
|
||||
light = result.node()
|
||||
if hasattr(light, 'setColor'):
|
||||
color = tuple(self.dialog_params['pointlight_color'])
|
||||
light.setColor(color + (1.0,)) # 添加alpha通道
|
||||
if hasattr(light, 'setEnergy'):
|
||||
light.setEnergy(self.dialog_params['pointlight_intensity'])
|
||||
if hasattr(light, 'setAttenuation'):
|
||||
# 设置衰减: (constant, linear, quadratic)
|
||||
radius = self.dialog_params['pointlight_radius']
|
||||
light.setAttenuation((1.0, 0.5/radius, 0.5/(radius*radius)))
|
||||
|
||||
self.add_success_message("点光源创建成功")
|
||||
self.show_point_light_dialog = False
|
||||
else:
|
||||
@ -728,8 +748,10 @@ class DialogPanels:
|
||||
|
||||
# 转换为地形管理器期望的格式
|
||||
size = (width, height)
|
||||
|
||||
result = self.createFlatTerrain(size, resolution)
|
||||
|
||||
result = self._execute_scene_create_command(
|
||||
lambda: self.createFlatTerrain(size, resolution)
|
||||
)
|
||||
if result:
|
||||
self.add_success_message("平面地形创建成功")
|
||||
self.show_terrain_dialog = False
|
||||
@ -1061,7 +1083,9 @@ class DialogPanels:
|
||||
try:
|
||||
# 使用默认缩放参数创建地形
|
||||
scale = (1.0, 1.0, 10.0) # X, Y, Z缩放
|
||||
result = self.createTerrainFromHeightMap(self.heightmap_file_path, scale)
|
||||
result = self._execute_scene_create_command(
|
||||
lambda: self.createTerrainFromHeightMap(self.heightmap_file_path, scale)
|
||||
)
|
||||
if result:
|
||||
self.add_success_message("高度图地形创建成功")
|
||||
self.show_heightmap_browser = False
|
||||
|
||||
Loading…
Reference in New Issue
Block a user