diff --git a/ui/panels/editor_panels_right.py b/ui/panels/editor_panels_right.py index b0b9f013..f70dc892 100644 --- a/ui/panels/editor_panels_right.py +++ b/ui/panels/editor_panels_right.py @@ -1,7 +1,16 @@ from imgui_bundle import imgui, imgui_ctx -class EditorPanelsRightMixin: - """Auto-split mixin from editor_panels.py.""" +from ui.panels.editor_panels_right_collision import EditorPanelsRightCollisionMixin +from ui.panels.editor_panels_right_material import EditorPanelsRightMaterialMixin +from ui.panels.editor_panels_right_transform import EditorPanelsRightTransformMixin + + +class EditorPanelsRightMixin( + EditorPanelsRightTransformMixin, + EditorPanelsRightMaterialMixin, + EditorPanelsRightCollisionMixin, +): + """Right panel aggregator mixin.""" def _draw_property_panel(self): """绘制属性面板""" @@ -270,93 +279,6 @@ class EditorPanelsRightMixin: imgui.same_line() imgui.text_colored((0.5, 0.5, 0.5, 1.0), "[标准对象]") - def _draw_transform_properties(self, node): - """绘制变换属性""" - # 位置组 - if imgui.collapsing_header("位置 Position"): - # 相对位置 - imgui.text("相对位置") - pos = node.getPos() - - # X坐标 - changed, new_x = imgui.input_float("X##pos_x", pos.x, 0.1, 1.0, "%.3f") - if changed: node.setX(new_x) - - # Y坐标 - changed, new_y = imgui.input_float("Y##pos_y", pos.y, 0.1, 1.0, "%.3f") - if changed: node.setY(new_y) - - # Z坐标 - changed, new_z = imgui.input_float("Z##pos_z", pos.z, 0.1, 1.0, "%.3f") - if changed: node.setZ(new_z) - - # 世界位置 - imgui.text("世界位置") - world_pos = node.getPos(self.render) - - imgui.text(f"世界 X: {world_pos.x:.3f}") - imgui.text(f"世界 Y: {world_pos.y:.3f}") - imgui.text(f"世界 Z: {world_pos.z:.3f}") - - # 位置操作按钮 - if imgui.button("重置位置##reset_pos"): - node.setPos(0, 0, 0) - imgui.same_line() - if imgui.button("复制位置##copy_pos"): - self._clipboard_pos = (pos.x, pos.y, pos.z) - imgui.same_line() - if imgui.button("粘贴位置##paste_pos") and hasattr(self, '_clipboard_pos'): - node.setPos(self._clipboard_pos[0], self._clipboard_pos[1], self._clipboard_pos[2]) - - # 旋转组 - if imgui.collapsing_header("旋转 Rotation"): - hpr = node.getHpr() - - # HPR旋转 - imgui.text("HPR 旋转 (度)") - changed, new_h = imgui.input_float("H##rot_h", hpr.x, 1.0, 10.0, "%.1f") - if changed: node.setH(new_h) - - changed, new_p = imgui.input_float("P##rot_p", hpr.y, 1.0, 10.0, "%.1f") - if changed: node.setP(new_p) - - changed, new_r = imgui.input_float("R##rot_r", hpr.z, 1.0, 10.0, "%.1f") - if changed: node.setR(new_r) - - # 旋转操作按钮 - if imgui.button("重置旋转##reset_rot"): - node.setHpr(0, 0, 0) - imgui.same_line() - if imgui.button("随机旋转##random_rot"): - import random - node.setHpr(random.randint(0, 360), random.randint(0, 360), random.randint(0, 360)) - - # 缩放组 - if imgui.collapsing_header("缩放 Scale"): - scale = node.getScale() - - # XYZ缩放 - imgui.text("XYZ 缩放") - changed, new_sx = imgui.input_float("X##scale_x", scale.x, 0.1, 1.0, "%.3f") - if changed: node.setSx(new_sx) - - changed, new_sy = imgui.input_float("Y##scale_y", scale.y, 0.1, 1.0, "%.3f") - if changed: node.setSy(new_sy) - - changed, new_sz = imgui.input_float("Z##scale_z", scale.z, 0.1, 1.0, "%.3f") - if changed: node.setSz(new_sz) - - # 统一缩放 - if imgui.button("统一缩放##uniform_scale"): - uniform_scale = (scale.x + scale.y + scale.z) / 3.0 - node.setScale(uniform_scale, uniform_scale, uniform_scale) - imgui.same_line() - if imgui.button("重置缩放##reset_scale"): - node.setScale(1, 1, 1) - imgui.same_line() - if imgui.button("翻倍##double_scale"): - node.setScale(scale.x * 2, scale.y * 2, scale.z * 2) - def _draw_gui_properties(self, node): """绘制GUI元素属性""" # 获取GUI元素 @@ -810,219 +732,6 @@ class EditorPanelsRightMixin: imgui.same_line() imgui.text_colored((0.7, 0.7, 0.7, 1.0), "倍速") - def _draw_collision_properties(self, node): - """绘制碰撞检测属性""" - if not node or node.isEmpty(): - return - - try: - # 检查节点是否已有碰撞 - has_collision = self._has_collision(node) - - # 碰撞状态徽章 - imgui.text("状态:") - imgui.same_line() - if has_collision: - imgui.text_colored((0.0, 0.8, 0.0, 1.0), "🟢 已启用") - else: - imgui.text_colored((0.8, 0.0, 0.0, 1.0), "🔴 未启用") - - imgui.separator() - - # 碰撞形状选择 - imgui.text("碰撞形状:") - imgui.same_line() - - # 碰撞形状选项 - collision_shapes = ["球形 (Sphere)", "盒型 (Box)", "胶囊体 (Capsule)", "平面 (Plane)", "自动选择 (Auto)"] - - # 获取当前形状 - current_shape = self._get_current_collision_shape(node) if has_collision else getattr(self.app, '_selected_collision_shape', "球形 (Sphere)") - if has_collision: self.app._selected_collision_shape = current_shape - - # 形状选择下拉框 - current_index = collision_shapes.index(current_shape) if current_shape in collision_shapes else 0 - changed, selected_index = imgui.combo("##collision_shape", current_index, collision_shapes) - if changed: - # 始终更新选择的形状 - selected_shape = collision_shapes[selected_index] - self.app._selected_collision_shape = selected_shape - # 如果已经有碰撞体,询问用户是否要重新创建 - if has_collision: - self._remove_collision_from_node(node) - self._add_collision_to_node(node) - - imgui.separator() - - # 位置偏移控件 - imgui.text("位置偏移:") - - # 获取当前位置偏移 - pos_offset = self._get_collision_position_offset(node) - - # X位置 - changed, new_x = imgui.drag_float("X##collision_pos_x", pos_offset[0], 0.1, -100.0, 100.0, "%.2f") - if changed and has_collision: - self._update_collision_position(node, 'x', new_x) - - # Y位置 - changed, new_y = imgui.drag_float("Y##collision_pos_y", pos_offset[1], 0.1, -100.0, 100.0, "%.2f") - if changed and has_collision: - self._update_collision_position(node, 'y', new_y) - - # Z位置 - changed, new_z = imgui.drag_float("Z##collision_pos_z", pos_offset[2], 0.1, -100.0, 100.0, "%.2f") - if changed and has_collision: - self._update_collision_position(node, 'z', new_z) - - # 形状特定参数(始终显示,但根据状态启用/禁用) - shape_type = self._get_current_collision_shape_type(node) - self._draw_shape_specific_parameters(node, shape_type, has_collision) - - imgui.separator() - - # 操作按钮 - if has_collision: - # 显示/隐藏碰撞体按钮 - is_visible = self._is_collision_visible(node) - visibility_text = "隐藏碰撞体" if is_visible else "显示碰撞体" - if imgui.button(visibility_text): - self._toggle_collision_visibility(node) - - imgui.same_line() - - # 移除碰撞按钮 - if imgui.button("移除碰撞"): - self._remove_collision_from_node(node) - else: - # 添加碰撞按钮 - if imgui.button("添加碰撞"): - self._add_collision_to_node(node) - - imgui.separator() - - # 碰撞检测触发模式 - imgui.text("触发模式:") - - # 自动检测开关 - auto_enabled = self.collision_manager.model_collision_enabled if hasattr(self, 'collision_manager') else False - changed, new_auto = imgui.checkbox("自动检测", auto_enabled) - if changed and hasattr(self, 'collision_manager'): - self.collision_manager.enableModelCollisionDetection(new_auto, 0.1, 0.5) - - imgui.same_line() - - # 手动检测按钮 - if imgui.button("立即检测"): - if hasattr(self, 'collision_manager'): - self._manual_collision_detection() - - except Exception as e: - print(f"绘制碰撞属性失败: {e}") - import traceback - traceback.print_exc() - - def _draw_shape_specific_parameters(self, node, shape_type, has_collision=True): - """绘制形状特定参数""" - try: - if shape_type == "sphere": - self._draw_sphere_parameters(node, has_collision) - elif shape_type == "box": - self._draw_box_parameters(node, has_collision) - elif shape_type == "capsule": - self._draw_capsule_parameters(node, has_collision) - elif shape_type == "plane": - self._draw_plane_parameters(node, has_collision) - except Exception as e: - print(f"绘制形状参数失败: {e}") - - def _draw_sphere_parameters(self, node, has_collision=True): - """绘制球形参数""" - try: - imgui.text("球形参数:") - imgui.same_line() - - # 获取当前半径 - radius = self._get_sphere_radius(node) - - # 半径调整 - changed, new_radius = imgui.drag_float("半径##sphere_radius", radius, 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_sphere_radius(node, new_radius) - - except Exception as e: - print(f"绘制球形参数失败: {e}") - - def _draw_box_parameters(self, node, has_collision=True): - """绘制盒型参数""" - try: - imgui.text("盒型参数:") - - # 获取当前尺寸 - size = self._get_box_size(node) - - # 尺寸调整 - changed, new_x = imgui.drag_float("长度##box_length", size[0], 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_box_size(node, 'x', new_x) - - changed, new_y = imgui.drag_float("宽度##box_width", size[1], 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_box_size(node, 'y', new_y) - - changed, new_z = imgui.drag_float("高度##box_height", size[2], 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_box_size(node, 'z', new_z) - - except Exception as e: - print(f"绘制盒型参数失败: {e}") - - def _draw_capsule_parameters(self, node, has_collision=True): - """绘制胶囊体参数""" - try: - imgui.text("胶囊体参数:") - - # 获取当前参数 - radius = self._get_capsule_radius(node) - height = self._get_capsule_height(node) - - # 半径调整 - changed, new_radius = imgui.drag_float("半径##capsule_radius", radius, 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_capsule_radius(node, new_radius) - - # 高度调整 - changed, new_height = imgui.drag_float("高度##capsule_height", height, 0.1, 0.1, 100.0, "%.2f") - if changed and has_collision: - self._update_capsule_height(node, new_height) - - except Exception as e: - print(f"绘制胶囊体参数失败: {e}") - - def _draw_plane_parameters(self, node, has_collision=True): - """绘制平面参数""" - try: - imgui.text("平面参数:") - - # 获取当前法向量 - normal = self._get_plane_normal(node) - - # 法向量调整 - changed, new_x = imgui.drag_float("法向量 X##plane_normal_x", normal[0], 0.1, -1.0, 1.0, "%.2f") - if changed and has_collision: - self._update_plane_normal(node, 'x', new_x) - - changed, new_y = imgui.drag_float("法向量 Y##plane_normal_y", normal[1], 0.1, -1.0, 1.0, "%.2f") - if changed and has_collision: - self._update_plane_normal(node, 'y', new_y) - - changed, new_z = imgui.drag_float("法向量 Z##plane_normal_z", normal[2], 0.1, -1.0, 1.0, "%.2f") - if changed and has_collision: - self._update_plane_normal(node, 'z', new_z) - - except Exception as e: - print(f"绘制平面参数失败: {e}") - def _draw_property_actions(self, node): """绘制属性操作按钮""" # 重置变换 @@ -1055,225 +764,3 @@ class EditorPanelsRightMixin: if hasattr(self, 'selection') and self.selection: self.selection.deleteSelectedNode() - def _draw_appearance_properties(self, node): - """绘制外观属性""" - # 颜色属性 - if hasattr(node, 'getColor'): - imgui.text("颜色") - try: - color = node.getColor() - # 确保颜色是有效的 - if not color or len(color) < 3: - color = (1.0, 1.0, 1.0, 1.0) # 默认白色 - except: - color = (1.0, 1.0, 1.0, 1.0) # 默认白色 - - # 颜色滑块 - changed, new_r = imgui.slider_float("R##color_r", color[0], 0.0, 1.0) - if changed: - new_color = (new_r, color[1], color[2], color[3] if len(color) > 3 else 1.0) - node.setColor(new_color) - color = new_color - - changed, new_g = imgui.slider_float("G##color_g", color[1], 0.0, 1.0) - if changed: - new_color = (color[0], new_g, color[2], color[3] if len(color) > 3 else 1.0) - node.setColor(new_color) - color = new_color - - changed, new_b = imgui.slider_float("B##color_b", color[2], 0.0, 1.0) - if changed: - new_color = (color[0], color[1], new_b, color[3] if len(color) > 3 else 1.0) - node.setColor(new_color) - color = new_color - - # 只有当颜色有alpha通道时才显示alpha滑块 - if len(color) > 3: - changed, new_a = imgui.slider_float("A##color_a", color[3], 0.0, 1.0) - if changed: - new_color = (color[0], color[1], color[2], new_a) - node.setColor(new_color) - color = new_color - - # 颜色预览和选择器 - imgui.text("颜色预览") - color_with_alpha = (color[0], color[1], color[2], color[3] if len(color) > 3 else 1.0) - if imgui.color_button("颜色预览##preview", color_with_alpha, 0, (100, 30)): - # 点击颜色按钮打开颜色选择器 - self.show_color_picker(node, 'color', color_with_alpha) - - imgui.same_line() - if imgui.button("选择颜色##color_picker_btn"): - self.show_color_picker(node, 'color', (color.x, color.y, color.z, color.w)) - - # 透明度 - if hasattr(node, 'setTransparency') and hasattr(node, 'getTransparency'): - imgui.text("透明度") - current_transparency = node.getTransparency() - # 将当前的透明度值转换为0.0-1.0范围用于显示 - display_transparency = 1.0 - current_transparency if current_transparency <= 1 else 0.0 - changed, new_transparency = imgui.slider_float("透明度", display_transparency, 0.0, 1.0) - if changed: - # 将0.0-1.0范围转换回Panda3D的透明度格式 - panda_transparency = int((1.0 - new_transparency) * 255) - node.setTransparency(panda_transparency) - - # 材质属性 - self._draw_material_properties(node) - - # 渲染状态 - imgui.text("渲染状态") - if imgui.button("应用材质"): - self._apply_material_to_node(node) - - imgui.same_line() - if imgui.button("重置材质"): - self._reset_material(node) - - def _draw_material_properties(self, node): - """绘制材质属性""" - materials = node.find_all_materials() - - if not materials: - imgui.text_colored((0.5, 0.5, 0.5, 1.0), "无材质") - return - - for i, material in enumerate(materials): - material_name = material.get_name() if hasattr(material, 'get_name') and material.get_name() else f"材质{i + 1}" - - if imgui.collapsing_header(f"材质: {material_name}"): - # 材质基础颜色 - base_color = self._get_material_base_color(material) - if base_color: - imgui.text("基础颜色") - changed, new_r = imgui.slider_float(f"R##mat_r_{i}", base_color[0], 0.0, 1.0) - if changed: - self._update_material_base_color(material, 'r', new_r) - base_color = (new_r, base_color[1], base_color[2], base_color[3]) - - changed, new_g = imgui.slider_float(f"G##mat_g_{i}", base_color[1], 0.0, 1.0) - if changed: - self._update_material_base_color(material, 'g', new_g) - base_color = (base_color[0], new_g, base_color[2], base_color[3]) - - changed, new_b = imgui.slider_float(f"B##mat_b_{i}", base_color[2], 0.0, 1.0) - if changed: - self._update_material_base_color(material, 'b', new_b) - base_color = (base_color[0], base_color[1], new_b, base_color[3]) - - changed, new_a = imgui.slider_float(f"A##mat_a_{i}", base_color[3], 0.0, 1.0) - if changed: - self._update_material_base_color(material, 'a', new_a) - base_color = (base_color[0], base_color[1], base_color[2], new_a) - - # PBR属性 - if hasattr(material, 'roughness') and material.roughness is not None: - imgui.text("PBR属性") - try: - roughness_value = float(material.roughness) - changed, new_roughness = imgui.slider_float(f"粗糙度##rough_{i}", roughness_value, 0.0, 1.0) - if changed: - self._update_material_roughness(material, new_roughness) - except: - imgui.text_colored((0.7, 0.7, 0.7, 1.0), "粗糙度: 不可用") - - if hasattr(material, 'metallic') and material.metallic is not None: - try: - metallic_value = float(material.metallic) - changed, new_metallic = imgui.slider_float(f"金属性##metal_{i}", metallic_value, 0.0, 1.0) - if changed: - self._update_material_metallic(material, new_metallic) - except: - imgui.text_colored((0.7, 0.7, 0.7, 1.0), "金属性: 不可用") - - if hasattr(material, 'refractive_index') and material.refractive_index is not None: - try: - ior_value = float(material.refractive_index) - changed, new_ior = imgui.slider_float(f"折射率##ior_{i}", ior_value, 1.0, 3.0) - if changed: - self._update_material_ior(material, new_ior) - except: - imgui.text_colored((0.7, 0.7, 0.7, 1.0), "折射率: 不可用") - - # 材质预设 - imgui.text("材质预设") - presets = ["默认", "金属", "塑料", "玻璃", "木材", "混凝土"] - current_preset = 0 # 默认选择 - - if imgui.begin_combo(f"预设##preset_{i}", presets[current_preset]): - for j, preset_name in enumerate(presets): - if imgui.selectable(preset_name, j == current_preset): - self._apply_material_preset(material, preset_name) - imgui.end_combo() - - # 纹理信息 - imgui.text("纹理贴图") - if imgui.button(f"选择漫反射贴图##diffuse_{i}"): - self._select_texture_for_material(node, material, "diffuse") - - imgui.same_line() - if imgui.button(f"选择法线贴图##normal_{i}"): - self._select_texture_for_material(node, material, "normal") - - imgui.same_line() - if imgui.button(f"选择粗糙度贴图##roughness_{i}"): - self._select_texture_for_material(node, material, "roughness") - - if imgui.button(f"选择金属性贴图##metallic_{i}"): - self._select_texture_for_material(node, material, "metallic") - - imgui.same_line() - if imgui.button(f"选择自发光贴图##emission_{i}"): - self._select_texture_for_material(node, material, "emission") - - imgui.same_line() - if imgui.button(f"清除所有贴图##clear_{i}"): - self._clear_all_textures(node) - - # 着色模型选择 - self._draw_shading_model_panel(material, i) - - # 显示当前纹理信息 - self._display_current_textures(node, material) - - def _draw_shading_model_panel(self, material, material_index): - """绘制着色模型选择面板""" - try: - imgui.text("着色模型") - - # RenderPipeline支持的着色模型 - shading_models = ["默认", "自发光", "透明"] - current_model = 0 # 默认选择 - - # 安全地获取当前着色模型 - try: - if hasattr(material, 'emission') and material.emission is not None: - current_model = int(material.emission.x) - except: - current_model = 0 - - # 着色模型选择 - if imgui.begin_combo(f"着色模型##shading_{material_index}", shading_models[current_model]): - for j, model_name in enumerate(shading_models): - if imgui.selectable(model_name, j == current_model): - self._update_shading_model(material, j) - imgui.end_combo() - - # 如果是透明着色模型,添加透明度控制 - if current_model == 3: # 透明着色模型 - imgui.text("透明度设置") - try: - if hasattr(material, 'shading_model_param0'): - current_opacity = material.shading_model_param0 - else: - current_opacity = 1.0 - - changed, new_opacity = imgui.slider_float(f"不透明度##opacity_{material_index}", current_opacity, 0.0, 1.0) - if changed: - self._update_transparency(material, new_opacity) - except: - imgui.text_colored((0.7, 0.7, 0.7, 1.0), "透明度控制不可用") - - except Exception as e: - print(f"绘制着色模型面板失败: {e}") - diff --git a/ui/panels/editor_panels_right_collision.py b/ui/panels/editor_panels_right_collision.py new file mode 100644 index 00000000..aafc5819 --- /dev/null +++ b/ui/panels/editor_panels_right_collision.py @@ -0,0 +1,218 @@ +from imgui_bundle import imgui, imgui_ctx + +class EditorPanelsRightCollisionMixin: + """Auto-split mixin from editor_panels_right.py.""" + + def _draw_collision_properties(self, node): + """绘制碰撞检测属性""" + if not node or node.isEmpty(): + return + + try: + # 检查节点是否已有碰撞 + has_collision = self._has_collision(node) + + # 碰撞状态徽章 + imgui.text("状态:") + imgui.same_line() + if has_collision: + imgui.text_colored((0.0, 0.8, 0.0, 1.0), "🟢 已启用") + else: + imgui.text_colored((0.8, 0.0, 0.0, 1.0), "🔴 未启用") + + imgui.separator() + + # 碰撞形状选择 + imgui.text("碰撞形状:") + imgui.same_line() + + # 碰撞形状选项 + collision_shapes = ["球形 (Sphere)", "盒型 (Box)", "胶囊体 (Capsule)", "平面 (Plane)", "自动选择 (Auto)"] + + # 获取当前形状 + current_shape = self._get_current_collision_shape(node) if has_collision else getattr(self.app, '_selected_collision_shape', "球形 (Sphere)") + if has_collision: self.app._selected_collision_shape = current_shape + + # 形状选择下拉框 + current_index = collision_shapes.index(current_shape) if current_shape in collision_shapes else 0 + changed, selected_index = imgui.combo("##collision_shape", current_index, collision_shapes) + if changed: + # 始终更新选择的形状 + selected_shape = collision_shapes[selected_index] + self.app._selected_collision_shape = selected_shape + # 如果已经有碰撞体,询问用户是否要重新创建 + if has_collision: + self._remove_collision_from_node(node) + self._add_collision_to_node(node) + + imgui.separator() + + # 位置偏移控件 + imgui.text("位置偏移:") + + # 获取当前位置偏移 + pos_offset = self._get_collision_position_offset(node) + + # X位置 + changed, new_x = imgui.drag_float("X##collision_pos_x", pos_offset[0], 0.1, -100.0, 100.0, "%.2f") + if changed and has_collision: + self._update_collision_position(node, 'x', new_x) + + # Y位置 + changed, new_y = imgui.drag_float("Y##collision_pos_y", pos_offset[1], 0.1, -100.0, 100.0, "%.2f") + if changed and has_collision: + self._update_collision_position(node, 'y', new_y) + + # Z位置 + changed, new_z = imgui.drag_float("Z##collision_pos_z", pos_offset[2], 0.1, -100.0, 100.0, "%.2f") + if changed and has_collision: + self._update_collision_position(node, 'z', new_z) + + # 形状特定参数(始终显示,但根据状态启用/禁用) + shape_type = self._get_current_collision_shape_type(node) + self._draw_shape_specific_parameters(node, shape_type, has_collision) + + imgui.separator() + + # 操作按钮 + if has_collision: + # 显示/隐藏碰撞体按钮 + is_visible = self._is_collision_visible(node) + visibility_text = "隐藏碰撞体" if is_visible else "显示碰撞体" + if imgui.button(visibility_text): + self._toggle_collision_visibility(node) + + imgui.same_line() + + # 移除碰撞按钮 + if imgui.button("移除碰撞"): + self._remove_collision_from_node(node) + else: + # 添加碰撞按钮 + if imgui.button("添加碰撞"): + self._add_collision_to_node(node) + + imgui.separator() + + # 碰撞检测触发模式 + imgui.text("触发模式:") + + # 自动检测开关 + auto_enabled = self.collision_manager.model_collision_enabled if hasattr(self, 'collision_manager') else False + changed, new_auto = imgui.checkbox("自动检测", auto_enabled) + if changed and hasattr(self, 'collision_manager'): + self.collision_manager.enableModelCollisionDetection(new_auto, 0.1, 0.5) + + imgui.same_line() + + # 手动检测按钮 + if imgui.button("立即检测"): + if hasattr(self, 'collision_manager'): + self._manual_collision_detection() + + except Exception as e: + print(f"绘制碰撞属性失败: {e}") + import traceback + traceback.print_exc() + + def _draw_shape_specific_parameters(self, node, shape_type, has_collision=True): + """绘制形状特定参数""" + try: + if shape_type == "sphere": + self._draw_sphere_parameters(node, has_collision) + elif shape_type == "box": + self._draw_box_parameters(node, has_collision) + elif shape_type == "capsule": + self._draw_capsule_parameters(node, has_collision) + elif shape_type == "plane": + self._draw_plane_parameters(node, has_collision) + except Exception as e: + print(f"绘制形状参数失败: {e}") + + def _draw_sphere_parameters(self, node, has_collision=True): + """绘制球形参数""" + try: + imgui.text("球形参数:") + imgui.same_line() + + # 获取当前半径 + radius = self._get_sphere_radius(node) + + # 半径调整 + changed, new_radius = imgui.drag_float("半径##sphere_radius", radius, 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_sphere_radius(node, new_radius) + + except Exception as e: + print(f"绘制球形参数失败: {e}") + + def _draw_box_parameters(self, node, has_collision=True): + """绘制盒型参数""" + try: + imgui.text("盒型参数:") + + # 获取当前尺寸 + size = self._get_box_size(node) + + # 尺寸调整 + changed, new_x = imgui.drag_float("长度##box_length", size[0], 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_box_size(node, 'x', new_x) + + changed, new_y = imgui.drag_float("宽度##box_width", size[1], 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_box_size(node, 'y', new_y) + + changed, new_z = imgui.drag_float("高度##box_height", size[2], 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_box_size(node, 'z', new_z) + + except Exception as e: + print(f"绘制盒型参数失败: {e}") + + def _draw_capsule_parameters(self, node, has_collision=True): + """绘制胶囊体参数""" + try: + imgui.text("胶囊体参数:") + + # 获取当前参数 + radius = self._get_capsule_radius(node) + height = self._get_capsule_height(node) + + # 半径调整 + changed, new_radius = imgui.drag_float("半径##capsule_radius", radius, 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_capsule_radius(node, new_radius) + + # 高度调整 + changed, new_height = imgui.drag_float("高度##capsule_height", height, 0.1, 0.1, 100.0, "%.2f") + if changed and has_collision: + self._update_capsule_height(node, new_height) + + except Exception as e: + print(f"绘制胶囊体参数失败: {e}") + + def _draw_plane_parameters(self, node, has_collision=True): + """绘制平面参数""" + try: + imgui.text("平面参数:") + + # 获取当前法向量 + normal = self._get_plane_normal(node) + + # 法向量调整 + changed, new_x = imgui.drag_float("法向量 X##plane_normal_x", normal[0], 0.1, -1.0, 1.0, "%.2f") + if changed and has_collision: + self._update_plane_normal(node, 'x', new_x) + + changed, new_y = imgui.drag_float("法向量 Y##plane_normal_y", normal[1], 0.1, -1.0, 1.0, "%.2f") + if changed and has_collision: + self._update_plane_normal(node, 'y', new_y) + + changed, new_z = imgui.drag_float("法向量 Z##plane_normal_z", normal[2], 0.1, -1.0, 1.0, "%.2f") + if changed and has_collision: + self._update_plane_normal(node, 'z', new_z) + + except Exception as e: + print(f"绘制平面参数失败: {e}") + diff --git a/ui/panels/editor_panels_right_material.py b/ui/panels/editor_panels_right_material.py new file mode 100644 index 00000000..c1e62de1 --- /dev/null +++ b/ui/panels/editor_panels_right_material.py @@ -0,0 +1,227 @@ +from imgui_bundle import imgui, imgui_ctx + +class EditorPanelsRightMaterialMixin: + """Auto-split mixin from editor_panels_right.py.""" + + def _draw_appearance_properties(self, node): + """绘制外观属性""" + # 颜色属性 + if hasattr(node, 'getColor'): + imgui.text("颜色") + try: + color = node.getColor() + # 确保颜色是有效的 + if not color or len(color) < 3: + color = (1.0, 1.0, 1.0, 1.0) # 默认白色 + except: + color = (1.0, 1.0, 1.0, 1.0) # 默认白色 + + # 颜色滑块 + changed, new_r = imgui.slider_float("R##color_r", color[0], 0.0, 1.0) + if changed: + new_color = (new_r, color[1], color[2], color[3] if len(color) > 3 else 1.0) + node.setColor(new_color) + color = new_color + + changed, new_g = imgui.slider_float("G##color_g", color[1], 0.0, 1.0) + if changed: + new_color = (color[0], new_g, color[2], color[3] if len(color) > 3 else 1.0) + node.setColor(new_color) + color = new_color + + changed, new_b = imgui.slider_float("B##color_b", color[2], 0.0, 1.0) + if changed: + new_color = (color[0], color[1], new_b, color[3] if len(color) > 3 else 1.0) + node.setColor(new_color) + color = new_color + + # 只有当颜色有alpha通道时才显示alpha滑块 + if len(color) > 3: + changed, new_a = imgui.slider_float("A##color_a", color[3], 0.0, 1.0) + if changed: + new_color = (color[0], color[1], color[2], new_a) + node.setColor(new_color) + color = new_color + + # 颜色预览和选择器 + imgui.text("颜色预览") + color_with_alpha = (color[0], color[1], color[2], color[3] if len(color) > 3 else 1.0) + if imgui.color_button("颜色预览##preview", color_with_alpha, 0, (100, 30)): + # 点击颜色按钮打开颜色选择器 + self.show_color_picker(node, 'color', color_with_alpha) + + imgui.same_line() + if imgui.button("选择颜色##color_picker_btn"): + self.show_color_picker(node, 'color', (color.x, color.y, color.z, color.w)) + + # 透明度 + if hasattr(node, 'setTransparency') and hasattr(node, 'getTransparency'): + imgui.text("透明度") + current_transparency = node.getTransparency() + # 将当前的透明度值转换为0.0-1.0范围用于显示 + display_transparency = 1.0 - current_transparency if current_transparency <= 1 else 0.0 + changed, new_transparency = imgui.slider_float("透明度", display_transparency, 0.0, 1.0) + if changed: + # 将0.0-1.0范围转换回Panda3D的透明度格式 + panda_transparency = int((1.0 - new_transparency) * 255) + node.setTransparency(panda_transparency) + + # 材质属性 + self._draw_material_properties(node) + + # 渲染状态 + imgui.text("渲染状态") + if imgui.button("应用材质"): + self._apply_material_to_node(node) + + imgui.same_line() + if imgui.button("重置材质"): + self._reset_material(node) + + def _draw_material_properties(self, node): + """绘制材质属性""" + materials = node.find_all_materials() + + if not materials: + imgui.text_colored((0.5, 0.5, 0.5, 1.0), "无材质") + return + + for i, material in enumerate(materials): + material_name = material.get_name() if hasattr(material, 'get_name') and material.get_name() else f"材质{i + 1}" + + if imgui.collapsing_header(f"材质: {material_name}"): + # 材质基础颜色 + base_color = self._get_material_base_color(material) + if base_color: + imgui.text("基础颜色") + changed, new_r = imgui.slider_float(f"R##mat_r_{i}", base_color[0], 0.0, 1.0) + if changed: + self._update_material_base_color(material, 'r', new_r) + base_color = (new_r, base_color[1], base_color[2], base_color[3]) + + changed, new_g = imgui.slider_float(f"G##mat_g_{i}", base_color[1], 0.0, 1.0) + if changed: + self._update_material_base_color(material, 'g', new_g) + base_color = (base_color[0], new_g, base_color[2], base_color[3]) + + changed, new_b = imgui.slider_float(f"B##mat_b_{i}", base_color[2], 0.0, 1.0) + if changed: + self._update_material_base_color(material, 'b', new_b) + base_color = (base_color[0], base_color[1], new_b, base_color[3]) + + changed, new_a = imgui.slider_float(f"A##mat_a_{i}", base_color[3], 0.0, 1.0) + if changed: + self._update_material_base_color(material, 'a', new_a) + base_color = (base_color[0], base_color[1], base_color[2], new_a) + + # PBR属性 + if hasattr(material, 'roughness') and material.roughness is not None: + imgui.text("PBR属性") + try: + roughness_value = float(material.roughness) + changed, new_roughness = imgui.slider_float(f"粗糙度##rough_{i}", roughness_value, 0.0, 1.0) + if changed: + self._update_material_roughness(material, new_roughness) + except: + imgui.text_colored((0.7, 0.7, 0.7, 1.0), "粗糙度: 不可用") + + if hasattr(material, 'metallic') and material.metallic is not None: + try: + metallic_value = float(material.metallic) + changed, new_metallic = imgui.slider_float(f"金属性##metal_{i}", metallic_value, 0.0, 1.0) + if changed: + self._update_material_metallic(material, new_metallic) + except: + imgui.text_colored((0.7, 0.7, 0.7, 1.0), "金属性: 不可用") + + if hasattr(material, 'refractive_index') and material.refractive_index is not None: + try: + ior_value = float(material.refractive_index) + changed, new_ior = imgui.slider_float(f"折射率##ior_{i}", ior_value, 1.0, 3.0) + if changed: + self._update_material_ior(material, new_ior) + except: + imgui.text_colored((0.7, 0.7, 0.7, 1.0), "折射率: 不可用") + + # 材质预设 + imgui.text("材质预设") + presets = ["默认", "金属", "塑料", "玻璃", "木材", "混凝土"] + current_preset = 0 # 默认选择 + + if imgui.begin_combo(f"预设##preset_{i}", presets[current_preset]): + for j, preset_name in enumerate(presets): + if imgui.selectable(preset_name, j == current_preset): + self._apply_material_preset(material, preset_name) + imgui.end_combo() + + # 纹理信息 + imgui.text("纹理贴图") + if imgui.button(f"选择漫反射贴图##diffuse_{i}"): + self._select_texture_for_material(node, material, "diffuse") + + imgui.same_line() + if imgui.button(f"选择法线贴图##normal_{i}"): + self._select_texture_for_material(node, material, "normal") + + imgui.same_line() + if imgui.button(f"选择粗糙度贴图##roughness_{i}"): + self._select_texture_for_material(node, material, "roughness") + + if imgui.button(f"选择金属性贴图##metallic_{i}"): + self._select_texture_for_material(node, material, "metallic") + + imgui.same_line() + if imgui.button(f"选择自发光贴图##emission_{i}"): + self._select_texture_for_material(node, material, "emission") + + imgui.same_line() + if imgui.button(f"清除所有贴图##clear_{i}"): + self._clear_all_textures(node) + + # 着色模型选择 + self._draw_shading_model_panel(material, i) + + # 显示当前纹理信息 + self._display_current_textures(node, material) + + def _draw_shading_model_panel(self, material, material_index): + """绘制着色模型选择面板""" + try: + imgui.text("着色模型") + + # RenderPipeline支持的着色模型 + shading_models = ["默认", "自发光", "透明"] + current_model = 0 # 默认选择 + + # 安全地获取当前着色模型 + try: + if hasattr(material, 'emission') and material.emission is not None: + current_model = int(material.emission.x) + except: + current_model = 0 + + # 着色模型选择 + if imgui.begin_combo(f"着色模型##shading_{material_index}", shading_models[current_model]): + for j, model_name in enumerate(shading_models): + if imgui.selectable(model_name, j == current_model): + self._update_shading_model(material, j) + imgui.end_combo() + + # 如果是透明着色模型,添加透明度控制 + if current_model == 3: # 透明着色模型 + imgui.text("透明度设置") + try: + if hasattr(material, 'shading_model_param0'): + current_opacity = material.shading_model_param0 + else: + current_opacity = 1.0 + + changed, new_opacity = imgui.slider_float(f"不透明度##opacity_{material_index}", current_opacity, 0.0, 1.0) + if changed: + self._update_transparency(material, new_opacity) + except: + imgui.text_colored((0.7, 0.7, 0.7, 1.0), "透明度控制不可用") + + except Exception as e: + print(f"绘制着色模型面板失败: {e}") + diff --git a/ui/panels/editor_panels_right_transform.py b/ui/panels/editor_panels_right_transform.py new file mode 100644 index 00000000..a9aafbdb --- /dev/null +++ b/ui/panels/editor_panels_right_transform.py @@ -0,0 +1,92 @@ +from imgui_bundle import imgui, imgui_ctx + +class EditorPanelsRightTransformMixin: + """Auto-split mixin from editor_panels_right.py.""" + + def _draw_transform_properties(self, node): + """绘制变换属性""" + # 位置组 + if imgui.collapsing_header("位置 Position"): + # 相对位置 + imgui.text("相对位置") + pos = node.getPos() + + # X坐标 + changed, new_x = imgui.input_float("X##pos_x", pos.x, 0.1, 1.0, "%.3f") + if changed: node.setX(new_x) + + # Y坐标 + changed, new_y = imgui.input_float("Y##pos_y", pos.y, 0.1, 1.0, "%.3f") + if changed: node.setY(new_y) + + # Z坐标 + changed, new_z = imgui.input_float("Z##pos_z", pos.z, 0.1, 1.0, "%.3f") + if changed: node.setZ(new_z) + + # 世界位置 + imgui.text("世界位置") + world_pos = node.getPos(self.render) + + imgui.text(f"世界 X: {world_pos.x:.3f}") + imgui.text(f"世界 Y: {world_pos.y:.3f}") + imgui.text(f"世界 Z: {world_pos.z:.3f}") + + # 位置操作按钮 + if imgui.button("重置位置##reset_pos"): + node.setPos(0, 0, 0) + imgui.same_line() + if imgui.button("复制位置##copy_pos"): + self._clipboard_pos = (pos.x, pos.y, pos.z) + imgui.same_line() + if imgui.button("粘贴位置##paste_pos") and hasattr(self, '_clipboard_pos'): + node.setPos(self._clipboard_pos[0], self._clipboard_pos[1], self._clipboard_pos[2]) + + # 旋转组 + if imgui.collapsing_header("旋转 Rotation"): + hpr = node.getHpr() + + # HPR旋转 + imgui.text("HPR 旋转 (度)") + changed, new_h = imgui.input_float("H##rot_h", hpr.x, 1.0, 10.0, "%.1f") + if changed: node.setH(new_h) + + changed, new_p = imgui.input_float("P##rot_p", hpr.y, 1.0, 10.0, "%.1f") + if changed: node.setP(new_p) + + changed, new_r = imgui.input_float("R##rot_r", hpr.z, 1.0, 10.0, "%.1f") + if changed: node.setR(new_r) + + # 旋转操作按钮 + if imgui.button("重置旋转##reset_rot"): + node.setHpr(0, 0, 0) + imgui.same_line() + if imgui.button("随机旋转##random_rot"): + import random + node.setHpr(random.randint(0, 360), random.randint(0, 360), random.randint(0, 360)) + + # 缩放组 + if imgui.collapsing_header("缩放 Scale"): + scale = node.getScale() + + # XYZ缩放 + imgui.text("XYZ 缩放") + changed, new_sx = imgui.input_float("X##scale_x", scale.x, 0.1, 1.0, "%.3f") + if changed: node.setSx(new_sx) + + changed, new_sy = imgui.input_float("Y##scale_y", scale.y, 0.1, 1.0, "%.3f") + if changed: node.setSy(new_sy) + + changed, new_sz = imgui.input_float("Z##scale_z", scale.z, 0.1, 1.0, "%.3f") + if changed: node.setSz(new_sz) + + # 统一缩放 + if imgui.button("统一缩放##uniform_scale"): + uniform_scale = (scale.x + scale.y + scale.z) / 3.0 + node.setScale(uniform_scale, uniform_scale, uniform_scale) + imgui.same_line() + if imgui.button("重置缩放##reset_scale"): + node.setScale(1, 1, 1) + imgui.same_line() + if imgui.button("翻倍##double_scale"): + node.setScale(scale.x * 2, scale.y * 2, scale.z * 2) +