Use commands for reset transform
This commit is contained in:
parent
8a80af9825
commit
7e6b1d54d9
20
imgui.ini
20
imgui.ini
@ -25,25 +25,25 @@ Collapsed=0
|
||||
|
||||
[Window][工具栏]
|
||||
Pos=354,20
|
||||
Size=1846,32
|
||||
Size=1334,32
|
||||
Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
|
||||
[Window][场景树]
|
||||
Pos=0,20
|
||||
Size=352,995
|
||||
Size=352,748
|
||||
Collapsed=0
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][属性面板]
|
||||
Pos=2202,20
|
||||
Size=358,995
|
||||
Pos=1690,20
|
||||
Size=358,748
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Window][控制台]
|
||||
Pos=2202,20
|
||||
Size=358,995
|
||||
Pos=1690,20
|
||||
Size=358,748
|
||||
Collapsed=0
|
||||
DockId=0x00000002,1
|
||||
|
||||
@ -60,7 +60,7 @@ Collapsed=0
|
||||
|
||||
[Window][WindowOverViewport_11111111]
|
||||
Pos=0,20
|
||||
Size=2560,1331
|
||||
Size=2048,1084
|
||||
Collapsed=0
|
||||
|
||||
[Window][测试窗口1]
|
||||
@ -99,8 +99,8 @@ Size=600,500
|
||||
Collapsed=0
|
||||
|
||||
[Window][资源管理器]
|
||||
Pos=0,1017
|
||||
Size=2560,334
|
||||
Pos=0,770
|
||||
Size=2048,334
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
@ -207,7 +207,7 @@ Collapsed=0
|
||||
DockId=0x00000002,2
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=2560,1331 Split=Y
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=2048,1084 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=2560,995 Split=X
|
||||
DockNode ID=0x00000007 Parent=0x00000005 SizeRef=352,1084 Selected=0xE0015051
|
||||
DockNode ID=0x00000008 Parent=0x00000005 SizeRef=2206,1084 Split=X
|
||||
|
||||
@ -726,9 +726,30 @@ class EditorPanelsRightMixin(
|
||||
"""绘制属性操作按钮"""
|
||||
# 重置变换
|
||||
if imgui.button("重置变换"):
|
||||
node.setPos(0, 0, 0)
|
||||
node.setHpr(0, 0, 0)
|
||||
node.setScale(1, 1, 1)
|
||||
if hasattr(self.app, "command_manager") and self.app.command_manager:
|
||||
from core.Command_System import (
|
||||
CompositeCommand,
|
||||
MoveNodeCommand,
|
||||
RotateNodeCommand,
|
||||
ScaleNodeCommand,
|
||||
)
|
||||
|
||||
current_pos = tuple(float(v) for v in node.getPos())
|
||||
current_hpr = tuple(float(v) for v in node.getHpr())
|
||||
current_scale = tuple(float(v) for v in node.getScale())
|
||||
self.app.command_manager.execute_command(
|
||||
CompositeCommand(
|
||||
[
|
||||
MoveNodeCommand(node, current_pos, (0.0, 0.0, 0.0)),
|
||||
RotateNodeCommand(node, current_hpr, (0.0, 0.0, 0.0)),
|
||||
ScaleNodeCommand(node, current_scale, (1.0, 1.0, 1.0)),
|
||||
]
|
||||
)
|
||||
)
|
||||
else:
|
||||
node.setPos(0, 0, 0)
|
||||
node.setHpr(0, 0, 0)
|
||||
node.setScale(1, 1, 1)
|
||||
|
||||
imgui.same_line()
|
||||
|
||||
@ -736,10 +757,7 @@ class EditorPanelsRightMixin(
|
||||
is_visible = not node.is_hidden()
|
||||
visibility_text = "隐藏" if is_visible else "显示"
|
||||
if imgui.button(visibility_text):
|
||||
if is_visible:
|
||||
node.hide()
|
||||
else:
|
||||
node.show()
|
||||
self._record_visibility_change(node, is_visible, not is_visible)
|
||||
|
||||
imgui.same_line()
|
||||
|
||||
|
||||
@ -47,6 +47,15 @@ class EditorPanelsRightMaterialMixin:
|
||||
after_snapshot = self.app._capture_node_material_snapshot(node)
|
||||
self._record_material_snapshot_command(node, before_snapshot, after_snapshot)
|
||||
|
||||
def _select_texture_for_material_with_history(self, node, material, texture_type):
|
||||
before_snapshot = self.app._capture_node_material_snapshot(node)
|
||||
changed = self._select_texture_for_material(node, material, texture_type)
|
||||
if not changed:
|
||||
return False
|
||||
after_snapshot = self.app._capture_node_material_snapshot(node)
|
||||
self._record_material_snapshot_command(node, before_snapshot, after_snapshot)
|
||||
return True
|
||||
|
||||
def _draw_appearance_properties(self, node):
|
||||
"""绘制材质属性(Unity风格主材质入口)。"""
|
||||
materials = self.app._get_node_materials(node)
|
||||
@ -228,26 +237,26 @@ class EditorPanelsRightMaterialMixin:
|
||||
# 纹理信息
|
||||
imgui.text("纹理贴图")
|
||||
if imgui.button(f"选择漫反射贴图##diffuse_{i}"):
|
||||
self._select_texture_for_material(node, material, "diffuse")
|
||||
self._select_texture_for_material_with_history(node, material, "diffuse")
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"选择法线贴图##normal_{i}"):
|
||||
self._select_texture_for_material(node, material, "normal")
|
||||
self._select_texture_for_material_with_history(node, material, "normal")
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"选择粗糙度贴图##roughness_{i}"):
|
||||
self._select_texture_for_material(node, material, "roughness")
|
||||
self._select_texture_for_material_with_history(node, material, "roughness")
|
||||
|
||||
if imgui.button(f"选择金属性贴图##metallic_{i}"):
|
||||
self._select_texture_for_material(node, material, "metallic")
|
||||
self._select_texture_for_material_with_history(node, material, "metallic")
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"选择自发光贴图##emission_{i}"):
|
||||
self._select_texture_for_material(node, material, "emission")
|
||||
self._select_texture_for_material_with_history(node, material, "emission")
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"清除所有贴图##clear_{i}"):
|
||||
self._clear_all_textures(node)
|
||||
self._apply_material_change_with_history(node, lambda: self._clear_all_textures(node))
|
||||
|
||||
# 显示当前纹理信息
|
||||
self._display_current_textures(node, material)
|
||||
|
||||
@ -50,6 +50,12 @@ class InteractionPanels:
|
||||
|
||||
if imgui.menu_item("重命名", "", False, True)[1]:
|
||||
self._renaming_node = True
|
||||
if hasattr(self, "_context_menu_target") and self._context_menu_target:
|
||||
self._rename_target = self._context_menu_target
|
||||
self._rename_buffer = self._context_menu_target.getName() or ""
|
||||
else:
|
||||
self._rename_target = None
|
||||
self._rename_buffer = ""
|
||||
imgui.close_current_popup()
|
||||
|
||||
imgui.separator()
|
||||
@ -71,10 +77,6 @@ class InteractionPanels:
|
||||
# 重命名对话框
|
||||
if hasattr(self, '_renaming_node') and self._renaming_node:
|
||||
imgui.open_popup("重命名节点")
|
||||
if not hasattr(self, '_rename_buffer'):
|
||||
self._rename_buffer = ""
|
||||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||||
self._rename_buffer = self._context_menu_target.getName() or ""
|
||||
|
||||
if imgui.begin_popup("重命名节点"):
|
||||
changed, new_name = imgui.input_text("新名称", self._rename_buffer, 256)
|
||||
@ -82,14 +84,28 @@ class InteractionPanels:
|
||||
self._rename_buffer = new_name
|
||||
|
||||
if imgui.button("确定"):
|
||||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||||
self._context_menu_target.setName(self._rename_buffer)
|
||||
target = getattr(self, "_rename_target", None) or getattr(self, "_context_menu_target", None)
|
||||
if target and not target.isEmpty():
|
||||
old_name = target.getName() or ""
|
||||
new_name = (self._rename_buffer or "").strip()
|
||||
if not new_name:
|
||||
new_name = old_name
|
||||
if hasattr(self, "editor_panels") and self.editor_panels:
|
||||
self.editor_panels._record_name_change(target, old_name, new_name)
|
||||
elif hasattr(self, "_update_node_name"):
|
||||
self._update_node_name(target, new_name)
|
||||
else:
|
||||
target.setName(new_name)
|
||||
self._renaming_node = False
|
||||
self._rename_target = None
|
||||
self._rename_buffer = ""
|
||||
imgui.close_current_popup()
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button("取消"):
|
||||
self._renaming_node = False
|
||||
self._rename_target = None
|
||||
self._rename_buffer = ""
|
||||
imgui.close_current_popup()
|
||||
|
||||
imgui.end_popup()
|
||||
@ -99,38 +115,17 @@ class InteractionPanels:
|
||||
"""删除节点 - 简化版本"""
|
||||
if not node or node.isEmpty():
|
||||
return
|
||||
|
||||
# 从场景管理器中删除
|
||||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||||
if hasattr(self.scene_manager, 'models') and node in self.scene_manager.models:
|
||||
self.scene_manager.models.remove(node)
|
||||
|
||||
# 从GUI管理器中删除
|
||||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||||
gui_element = None
|
||||
if hasattr(node, 'getPythonTag'):
|
||||
gui_element = node.getPythonTag('gui_element')
|
||||
if gui_element and hasattr(self.gui_manager, 'gui_elements'):
|
||||
if gui_element in self.gui_manager.gui_elements:
|
||||
self.gui_manager.gui_elements.remove(gui_element)
|
||||
|
||||
# 使用主删除方法
|
||||
self._delete_node(node)
|
||||
|
||||
# 获取节点名称(在删除之前)
|
||||
node_name = node.getName() if not node.isEmpty() else '未命名节点'
|
||||
|
||||
# 删除节点本身
|
||||
node.removeNode()
|
||||
|
||||
# 清除选择
|
||||
if hasattr(self, 'selection') and self.selection:
|
||||
|
||||
node_name = node.getName() or "未命名节点"
|
||||
deleted = self._delete_node(node)
|
||||
|
||||
if deleted and hasattr(self, 'selection') and self.selection:
|
||||
current_node = self.selection.getSelectedNode() if hasattr(self.selection, "getSelectedNode") else self.selection.selectedNode
|
||||
if current_node == node:
|
||||
self.selection.clearSelection()
|
||||
|
||||
# 添加成功消息
|
||||
self.add_success_message(f"已删除节点: {node_name}")
|
||||
|
||||
if deleted:
|
||||
self.add_success_message(f"已删除节点: {node_name}")
|
||||
|
||||
|
||||
def _copy_node(self, node):
|
||||
|
||||
@ -850,7 +850,7 @@ class PropertyHelpers:
|
||||
fallback_material = self._ensure_material_for_node(node)
|
||||
materials = [fallback_material] if fallback_material else []
|
||||
|
||||
snapshot = []
|
||||
material_entries = []
|
||||
for material in materials:
|
||||
emission = None
|
||||
try:
|
||||
@ -872,14 +872,47 @@ class PropertyHelpers:
|
||||
"ior": float(material.refractive_index) if hasattr(material, "refractive_index") and material.refractive_index is not None else None,
|
||||
"emission": emission,
|
||||
}
|
||||
snapshot.append(entry)
|
||||
return snapshot
|
||||
material_entries.append(entry)
|
||||
|
||||
texture_tags = {}
|
||||
for texture_type in self._get_material_texture_slots().keys():
|
||||
tag_name = f"material_texture_{texture_type}"
|
||||
if node and hasattr(node, "hasTag") and node.hasTag(tag_name):
|
||||
texture_tags[texture_type] = node.getTag(tag_name)
|
||||
|
||||
effect_tags = {}
|
||||
for tag_name in (
|
||||
"material_effect_metallic_enabled",
|
||||
"material_effect_default_texture_enabled",
|
||||
"material_effect_parallax_enabled",
|
||||
):
|
||||
effect_tags[tag_name] = bool(node and hasattr(node, "hasTag") and node.hasTag(tag_name))
|
||||
|
||||
return {
|
||||
"materials": material_entries,
|
||||
"node_state": {
|
||||
"textures": texture_tags,
|
||||
"effect_tags": effect_tags,
|
||||
},
|
||||
}
|
||||
|
||||
def _normalize_material_snapshot(self, snapshot):
|
||||
if isinstance(snapshot, list):
|
||||
return {"materials": snapshot, "node_state": {"textures": {}, "effect_tags": {}}}
|
||||
if isinstance(snapshot, dict):
|
||||
return {
|
||||
"materials": snapshot.get("materials", []) or [],
|
||||
"node_state": snapshot.get("node_state", {}) or {"textures": {}, "effect_tags": {}},
|
||||
}
|
||||
return {"materials": [], "node_state": {"textures": {}, "effect_tags": {}}}
|
||||
|
||||
def _material_snapshots_equal(self, before_snapshot, after_snapshot):
|
||||
"""Compare two material snapshots with a small float tolerance."""
|
||||
before_snapshot = before_snapshot or []
|
||||
after_snapshot = after_snapshot or []
|
||||
if len(before_snapshot) != len(after_snapshot):
|
||||
before_snapshot = self._normalize_material_snapshot(before_snapshot)
|
||||
after_snapshot = self._normalize_material_snapshot(after_snapshot)
|
||||
before_materials = before_snapshot.get("materials", [])
|
||||
after_materials = after_snapshot.get("materials", [])
|
||||
if len(before_materials) != len(after_materials):
|
||||
return False
|
||||
|
||||
def _rounded_tuple(values):
|
||||
@ -887,7 +920,7 @@ class PropertyHelpers:
|
||||
return None
|
||||
return tuple(round(float(value), 6) for value in values)
|
||||
|
||||
for before_entry, after_entry in zip(before_snapshot, after_snapshot):
|
||||
for before_entry, after_entry in zip(before_materials, after_materials):
|
||||
before_material = before_entry.get("material")
|
||||
after_material = after_entry.get("material")
|
||||
before_key = getattr(before_material, "this", None) or id(before_material)
|
||||
@ -909,6 +942,13 @@ class PropertyHelpers:
|
||||
continue
|
||||
if round(float(before_value), 6) != round(float(after_value), 6):
|
||||
return False
|
||||
|
||||
before_node_state = before_snapshot.get("node_state", {}) or {}
|
||||
after_node_state = after_snapshot.get("node_state", {}) or {}
|
||||
if (before_node_state.get("textures", {}) or {}) != (after_node_state.get("textures", {}) or {}):
|
||||
return False
|
||||
if (before_node_state.get("effect_tags", {}) or {}) != (after_node_state.get("effect_tags", {}) or {}):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _apply_node_material_snapshot(self, node, snapshot):
|
||||
@ -919,8 +959,11 @@ class PropertyHelpers:
|
||||
if not node or node.isEmpty():
|
||||
return
|
||||
|
||||
snapshot = snapshot or []
|
||||
for entry in snapshot:
|
||||
snapshot = self._normalize_material_snapshot(snapshot)
|
||||
materials_snapshot = snapshot.get("materials", [])
|
||||
node_state = snapshot.get("node_state", {}) or {}
|
||||
|
||||
for entry in materials_snapshot:
|
||||
material = entry.get("material")
|
||||
if material is None:
|
||||
continue
|
||||
@ -948,7 +991,26 @@ class PropertyHelpers:
|
||||
self._apply_material_to_geom_states(node, material)
|
||||
self._apply_material_surface_state(node, material)
|
||||
|
||||
for entry in snapshot:
|
||||
self._clear_all_textures(node)
|
||||
texture_tags = node_state.get("textures", {}) or {}
|
||||
primary_material = None
|
||||
if materials_snapshot:
|
||||
primary_material = materials_snapshot[0].get("material")
|
||||
if primary_material is None:
|
||||
primary_material = self._ensure_material_for_node(node)
|
||||
|
||||
texture_slots = self._get_material_texture_slots()
|
||||
for texture_type, texture_path in sorted(texture_tags.items(), key=lambda item: texture_slots.get(item[0], 999)):
|
||||
if texture_path:
|
||||
self._apply_texture_to_material(node, primary_material, texture_type, texture_path)
|
||||
|
||||
for tag_name, enabled in (node_state.get("effect_tags", {}) or {}).items():
|
||||
if enabled:
|
||||
node.setTag(tag_name, "1")
|
||||
elif node.hasTag(tag_name):
|
||||
node.clearTag(tag_name)
|
||||
|
||||
for entry in materials_snapshot:
|
||||
material = entry.get("material")
|
||||
if material is not None:
|
||||
self._refresh_pipeline_material_mode(node, material)
|
||||
@ -1706,12 +1768,14 @@ class PropertyHelpers:
|
||||
|
||||
if selected_path and os.path.exists(selected_path):
|
||||
self._texture_dialog_path = os.path.dirname(selected_path)
|
||||
self._apply_texture_to_material(node, material, texture_type, selected_path)
|
||||
return bool(self._apply_texture_to_material(node, material, texture_type, selected_path))
|
||||
else:
|
||||
print(f"已取消选择{texture_type}贴图")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"选择纹理失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _get_material_texture_slots(self):
|
||||
@ -2040,12 +2104,15 @@ class PropertyHelpers:
|
||||
|
||||
# 记录路径,便于 UI 展示和后续恢复
|
||||
if texture_path:
|
||||
node.setTag(f"material_texture_{texture_type}", os.path.normpath(normalized_path or texture_path))
|
||||
stable_texture_path = os.path.normpath(os.path.abspath(texture_path))
|
||||
node.setTag(f"material_texture_{texture_type}", stable_texture_path)
|
||||
|
||||
print(f"已应用{texture_type}纹理到槽位 p3d_Texture{slot}: {texture_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"应用纹理失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _clear_all_textures(self, node):
|
||||
@ -2072,8 +2139,10 @@ class PropertyHelpers:
|
||||
node.clearTag("material_effect_parallax_enabled")
|
||||
|
||||
print("已清除所有纹理")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"清除纹理失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _display_current_textures(self, node, material):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user