forked from Rowland/EG
聚焦功能
This commit is contained in:
parent
bd9fa08cb6
commit
7a621a3a51
@ -457,36 +457,36 @@ class EventHandler:
|
||||
# 更新选择状态并显示选择框和坐标轴
|
||||
self.world.selection.updateSelection(selectedModel)
|
||||
|
||||
# # 在树形控件中查找并选中对应的项
|
||||
# if self.world.interface_manager.treeWidget:
|
||||
# #print("查找树形控件中的对应项...")
|
||||
# root = self.world.interface_manager.treeWidget.invisibleRootItem()
|
||||
# foundItem = None
|
||||
#
|
||||
# for i in range(root.childCount()):
|
||||
# sceneItem = root.child(i)
|
||||
# if sceneItem.text(0) == "场景":
|
||||
# #print(f"在场景节点下查找...")
|
||||
# foundItem = self.world.interface_manager.findTreeItem(selectedModel, sceneItem)
|
||||
# if foundItem:
|
||||
# print(f"✓ 在树形控件中找到对应项: {foundItem.text(0)}")
|
||||
# try:
|
||||
# self.world.interface_manager.treeWidget.itemClicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
#
|
||||
# self.world.interface_manager.treeWidget.setCurrentItem(foundItem)
|
||||
#
|
||||
# self.world.interface_manager.treeWidget.itemClicked.connect(
|
||||
# self.world.interface_manager.onTreeItemClicked)
|
||||
# else:
|
||||
# print("× 在树形控件中没有找到对应项")
|
||||
# break
|
||||
#
|
||||
# if not foundItem:
|
||||
# print("× 没有找到场景节点或对应的树形项")
|
||||
# else:
|
||||
# print("× 树形控件不存在")
|
||||
# 在树形控件中查找并选中对应的项
|
||||
if self.world.interface_manager.treeWidget:
|
||||
#print("查找树形控件中的对应项...")
|
||||
root = self.world.interface_manager.treeWidget.invisibleRootItem()
|
||||
foundItem = None
|
||||
|
||||
for i in range(root.childCount()):
|
||||
sceneItem = root.child(i)
|
||||
if sceneItem.text(0) == "场景":
|
||||
#print(f"在场景节点下查找...")
|
||||
foundItem = self.world.interface_manager.findTreeItem(selectedModel, sceneItem)
|
||||
if foundItem:
|
||||
print(f"✓ 在树形控件中找到对应项: {foundItem.text(0)}")
|
||||
try:
|
||||
self.world.interface_manager.treeWidget.itemClicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
self.world.interface_manager.treeWidget.setCurrentItem(foundItem)
|
||||
|
||||
self.world.interface_manager.treeWidget.itemClicked.connect(
|
||||
self.world.interface_manager.onTreeItemClicked)
|
||||
else:
|
||||
print("× 在树形控件中没有找到对应项")
|
||||
break
|
||||
|
||||
if not foundItem:
|
||||
print("× 没有找到场景节点或对应的树形项")
|
||||
else:
|
||||
print("× 树形控件不存在")
|
||||
else:
|
||||
print("× 没有找到可选择的模型节点")
|
||||
self.world.selection.updateSelection(None)
|
||||
|
||||
@ -1021,7 +1021,7 @@ class SelectionSystem:
|
||||
)
|
||||
|
||||
mat.setBaseColor(adjusted_color)
|
||||
mat.setEmission(Vec4(1, 1, 1, 1.0)) # 自发光
|
||||
#mat.setEmission(Vec4(1, 1, 1, 1.0)) # 自发光
|
||||
|
||||
# 应用材质
|
||||
handle_node.setMaterial(mat, 1)
|
||||
|
||||
@ -11,8 +11,8 @@ import os
|
||||
from PyQt5.QtCore import Qt
|
||||
from panda3d.core import (
|
||||
ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
|
||||
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere,
|
||||
BitMask32, TransparencyAttrib,LColor
|
||||
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere,
|
||||
BitMask32, TransparencyAttrib, LColor, TransformState
|
||||
)
|
||||
import json
|
||||
import aiohttp
|
||||
@ -141,11 +141,7 @@ class SceneManager:
|
||||
print("加载模型失败")
|
||||
return None
|
||||
|
||||
# 验证并修复模型变换矩阵(在任何操作之前)
|
||||
#
|
||||
self._validateAndFixAllTransforms(model)
|
||||
|
||||
self._fixModelStructure(model)
|
||||
|
||||
# 设置模型名称
|
||||
model_name = os.path.basename(filepath)
|
||||
@ -238,11 +234,11 @@ class SceneManager:
|
||||
print(f"导入模型失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def _fixModelStructure(self,model):
|
||||
def _fixModelStructure(self, model):
|
||||
"""修复模型结构"""
|
||||
try:
|
||||
from panda3d.core import CharacterNode,AnimBundleNode
|
||||
|
||||
character_nodes = model.findAllMatches("**/+CharacterNode")
|
||||
# 使用正确的方式查找动画相关节点
|
||||
character_nodes = model.findAllMatches("**/+Character")
|
||||
anim_bundle_nodes = model.findAllMatches("**/+AnimBundleNode")
|
||||
|
||||
if character_nodes.getNumPaths() > 0 or anim_bundle_nodes.getNumPaths() > 0:
|
||||
@ -252,65 +248,103 @@ class SceneManager:
|
||||
if anim_bundle_nodes.getNumPaths() > 0:
|
||||
print(f"AnimBundleNode数量: {anim_bundle_nodes.getNumPaths()}")
|
||||
|
||||
model.setTag("fixed_structure","true")
|
||||
model.setTag("fixed_structure", "true")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"修复模型结构时出错{e}")
|
||||
print(f"修复模型结构时出错: {e}")
|
||||
return False
|
||||
|
||||
def _validateAndFixAllTransforms(self, model):
|
||||
"""验证并修复所有节点的变换矩阵"""
|
||||
"""递归验证并修复模型中所有节点的变换矩阵"""
|
||||
try:
|
||||
def fix_node_transform(node_path, depth=0):
|
||||
indent = " " * depth
|
||||
try:
|
||||
# 检查节点的变换矩阵是否有效
|
||||
transform = node_path.getTransform()
|
||||
if not transform.isInvalid():
|
||||
# 检查是否有NaN或无穷大值
|
||||
pos = node_path.getPos()
|
||||
hpr = node_path.getHpr()
|
||||
scale = node_path.getScale()
|
||||
fixed_count = 0
|
||||
|
||||
# 检查位置
|
||||
if pos.x != pos.x or pos.y != pos.y or pos.z != pos.z: # NaN检查
|
||||
print(f"{indent}修复NaN位置: {node_path.getName()}")
|
||||
node_path.setPos(0, 0, 0)
|
||||
# 先处理根节点
|
||||
if not self._validateAndFixTransform(model):
|
||||
fixed_count += 1
|
||||
|
||||
# 检查旋转
|
||||
if hpr.x != hpr.x or hpr.y != hpr.y or hpr.z != hpr.z: # NaN检查
|
||||
print(f"{indent}修复NaN旋转: {node_path.getName()}")
|
||||
node_path.setHpr(0, 0, 0)
|
||||
# 递归处理所有子节点
|
||||
def process_children(node, depth=0):
|
||||
nonlocal fixed_count
|
||||
for i in range(node.getNumChildren()):
|
||||
try:
|
||||
child = node.getChild(i)
|
||||
if not self._validateAndFixTransform(child):
|
||||
fixed_count += 1
|
||||
# 递归处理孙节点
|
||||
process_children(child, depth + 1)
|
||||
except Exception as e:
|
||||
print(f"处理子节点时出错 (深度 {depth}): {e}")
|
||||
continue
|
||||
|
||||
# 检查缩放
|
||||
if scale.x != scale.x or scale.y != scale.y or scale.z != scale.z: # NaN检查
|
||||
print(f"{indent}修复NaN缩放: {node_path.getName()}")
|
||||
node_path.setScale(1, 1, 1)
|
||||
process_children(model)
|
||||
|
||||
# 检查过大值
|
||||
if abs(pos.x) > 1e10 or abs(pos.y) > 1e10 or abs(pos.z) > 1e10:
|
||||
print(f"{indent}修复过大位置值: {node_path.getName()}")
|
||||
node_path.setPos(0, 0, 0)
|
||||
if fixed_count > 0:
|
||||
print(f"共修复了 {fixed_count} 个节点的变换")
|
||||
|
||||
else:
|
||||
print(f"{indent}检测到无效变换矩阵: {node_path.getName()}")
|
||||
node_path.setPos(0, 0, 0)
|
||||
node_path.setHpr(0, 0, 0)
|
||||
node_path.setScale(1, 1, 1)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"验证所有变换时出错: {e}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"{indent}修复节点变换时出错 {node_path.getName()}: {e}")
|
||||
def _validateAndFixTransform(self, node_path):
|
||||
"""验证并修复单个节点的变换矩阵"""
|
||||
try:
|
||||
node_name = node_path.getName()
|
||||
|
||||
# 递归处理子节点
|
||||
for child in node_path.getChildren():
|
||||
fix_node_transform(child, depth + 1)
|
||||
# 获取当前变换状态
|
||||
original_pos = node_path.getPos()
|
||||
original_hpr = node_path.getHpr()
|
||||
original_scale = node_path.getScale()
|
||||
|
||||
# 从模型根节点开始修复
|
||||
fix_node_transform(model)
|
||||
print(f"✓ 完成模型 {model.getName()} 的变换验证和修复")
|
||||
# 检查位置是否包含无效值
|
||||
if not original_pos.isFinite():
|
||||
print(f"警告: 节点 {node_name} 位置包含无效值 {original_pos},重置为 (0,0,0)")
|
||||
node_path.setPos(0, 0, 0)
|
||||
return False
|
||||
|
||||
# 检查旋转是否包含无效值
|
||||
if not original_hpr.isFinite():
|
||||
print(f"警告: 节点 {node_name} 旋转包含无效值 {original_hpr},重置为 (0,0,0)")
|
||||
node_path.setHpr(0, 0, 0)
|
||||
return False
|
||||
|
||||
# 检查缩放是否包含无效值或为零
|
||||
if not original_scale.isFinite():
|
||||
print(f"警告: 节点 {node_name} 缩放包含无效值 {original_scale},重置为 (1,1,1)")
|
||||
node_path.setScale(1, 1, 1)
|
||||
return False
|
||||
|
||||
# 检查缩放是否为零或接近零
|
||||
min_scale = 1e-10
|
||||
if (abs(original_scale.x) < min_scale or
|
||||
abs(original_scale.y) < min_scale or
|
||||
abs(original_scale.z) < min_scale):
|
||||
print(f"警告: 节点 {node_name} 缩放接近零 {original_scale},重置为 (1,1,1)")
|
||||
node_path.setScale(1, 1, 1)
|
||||
return False
|
||||
|
||||
# 检查缩放是否过大(防止异常大的缩放)
|
||||
max_scale = 1000000 # 100万倍作为上限
|
||||
if (abs(original_scale.x) > max_scale or
|
||||
abs(original_scale.y) > max_scale or
|
||||
abs(original_scale.z) > max_scale):
|
||||
print(f"警告: 节点 {node_name} 缩放过异常 {original_scale},重置为 (1,1,1)")
|
||||
node_path.setScale(1, 1, 1)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"验证和修复模型变换时出错: {e}")
|
||||
print(f"验证/修复节点 {node_path.getName()} 变换时出错: {e}")
|
||||
# 只在出现严重错误时才重置变换
|
||||
try:
|
||||
node_path.setPos(0, 0, 0)
|
||||
node_path.setHpr(0, 0, 0)
|
||||
node_path.setScale(1, 1, 1)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def _applyModelScale(self, model, scale_factor):
|
||||
"""应用模型特定缩放
|
||||
@ -523,6 +557,18 @@ class SceneManager:
|
||||
# 应用缩放
|
||||
model.setScale(scale_factor)
|
||||
|
||||
# 应用缩放(添加异常处理)
|
||||
try:
|
||||
model.setScale(scale_factor)
|
||||
except Exception as e:
|
||||
print(f"直接设置缩放失败: {e},尝试使用变换状态")
|
||||
try:
|
||||
model.setTransform(TransformState.makeScale(scale_factor))
|
||||
except Exception as e2:
|
||||
print(f"使用变换状态设置缩放也失败: {e2}")
|
||||
|
||||
# 应用缩放后验证变换
|
||||
self._validateAndFixTransform(model)
|
||||
# 重新调整位置(因为缩放会影响边界)
|
||||
if original_bounds and not original_bounds.isEmpty():
|
||||
new_bounds = model.getBounds()
|
||||
@ -1504,7 +1550,7 @@ class SceneManager:
|
||||
if nodePath.hasTag("is_model_root"):
|
||||
print(f"J{indent}处理模型节点{nodePath.getName()}")
|
||||
|
||||
self._validateAndFixAllTransforms(nodePath)
|
||||
#self._validateAndFixAllTransforms(nodePath)
|
||||
|
||||
self._fixModelStructure(nodePath)
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@ class InterfaceManager:
|
||||
"""设置树形控件引用并更新场景树"""
|
||||
self.treeWidget = treeWidget
|
||||
|
||||
|
||||
# 添加右键菜单
|
||||
# self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
# self.treeWidget.customContextMenuRequested.connect(self.showTreeContextMenu)
|
||||
|
||||
@ -4756,12 +4756,12 @@ class PropertyPanelManager:
|
||||
if geom_node:
|
||||
geom_node_name = geom_node.getName()
|
||||
unique_name = f"{geom_node_name}({model_name})"
|
||||
print(f"材质 {i}: 使用几何节点名称 '{geom_node_name}'")
|
||||
#print(f"材质 {i}: 使用几何节点名称 '{geom_node_name}'")
|
||||
else:
|
||||
material_name = material.get_name() if hasattr(material,
|
||||
'get_name') and material.get_name() else f"材质{i + 1}"
|
||||
unique_name = f"{material_name}({model_name})"
|
||||
print(f"材质 {i}: 未找到几何节点,使用材质名称 '{material_name}'")
|
||||
#print(f"材质 {i}: 未找到几何节点,使用材质名称 '{material_name}'")
|
||||
|
||||
# 处理重复名称
|
||||
if unique_name in name_counter:
|
||||
@ -4800,7 +4800,7 @@ class PropertyPanelManager:
|
||||
# 基础颜色编辑
|
||||
base_color = self._getOrCreateMaterialBaseColor(material)
|
||||
if base_color is not None:
|
||||
print(f"材质基础颜色: {base_color}")
|
||||
#print(f"材质基础颜色: {base_color}")
|
||||
|
||||
# 基础颜色标题
|
||||
color_row = 2 if material_status != "标准PBR材质" else 1
|
||||
@ -5186,7 +5186,7 @@ class PropertyPanelManager:
|
||||
try:
|
||||
# 方法1: 尝试获取base_color属性
|
||||
if hasattr(material, 'base_color') and material.base_color is not None:
|
||||
print(f"✓ 找到base_color属性: {material.base_color}")
|
||||
#print(f"✓ 找到base_color属性: {material.base_color}")
|
||||
return material.base_color
|
||||
|
||||
# 方法2: 尝试调用get_base_color方法
|
||||
@ -5204,7 +5204,7 @@ class PropertyPanelManager:
|
||||
try:
|
||||
diffuse_color = material.getDiffuse()
|
||||
if diffuse_color is not None:
|
||||
print(f"✓ 从diffuse颜色获取: {diffuse_color}")
|
||||
#print(f"✓ 从diffuse颜色获取: {diffuse_color}")
|
||||
# 同时设置为base_color
|
||||
if hasattr(material, 'set_base_color'):
|
||||
material.set_base_color(diffuse_color)
|
||||
@ -6812,7 +6812,7 @@ class PropertyPanelManager:
|
||||
# print(f"找到匹配的几何节点: {geom_np.get_name()}")
|
||||
return geom_np
|
||||
|
||||
print("未找到匹配的几何节点")
|
||||
#print("未找到匹配的几何节点")
|
||||
return None
|
||||
|
||||
def _findSpecificGeomNodeForMaterial(self, target_material):
|
||||
@ -8097,7 +8097,7 @@ class PropertyPanelManager:
|
||||
format_info = self._getModelFormat(origin_model)
|
||||
processed = []
|
||||
|
||||
print(f"[动画分析] 格式: {format_info}, 原始动画名称: {anim_names}")
|
||||
#print(f"[动画分析] 格式: {format_info}, 原始动画名称: {anim_names}")
|
||||
|
||||
for name in anim_names:
|
||||
display_name = name
|
||||
@ -8131,7 +8131,7 @@ class PropertyPanelManager:
|
||||
display_name = name
|
||||
|
||||
processed.append((display_name, original_name))
|
||||
print(f"[动画分析] {original_name} → {display_name}")
|
||||
#print(f"[动画分析] {original_name} → {display_name}")
|
||||
|
||||
return processed
|
||||
|
||||
@ -8165,7 +8165,7 @@ class PropertyPanelManager:
|
||||
if frames > 1:
|
||||
valid_anims += 1
|
||||
total_frames += frames
|
||||
print(f"[动画分析] '{anim_name}': {frames} 帧")
|
||||
#print(f"[动画分析] '{anim_name}': {frames} 帧")
|
||||
else:
|
||||
print(f"[动画分析] '{anim_name}': 无有效帧数 ({frames})")
|
||||
except Exception as e:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user