refactor: 拆分右侧属性面板为变换/材质/碰撞子mixin

This commit is contained in:
ayuan9957 2026-02-28 16:35:40 +08:00
parent 3a13025009
commit 381a478abf
4 changed files with 548 additions and 524 deletions

View File

@ -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}")

View File

@ -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}")

View File

@ -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}")

View File

@ -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)