1.坐标轴颜色正常但需继续更改sort

2.拖拽结束后模型可见性更新
This commit is contained in:
Hector 2025-08-20 16:36:19 +08:00
parent 138820ed48
commit dc150f793b
3 changed files with 177 additions and 325 deletions

BIN
core/TranslateArrowHandle.fbx Executable file

Binary file not shown.

View File

@ -11,7 +11,7 @@ from PIL.ImageChops import lighter
from panda3d.core import (Vec3, Point3, Point2, LineSegs, ColorAttrib, RenderState,
DepthTestAttrib, CollisionTraverser, CollisionHandlerQueue,
CollisionNode, CollisionRay, GeomNode, BitMask32, Material, LColor, DepthWriteAttrib,
TransparencyAttrib)
TransparencyAttrib, Vec4)
from direct.task.TaskManagerGlobal import taskMgr
import math
@ -50,14 +50,14 @@ class SelectionSystem:
# 高亮相关
self.gizmoHighlightAxis = None
self.gizmo_colors = {
"x": (1*10, 0, 0, 1), # 红色
"y": (0, 1*10, 0, 1), # 绿色
"z": (0, 0, 1*10, 1) # 蓝色
"x": (1, 0, 0, 0), # 红色
"y": (0, 1, 0, 0), # 绿色
"z": (0, 0, 1, 0) # 蓝色
}
self.gizmo_highlight_colors = {
"x": (1.5*20, 1.5*20, 0, 1), # 黄色高亮
"y": (1.5*20, 1.5*20, 0, 1), # 黄色高亮
"z": (1.5*20, 1.5*20, 0, 1) # 黄色高亮
"x": (1, 1, 0, 0), # 黄色高亮
"y": (1, 1, 0, 0), # 黄色高亮
"z": (1, 1, 0, 0) # 黄色高亮
}
print("✓ 选择和变换系统初始化完成")
@ -303,7 +303,7 @@ class SelectionSystem:
# 只调用一次几何体创建
self.createGizmoGeometry()
# 只调用一次颜色设置
#只调用一次颜色设置
self.setGizmoAxisColor("x", self.gizmo_colors["x"])
self.setGizmoAxisColor("y", self.gizmo_colors["y"])
self.setGizmoAxisColor("z", self.gizmo_colors["z"])
@ -322,321 +322,79 @@ class SelectionSystem:
if not self.gizmo:
return
# 创建X轴红色
x_lines = LineSegs("x_axis")
x_lines.setThickness(6.0)
x_lines.moveTo(0, 0, 0)
x_lines.drawTo(self.axis_length, 0, 0)
# 创建X轴箭头
x_lines.moveTo(self.axis_length - 0.5, -0.2, 0)
x_lines.drawTo(self.axis_length, 0, 0)
x_lines.drawTo(self.axis_length - 0.5, 0.2, 0)
x_geom = x_lines.create()
self.gizmoXAxis = self.gizmo.attachNewNode(x_geom)
self.gizmoXAxis.setName("gizmo_x_axis")
#self.gizmoXAxis.setLightOff()
# 创建Y轴绿色
y_lines = LineSegs("y_axis")
y_lines.setThickness(6.0)
y_lines.moveTo(0, 0, 0)
y_lines.drawTo(0, self.axis_length, 0)
# 创建Y轴箭头
y_lines.moveTo(-0.2, self.axis_length - 0.5, 0)
y_lines.drawTo(0, self.axis_length, 0)
y_lines.drawTo(0.2, self.axis_length - 0.5, 0)
y_geom = y_lines.create()
self.gizmoYAxis = self.gizmo.attachNewNode(y_geom)
self.gizmoYAxis.setName("gizmo_y_axis")
#self.gizmoYAxis.setLightOff()
model_paths = [
"core/TranslateArrowHandle.fbx",
"EG/core/TranslateArrowHandle.fbx",
]
arrow_model = None
for path in model_paths:
try:
arrow_model = self.world.loader.loadModel(path)
if arrow_model:
print(f"成功加载模型: {path}")
break
except:
continue
self.gizmoXAxis = self.gizmo.attachNewNode("gizmo_x_axis")
x_arrow = arrow_model.copyTo(self.gizmoXAxis)
x_arrow.setName("x_arrow")
x_arrow.setHpr(0,-90,0)
x_arrow.setScale(0.1,0.05,0.05)
x_arrow.setPos(0,0,0)
self.gizmoYAxis = self.gizmo.attachNewNode("gizmo_y_axis")
y_arrow = arrow_model.copyTo(self.gizmoYAxis)
y_arrow.setName("y_arrow")
y_arrow.setHpr(90,0,0)
y_arrow.setScale(0.1,0.05,0.05)
y_arrow.setPos(0,0,0)
# 创建Z轴蓝色
z_lines = LineSegs("z_axis")
z_lines.setThickness(6.0)
z_lines.moveTo(0, 0, 0)
z_lines.drawTo(0, 0, self.axis_length)
# 创建Z轴箭头
z_lines.moveTo(-0.2, 0, self.axis_length - 0.5)
z_lines.drawTo(0, 0, self.axis_length)
z_lines.drawTo(0.2, 0, self.axis_length - 0.5)
z_geom = z_lines.create()
self.gizmoZAxis = self.gizmo.attachNewNode(z_geom)
self.gizmoZAxis.setName("gizmo_z_axis")
#self.gizmoZAxis.setLightOff()
self.gizmoZAxis = self.gizmo.attachNewNode("gizmo_z_axis")
z_arrow = arrow_model.copyTo(self.gizmoZAxis)
z_arrow.setName("z_arrow")
# 旋转箭头使其指向Z轴正方向
z_arrow.setHpr(0, 0, -90) # 根据需要调整旋转
z_arrow.setScale(0.1,0.05,0.05)
z_arrow.setPos(0, 0, 0)
# 确保坐标轴不被光照影响
#self.gizmo.setLightOff()
# 使用最强的渲染设置,确保坐标轴绝对不会被遮挡
self.gizmo.setBin("gui-popup", 0) # 使用最高的GUI渲染层
self.gizmo.setDepthTest(False) # 完全禁用深度测试
self.gizmo.setDepthWrite(False) # 禁用深度写入
self.gizmo.setTwoSided(True) # 双面渲染
# 创建强制前景渲染状态
from panda3d.core import RenderModeAttrib, TransparencyAttrib
foreground_state = RenderState.make(
DepthTestAttrib.make(DepthTestAttrib.MNone), # 完全不进行深度测试
TransparencyAttrib.make(TransparencyAttrib.MAlpha) # 启用透明度混合
)
#self.gizmo.setState(foreground_state)
# 对每个坐标轴设置独立的最高渲染优先级
self.gizmoXAxis.setBin("gui-popup", 10)
self.gizmoXAxis.setDepthTest(False)
self.gizmoXAxis.setDepthWrite(False)
self.gizmoXAxis.setLightOff()
self.gizmoXAxis.setState(foreground_state)
self.gizmoYAxis.setBin("gui-popup", 20)
self.gizmoYAxis.setDepthTest(False)
self.gizmoYAxis.setDepthWrite(False)
self.gizmoYAxis.setLightOff()
self.gizmoYAxis.setState(foreground_state)
self.gizmoZAxis.setBin("gui-popup", 30)
self.gizmoZAxis.setDepthTest(False)
self.gizmoZAxis.setDepthWrite(False)
self.gizmoZAxis.setLightOff()
self.gizmoZAxis.setState(foreground_state)
# 初始化高亮状态
self.gizmoHighlightAxis = None
# 立即设置初始颜色,确保创建时就有正确的颜色
self.setGizmoAxisColor("z", self.gizmo_colors["z"])
# 设置初始颜色
self.setGizmoAxisColor("x", self.gizmo_colors["x"])
self.setGizmoAxisColor("y", self.gizmo_colors["y"])
self.setGizmoAxisColor("z", self.gizmo_colors["z"])
# 使用最强的渲染设置,确保坐标轴绝对不会被遮挡
# self.gizmo.setBin("default", 0) # 使用最高的GUI渲染层
# self.gizmo.setDepthTest(True) # 完全禁用深度测试
# self.gizmo.setDepthWrite(True) # 禁用深度写入
# self.gizmo.setTwoSided(True) # 双面渲染
print(f"✓ 坐标轴几何体创建完成,长度={self.axis_length}")
# 为 RenderPipeline 环境设置正确的渲染状态
self._setupRenderPipelineCompatibleGizmo()
self._setupEmissiveMaterials()
self._setupGizmoRendering()
except Exception as e:
print(f"创建坐标轴几何体失败: {str(e)}")
def _setupEmissiveMaterials(self):
try:
from panda3d.core import Material,Vec4
materials ={
"x":(Vec4(1,0,0,1),Vec4(2.0,0,0,1)),
"y":(Vec4(0,1,0,1),Vec4(0,2.0,0,1)),
"z":(Vec4(0,0,1,1),Vec4(0,0,2.0,1))
}
axis_nodes ={
"x":self.gizmoXAxis,
"y":self.gizmoYAxis,
"z":self.gizmoZAxis
}
for axis,(base_color,emission_color) in materials.items():
if axis_nodes[axis]:
material=Material(f"gizmo_{axis}_material")
material.setBaseColor(base_color)
material.setEmission(emission_color)
material.setRoughness(1.0)
material.setMetallic(0.0)
axis_nodes[axis].setMaterial(material)
except Exception as e:
print(f"自发光材质设置失败: {str(e)}")
def _applyAxisMaterial(self, node, color):
from panda3d.core import Material, Vec4, ColorWriteAttrib, DepthWriteAttrib
# 构造一个“自发光”的材质,让颜色不依赖灯光/法线
m = Material()
col = Vec4(*color)
m.setBaseColor(col) # 记录用
m.setDiffuse(col) # 记录用RP标准材质可能不读取
m.setEmission(Vec4(col.x, col.y, col.z, 1.0)) # 关键:用发光通道显示颜色
node.setMaterial(m, 1)
def _setupGizmoRendering(self):
"""设置坐标轴渲染属性"""
try:
# 设置渲染优先级,确保在最前面显示
self.gizmo.setBin("gui-popup", 1000)
self.gizmo.setDepthTest(False)
self.gizmo.setDepthWrite(False)
self.gizmo.setLightOff()
# 走能直接写到最终画面的阶段(两种方式二选一):
# 方式1完全绕过管线最稳
node.setTag("pipeline-disable", "1")
# 方式2留在管线内但走最终阶段若不想禁用管线可改用下面这一行并去掉上一行
# node.setTag("pipeline-stage", "final")
# 为每个轴设置独立的渲染属性
for i, axis_node in enumerate([self.gizmoXAxis, self.gizmoYAxis, self.gizmoZAxis]):
if axis_node:
axis_node.setBin("gui-popup", 1001 + i)
axis_node.setDepthTest(False)
axis_node.setDepthWrite(False)
axis_node.setLightOff()
except Exception as e:
print(f"设置坐标轴渲染失败!!!!!!: {str(e)}")
def _setupRenderPipelineCompatibleGizmo(self):
"""为 RenderPipeline 环境设置兼容的坐标轴渲染 - 激进修复版本"""
try:
from panda3d.core import (ShaderAttrib, MaterialAttrib, RenderModeAttrib,
AntialiasAttrib, TransparencyAttrib, CullFaceAttrib,
RescaleNormalAttrib, TextureAttrib)
# 第一步:完全隔离坐标轴,避免被任何系统处理
self._isolateGizmoFromRenderPipeline()
# 第二步:使用最简单的渲染方式
self._setupMinimalGizmoRendering()
# 第三步:强制设置每个轴的独立渲染
self._forceAxisIndependentRendering()
except Exception as e:
# 使用最后的备用方案
self._setupUltimateGizmoFallback()
def _isolateGizmoFromRenderPipeline(self):
"""完全隔离坐标轴,避免被 RenderPipeline 处理"""
try:
# 设置所有可能的隔离标签
isolation_tags = [
("no_shadow", "1"),
("no_lighting", "1"),
("no_material", "1"),
("no_shader", "1"),
("no_fog", "1"),
("no_texture", "1"),
("gui_element", "1"),
("bypass_rp", "1"),
("fixed_pipeline", "1"),
("ignore_all", "1")
]
for tag, value in isolation_tags:
self.gizmo.setTag(tag, value)
# 完全禁用所有高级功能,使用最高优先级
self.gizmo.setShaderOff(10000)
self.gizmo.setLightOff(10000)
self.gizmo.setFogOff(10000)
self.gizmo.setMaterialOff(10000)
self.gizmo.setTextureOff(10000)
# 禁用所有可能的渲染特性
from panda3d.core import RenderModeAttrib, CullFaceAttrib
# self.gizmo.setRenderModeWireframe()
# self.gizmo.setTwoSided(True)
self.gizmo.setRenderMode(RenderModeAttrib.MFilled)
self.gizmo.setTwoSided(True)
self.gizmo.setColorScale(2.0,2.0,2.0,1.0)
for axis_node in [self.gizmoXAxis,self.gizmoYAxis,self.gizmoZAxis]:
if axis_node:
axis_node.setTag("emissive","1")
axis_node.setTag("unlit","1")
axis_node.setColorScale(2.0,2.0,2.0,1.0)
except Exception as e:
print(f" ❌ 隔离失败: {e}")
def _setupMinimalGizmoRendering(self):
"""设置最简单的渲染方式"""
try:
from panda3d.core import (ShaderAttrib, MaterialAttrib, TextureAttrib,
CullFaceAttrib, RescaleNormalAttrib)
# 使用最高优先级的 GUI 渲染 bin
self.gizmo.setBin("gui-popup", 10000)
self.gizmo.setDepthTest(False)
self.gizmo.setDepthWrite(False)
# 创建最简单的渲染状态
minimal_state = RenderState.make(
ShaderAttrib.makeOff(10000), # 完全禁用着色器
MaterialAttrib.makeOff(), # 禁用材质
TextureAttrib.makeOff(), # 禁用纹理
CullFaceAttrib.make(CullFaceAttrib.MCullNone), # 禁用面剔除
RescaleNormalAttrib.makeOff() # 禁用法线重缩放
)
self.gizmo.setState(minimal_state, 10000)
except Exception as e:
print(f" ❌ 最简渲染设置失败: {e}")
def _forceAxisIndependentRendering(self):
"""强制设置每个轴的独立渲染"""
try:
# 轴配置
axis_configs = [
(self.gizmoXAxis, "X轴", (1.0, 0.0, 0.0, 1.0), 0),
(self.gizmoYAxis, "Y轴", (0.0, 1.0, 0.0, 1.0), 0),
(self.gizmoZAxis, "Z轴", (0.0, 0.0, 1.0, 1.0), 0)
]
for axis_node, name, color, priority in axis_configs:
if axis_node:
# 每个轴都完全独立设置
self._setupSingleAxisRendering(axis_node, name, color, 0)
except Exception as e:
print(f" ❌ 独立轴渲染设置失败: {e}")
def _setupSingleAxisRendering(self, axis_node, name, color, priority):
"""为单个轴设置完全独立的渲染"""
try:
from panda3d.core import (LVecBase4f, RenderState, ColorAttrib,
TransparencyAttrib, LColor, AntialiasAttrib,
RenderModeAttrib, CullFaceAttrib, AuxBitplaneAttrib,
LightRampAttrib)
# 转换颜色为LColor并增加亮度
base_color = LColor(*color)
emissive_color = LColor(base_color[0], base_color[1], base_color[2], 1.0)
# 完全禁用所有高级渲染功能
axis_node.clearShader()
axis_node.clearTexture()
axis_node.clearMaterial()
axis_node.setLightOff()
axis_node.setFogOff()
axis_node.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 6.0))
axis_node.setAttrib(AntialiasAttrib.make(AntialiasAttrib.MLine))
axis_node.setBin("gui-popup", 0)
axis_node.setDepthTest(False)
axis_node.setDepthWrite(False)
axis_node.setTwoSided(True)
# 强制设置自发光颜色
axis_node.setColor(*color)
axis_node.setColorScale(1.0, 1.0, 1.0, 1.0) # 增加整体亮度
except Exception as e:
print("{} 轴渲染设置失败: {}".format(name, str(e)))
raise e
def _setupUltimateGizmoFallback(self):
"""最后的备用方案 - 最简单的渲染"""
try:
# 最简单的设置
self.gizmo.setLightOff()
self.gizmo.setFogOff()
self.gizmo.setBin("gui-popup", 20000)
self.gizmo.setDepthTest(False)
self.gizmo.setDepthWrite(False)
# 直接设置颜色,不使用复杂的渲染状态
if self.gizmoXAxis:
self.gizmoXAxis.setColor(1, 0, 0, 1)
self.gizmoXAxis.setLightOff()
self.gizmoXAxis.setBin("gui-popup", 20001)
self.gizmoXAxis.setDepthTest(False)
if self.gizmoYAxis:
self.gizmoYAxis.setColor(0, 1, 0, 1)
self.gizmoYAxis.setLightOff()
self.gizmoYAxis.setBin("gui-popup", 20002)
self.gizmoYAxis.setDepthTest(False)
if self.gizmoZAxis:
self.gizmoZAxis.setColor(0, 0, 1, 1)
self.gizmoZAxis.setLightOff()
self.gizmoZAxis.setBin("gui-popup", 20003)
self.gizmoZAxis.setDepthTest(False)
except Exception as e:
print(f"❌ 最后备用方案也失败: {e}")
# 可见性状态:允许颜色写入,不写深度,双面可见,禁用雾
node.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_all))
node.setAttrib(DepthWriteAttrib.make(False))
node.setTwoSided(True)
node.setFogOff()
def updateGizmoTask(self, task):
"""坐标轴更新任务 - 包含固定大小功能"""
@ -791,34 +549,127 @@ class SelectionSystem:
self.gizmoStartPos = None
def setGizmoAxisColor(self, axis, color):
"""设置坐标轴颜色 - RenderPipeline 兼容版本"""
try:
from panda3d.core import AntialiasAttrib,TransparencyAttrib
# def setGizmoAxisColor(self, axis, color):
# """设置坐标轴颜色 - RenderPipeline 兼容版本"""
# try:
# from panda3d.core import AntialiasAttrib,TransparencyAttrib
#
# axis_nodes = {
# "x": self.gizmoXAxis,
# "y": self.gizmoYAxis,
# "z": self.gizmoZAxis
# }
#
# if axis in axis_nodes and axis_nodes[axis]:
# axis_node = axis_nodes[axis]
#
# axis_node.setColor(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3])
# axis_node.setColorScale(color[0]*10.0,color[1]*10.0,color[2]*10.0,color[3])
# axis_node.setShaderOff(10000)
# axis_node.setLightOff()
# axis_node.setMaterialOff()
# axis_node.setTextureOff()
# axis_node.setFogOff()
#
# except Exception as e:
# print(f"设置坐标轴颜色失败: {str(e)}")
# # 回退到简单的颜色设置
# try:
# if axis in axis_nodes and axis_nodes[axis]:
# axis_nodes[axis].setColor(*color)
# except:
# pass
def setGizmoAxisColor(self, axis, color):
"""使用材质设置坐标轴颜色 - RenderPipeline兼容版本"""
try:
from panda3d.core import Material, Vec4,ColorWriteAttrib,DepthWriteAttrib,DepthTestAttrib,TransparencyAttrib
# 获取对应的轴节点
axis_nodes = {
"x": self.gizmoXAxis,
"y": self.gizmoYAxis,
"z": self.gizmoZAxis
}
if axis in axis_nodes and axis_nodes[axis]:
axis_node = axis_nodes[axis]
if axis not in axis_nodes or not axis_nodes[axis]:
return
axis_node.setColor(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3])
axis_node.setColorScale(color[0]*20.0,color[1]*20.0,color[2]*20.0,color[3])
axis_node.setShaderOff(10000)
axis_node.setLightOff(10000)
axis_node.setMaterialOff(10000)
axis_node.setTextureOff(1000)
axis_node.setFogOff(10000)
axis_node = axis_nodes[axis]
# 查找箭头模型节点
arrow_node = None
if axis == "x":
arrow_node = axis_node.find("x_arrow")
elif axis == "y":
arrow_node = axis_node.find("y_arrow")
elif axis == "z":
arrow_node = axis_node.find("z_arrow")
if not arrow_node:
print(f"未找到{axis}轴的箭头模型")
return
# 创建或获取材质
mat = Material()
# 设置材质属性 - 使用自发光确保在RenderPipeline下可见
mat.setBaseColor(Vec4(color[0], color[1], color[2], color[3]))
mat.setDiffuse(Vec4(0, 0, 0, 1))
#mat.setEmission(Vec4(color[0], color[1], color[2], 1.0)) # 自发光
mat.setEmission(Vec4(1,1,1,1.0)) # 自发光
mat.set_roughness(1)
# 应用材质
arrow_node.setMaterial(mat, 1)
# 设置透明度
if color[3] < 1.0:
arrow_node.setTransparency(TransparencyAttrib.MAlpha)
else:
arrow_node.setTransparency(TransparencyAttrib.MNone)
# 创建自定义渲染状态 - 确保始终在最前方
# state = RenderState.make(
# ColorWriteAttrib.make(ColorWriteAttrib.CAll), # 允许颜色写入
# DepthTestAttrib.make(DepthTestAttrib.MAlways), # 始终通过深度测试
# DepthWriteAttrib.make(DepthWriteAttrib.MOff) # 不写入深度缓冲区
# )
# # 应用渲染状态
# arrow_node.set_state(state)
arrow_node.setLightOff() # 禁用光照影响
arrow_node.setShaderOff() # 禁用着色器
arrow_node.setFogOff() # 禁用雾效果
arrow_node.setBin("fixed", 10) # 使用固定渲染顺序,确保在最前
# 保存材质引用以便后续修改
if axis == "x":
self.xMat = mat
elif axis == "y":
self.yMat = mat
elif axis == "z":
self.zMat = mat
axis_node.setLightOff()
axis_node.setShaderOff()
axis_node.setFogOff()
#axis_node.set_state(state)
axis_node.setBin("fixed", 9) # 确保轴节点在箭头模型之前渲染
except Exception as e:
print(f"设置坐标轴颜色失败: {str(e)}")
# 回退到简单的颜色设置
# 回退到简单颜色设置
try:
axis_nodes = {
"x": self.gizmoXAxis,
"y": self.gizmoYAxis,
"z": self.gizmoZAxis
}
if axis in axis_nodes and axis_nodes[axis]:
axis_nodes[axis].setColor(*color)
axis_nodes[axis].setColor(color[0], color[1], color[2], color[3])
except:
pass

View File

@ -363,6 +363,7 @@ class CustomTreeWidget(QTreeWidget):
# 更新属性面板
self.world.updatePropertyPanel(dragged_item)
self.world.property_panel._syncEffectiveVisibility(dragged_node)
else:
event.ignore()