1.修改保存层级数
This commit is contained in:
parent
7fd52d3458
commit
63801cfb0a
File diff suppressed because one or more lines are too long
@ -17,7 +17,6 @@ sys.path.insert(0, render_pipeline_file_path)
|
||||
icons_path = os.path.join(project_root, "icons")
|
||||
sys.path.insert(0, icons_path)
|
||||
|
||||
|
||||
# 现在可以导入并运行主程序
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
|
||||
@ -104,6 +104,9 @@ class TerrainManager:
|
||||
print("错误:无法生成有效的地形节点")
|
||||
return None
|
||||
|
||||
terrain_node.setTag("is_scene_element", "1")
|
||||
terrain_node.setTag("tree_item_type", "TERRAIN_NODE")
|
||||
|
||||
node_name = f"Terrain_{os.path.basename(heightmap_path)}_{len(self.terrains)}"
|
||||
terrain_node.setName(node_name)
|
||||
|
||||
@ -235,6 +238,9 @@ class TerrainManager:
|
||||
print("错误:无法生成有效的平面地形节点")
|
||||
return None
|
||||
|
||||
terrain_node.setTag("is_scene_element", "1")
|
||||
terrain_node.setTag("tree_item_type", "TERRAIN_NODE")
|
||||
|
||||
node_name = f"FlatTerrain_{len(self.terrains)}_{int(time.time() * 1000000) % 10000}"
|
||||
terrain_node.setName(node_name)
|
||||
|
||||
|
||||
@ -84,6 +84,8 @@ except ImportError:
|
||||
# 为GUI元素添加标识(效仿3D文本方法)
|
||||
image_node.setTag("gui_type", "3d_image")
|
||||
image_node.setTag("gui_id", f"3d_image_{len(self.gui_elements)}")
|
||||
image_node.setTag("is_scene_element", "1")
|
||||
image_node.setTag("tree_item_type", "GUI_3DIMAGE")
|
||||
if image_path:
|
||||
image_node.setTag("gui_image_path", image_path)
|
||||
image_node.setTag("is_gui_element", "1")
|
||||
@ -189,6 +191,7 @@ class GUIManager:
|
||||
button.setTag("gui_text", text)
|
||||
button.setTag("is_gui_element", "1")
|
||||
button.setTag("is_scene_element", "1") # 确保这个标签被设置
|
||||
button.setTag("tree_item_type", "GUI_BUTTON")
|
||||
button.setTag("saved_gui_type", "button") # 添加这个标签以确保兼容性
|
||||
button.setTag("gui_element_type","button")
|
||||
button.setTag("created_by_user", "1")
|
||||
@ -305,6 +308,7 @@ class GUIManager:
|
||||
label.setTag("gui_id", f"label_{len(self.gui_elements)}")
|
||||
label.setTag("gui_text", text)
|
||||
label.setTag("is_gui_element", "1")
|
||||
label.setTag("tree_item_type", "GUI_LABEL")
|
||||
label.setTag("is_scene_element", "1")
|
||||
label.setTag("created_by_user", "1")
|
||||
label.setTag("gui_parent_type", "gui" if parent_gui_node else "3d")
|
||||
@ -416,6 +420,7 @@ class GUIManager:
|
||||
entry.setTag("gui_id", f"entry_{len(self.gui_elements)}")
|
||||
entry.setTag("gui_placeholder", placeholder)
|
||||
entry.setTag("is_gui_element", "1")
|
||||
entry.setTag("tree_item_type", "GUI_ENTRY")
|
||||
entry.setTag("is_scene_element", "1")
|
||||
entry.setTag("created_by_user", "1")
|
||||
entry.setTag("gui_parent_type", "gui" if parent_gui_node else "3d")
|
||||
@ -549,6 +554,7 @@ class GUIManager:
|
||||
image_node.setTag("gui_text", f"2D图片_{len(self.gui_elements)}")
|
||||
image_node.setTag("is_gui_element", "1")
|
||||
image_node.setTag("is_scene_element", "1")
|
||||
image_node.setTag("tree_item_type", "GUI_IMAGE")
|
||||
image_node.setTag("created_by_user", "1")
|
||||
image_node.setTag("gui_parent_type", "gui" if parent_gui_node else "3d")
|
||||
image_node.setName(image_name)
|
||||
@ -700,6 +706,7 @@ class GUIManager:
|
||||
textNodePath.setTag("gui_text", text)
|
||||
textNodePath.setTag("is_gui_element", "1")
|
||||
textNodePath.setTag("is_scene_element", "1")
|
||||
textNodePath.setTag("tree_item_type", "GUI_3DTEXT")
|
||||
textNodePath.setTag("created_by_user", "1")
|
||||
|
||||
# 添加到GUI元素列表
|
||||
@ -836,6 +843,7 @@ class GUIManager:
|
||||
image_node.setTag("gui_image_path", image_path)
|
||||
image_node.setTag("is_gui_element", "1")
|
||||
image_node.setTag("is_scene_element", "1")
|
||||
image_node.setTag("tree_item_type", "GUI_3DIMAGE")
|
||||
image_node.setTag("created_by_user", "1")
|
||||
|
||||
# 添加到GUI元素列表
|
||||
@ -953,6 +961,7 @@ class GUIManager:
|
||||
video_screen.setTag("gui_text", f"视频屏幕_{len(self.gui_elements)}")
|
||||
video_screen.setTag("is_gui_element", "1")
|
||||
video_screen.setTag("is_scene_element", "1")
|
||||
video_screen.setTag("tree_item_type", "GUI_VIDEO_SCREEN")
|
||||
video_screen.setTag("created_by_user", "1")
|
||||
|
||||
# 设置视频路径标签
|
||||
@ -1473,6 +1482,7 @@ class GUIManager:
|
||||
video_screen.setTag("gui_text", f"2D视频屏幕_{len(self.gui_elements)}")
|
||||
video_screen.setTag("is_gui_element", "1")
|
||||
video_screen.setTag("is_scene_element", "1")
|
||||
video_screen.setTag("tree_item_type", "GUI_2D_VIDEO_SCREEN")
|
||||
video_screen.setTag("created_by_user", "1")
|
||||
|
||||
# 设置视频路径标签
|
||||
@ -1785,6 +1795,7 @@ class GUIManager:
|
||||
# 设置标签以便识别和管理
|
||||
sphere_np.setTag("gui_type", "spherical_video")
|
||||
sphere_np.setTag("is_gui_element", "1")
|
||||
sphere_np.setTag("tree_item_type", "GUI_SPHERICAL_VIDEO")
|
||||
sphere_np.setTag("video_path", video_path or "")
|
||||
sphere_np.setTag("original_radius", str(radius))
|
||||
|
||||
@ -1997,6 +2008,7 @@ class GUIManager:
|
||||
virtual_screen.setTag("gui_text", text)
|
||||
virtual_screen.setTag("is_gui_element", "1")
|
||||
virtual_screen.setTag("is_scene_element", "1")
|
||||
virtual_screen.setTag("tree_item_type", "GUI_VirtualScreen")
|
||||
virtual_screen.setTag("created_by_user", "1")
|
||||
|
||||
# 添加到GUI元素列表
|
||||
|
||||
@ -79,7 +79,7 @@ class ProjectManager:
|
||||
|
||||
# 自动保存初始场景
|
||||
scene_file = os.path.join(scenes_path, "scene.bam")
|
||||
if self.world.scene_manager.saveScene(scene_file):
|
||||
if self.world.scene_manager.saveScene(scene_file, project_path):
|
||||
# 更新配置文件中的场景路径
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, full_project_path)
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
@ -302,7 +302,7 @@ class ProjectManager:
|
||||
return False
|
||||
|
||||
# 保存场景
|
||||
if self.world.scene_manager.saveScene(scene_file):
|
||||
if self.world.scene_manager.saveScene(scene_file, project_path):
|
||||
# 更新项目配置文件
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if os.path.exists(config_file):
|
||||
|
||||
@ -169,6 +169,7 @@ class SceneManager:
|
||||
model.setTag("file", model_name)
|
||||
model.setTag("is_model_root", "1")
|
||||
model.setTag("is_scene_element", "1")
|
||||
model.setTag("tree_item_type", "IMPORTED_MODEL_NODE")
|
||||
|
||||
# 记录应用的处理选项
|
||||
if apply_unit_conversion:
|
||||
@ -724,7 +725,7 @@ class SceneManager:
|
||||
|
||||
# ==================== 场景保存和加载 ====================
|
||||
|
||||
def saveScene(self, filename):
|
||||
def saveScene(self, filename, project_path):
|
||||
"""保存场景到BAM文件 - 完整版,支持GUI元素"""
|
||||
try:
|
||||
print(f"\n=== 开始保存场景到: {filename} ===")
|
||||
@ -874,6 +875,7 @@ class SceneManager:
|
||||
self.world.render.ls()
|
||||
print("---------------------------------")
|
||||
|
||||
self.take_screenshot(project_path)
|
||||
# 保存场景
|
||||
success = self.world.render.writeBamFile(Filename.fromOsSpecific(filename))
|
||||
#success_2d = self.world.render2d.writeBamFile(Filename.fromOsSpecific(filename))
|
||||
@ -902,6 +904,51 @@ class SceneManager:
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def take_screenshot(self, projectpath):
|
||||
"""
|
||||
截图并保存到指定的完整路径
|
||||
|
||||
Args:
|
||||
full_path (str): 完整的文件保存路径,包括文件名和扩展名
|
||||
|
||||
Returns:
|
||||
bool: 截图是否成功
|
||||
"""
|
||||
try:
|
||||
from panda3d.core import Filename
|
||||
import os
|
||||
|
||||
print(f"\n=== 截图保存: {projectpath} ===")
|
||||
|
||||
# 确保目录存在
|
||||
directory = os.path.dirname(projectpath)
|
||||
if directory and not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
print(f"创建目录: {directory}")
|
||||
|
||||
# 规范化路径
|
||||
filename = os.path.basename(os.path.normpath(projectpath))
|
||||
filename = f'{filename}.png'
|
||||
print(f'project_path: {projectpath}')
|
||||
print(f'project_name: {filename}')
|
||||
full_path = os.path.normpath(os.path.join(projectpath, filename))
|
||||
p3d_filename = Filename.from_os_specific(full_path)
|
||||
# 使用 Panda3D 的截图功能
|
||||
success = self.world.win.saveScreenshot(p3d_filename)
|
||||
|
||||
if success:
|
||||
print(f"✅ 成功截图并保存到: {full_path}")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 截图保存失败: {full_path}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"保存截图时发生错误: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def loadScene(self, filename):
|
||||
"""从BAM文件加载场景 - 修复版"""
|
||||
try:
|
||||
@ -972,7 +1019,7 @@ class SceneManager:
|
||||
print("场景加载失败")
|
||||
return False
|
||||
|
||||
# tree_widget.create_model_items(scene)
|
||||
tree_widget.create_model_items(scene)
|
||||
# 遍历场景中的所有模型节点
|
||||
# 用于存储处理后的灯光节点,避免重复处理
|
||||
processed_lights = []
|
||||
@ -1226,7 +1273,7 @@ class SceneManager:
|
||||
scene.removeNode()
|
||||
|
||||
# 更新场景树
|
||||
self.updateSceneTree()
|
||||
# self.updateSceneTree()
|
||||
# self._get_tree_widget().create_model_items(scene)
|
||||
|
||||
print(f"加载完成,GUI元素数量: {len(self.world.gui_elements)}")
|
||||
@ -1835,6 +1882,7 @@ class SceneManager:
|
||||
# 设置节点属性和标签
|
||||
light_np.setTag("light_type", "spot_light")
|
||||
light_np.setTag("is_scene_element", "1")
|
||||
light_np.setTag("tree_item_type", "LIGHT_NODE")
|
||||
light_np.setTag("light_energy", str(light.energy))
|
||||
light_np.setTag("created_by_user", "1")
|
||||
|
||||
@ -1941,6 +1989,7 @@ class SceneManager:
|
||||
# 设置节点属性和标签
|
||||
light_np.setTag("light_type", "point_light")
|
||||
light_np.setTag("is_scene_element", "1")
|
||||
light_np.setTag("tree_item_type", "LIGHT_NODE")
|
||||
light_np.setTag("light_energy", str(light.energy))
|
||||
light_np.setTag("created_by_user", "1")
|
||||
|
||||
@ -2555,6 +2604,7 @@ except Exception as e:
|
||||
|
||||
# 添加标签以便场景识别和保存
|
||||
tileset_node.setTag("is_scene_element", "1")
|
||||
tileset_node.setTag("tree_item_type", "CESIUM_TILESET_NODE")
|
||||
tileset_node.setTag("element_type", "cesium_tileset")
|
||||
tileset_node.setTag("tileset_url", tileset_url)
|
||||
# 使用唯一名称作为文件标识,代替索引
|
||||
|
||||
1036
ui/main_window.py
1036
ui/main_window.py
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ from typing import Hashable
|
||||
from PyQt5.QtGui import QColor
|
||||
from PyQt5.QtWidgets import (QLabel, QLineEdit, QDoubleSpinBox, QPushButton,
|
||||
QTreeWidget, QTreeWidgetItem, QMenu, QCheckBox, QComboBox, QHBoxLayout, QWidget,
|
||||
QVBoxLayout, QGroupBox, QGridLayout, QSpinBox, QFileDialog)
|
||||
QVBoxLayout, QGroupBox, QGridLayout, QSpinBox, QFileDialog, QMessageBox)
|
||||
from PyQt5.QtCore import Qt
|
||||
from deploy_libs.unicodedata import normalize
|
||||
from direct.actor.Actor import Actor
|
||||
@ -235,23 +235,23 @@ class PropertyPanelManager:
|
||||
#材质属性
|
||||
self._updateTerrainMaterialPanel(terrain_node,terrain_info)
|
||||
|
||||
#删除按钮
|
||||
delete_btn = QPushButton("删除地形")
|
||||
delete_btn.setStyleSheet("""
|
||||
QPushButton{
|
||||
background-color:#ff4444;
|
||||
color:white;
|
||||
border:none;
|
||||
padding:8px;
|
||||
border-radius:4px;
|
||||
margin-top:10px
|
||||
}
|
||||
QPushButton:hover{
|
||||
background-color:#ff6666;
|
||||
}
|
||||
""")
|
||||
delete_btn.clicked.connect(lambda:self._deleteTerrain(terrain_info,item))
|
||||
self._propertyLayout.addWidget(delete_btn)
|
||||
# #删除按钮
|
||||
# delete_btn = QPushButton("删除地形")
|
||||
# delete_btn.setStyleSheet("""
|
||||
# QPushButton{
|
||||
# background-color:#ff4444;
|
||||
# color:white;
|
||||
# border:none;
|
||||
# padding:8px;
|
||||
# border-radius:4px;
|
||||
# margin-top:10px
|
||||
# }
|
||||
# QPushButton:hover{
|
||||
# background-color:#ff6666;
|
||||
# }
|
||||
# """)
|
||||
# delete_btn.clicked.connect(lambda:self._deleteTerrain(terrain_info,item))
|
||||
# self._propertyLayout.addWidget(delete_btn)
|
||||
except Exception as e:
|
||||
print(f"显示地形属性时出错: {e}")
|
||||
import traceback
|
||||
@ -909,23 +909,23 @@ class PropertyPanelManager:
|
||||
scale_group.setLayout(scale_layout)
|
||||
self._propertyLayout.addWidget(scale_group)
|
||||
|
||||
# 删除按钮
|
||||
delete_btn = QPushButton("删除 Tileset")
|
||||
delete_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #ff6666;
|
||||
}
|
||||
""")
|
||||
delete_btn.clicked.connect(lambda: self._deleteCesiumTileset(nodePath, item))
|
||||
self._propertyLayout.addWidget(delete_btn)
|
||||
# # 删除按钮
|
||||
# delete_btn = QPushButton("删除 Tileset")
|
||||
# delete_btn.setStyleSheet("""
|
||||
# QPushButton {
|
||||
# background-color: #ff4444;
|
||||
# color: white;
|
||||
# border: none;
|
||||
# padding: 8px;
|
||||
# border-radius: 4px;
|
||||
# margin-top: 10px;
|
||||
# }
|
||||
# QPushButton:hover {
|
||||
# background-color: #ff6666;
|
||||
# }
|
||||
# """)
|
||||
# delete_btn.clicked.connect(lambda: self._deleteCesiumTileset(nodePath, item))
|
||||
# self._propertyLayout.addWidget(delete_btn)
|
||||
|
||||
# 添加弹性空间
|
||||
self._propertyLayout.addStretch()
|
||||
@ -1280,8 +1280,6 @@ class PropertyPanelManager:
|
||||
model.setScale(current_scale.getX(), current_scale.getY(), value)
|
||||
self.refreshModelValues(model)
|
||||
|
||||
|
||||
|
||||
def updateGUIPropertyPanel(self, gui_element,item):
|
||||
"""更新GUI元素属性面板"""
|
||||
self.clearPropertyPanel()
|
||||
|
||||
243
ui/widgets.py
243
ui/widgets.py
@ -18,7 +18,7 @@ from PyQt5.QtCore import Qt, QUrl, QMimeData
|
||||
from PyQt5.QtGui import QDrag, QPainter, QPixmap, QPen, QBrush
|
||||
from PyQt5.sip import wrapinstance
|
||||
from direct.showbase.ShowBaseGlobal import aspect2d
|
||||
from panda3d.core import ModelRoot, NodePath
|
||||
from panda3d.core import ModelRoot, NodePath, CollisionNode
|
||||
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from scene import util
|
||||
@ -30,7 +30,68 @@ class NewProjectDialog(QDialog):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("新建项目")
|
||||
self.setMinimumWidth(500)
|
||||
|
||||
|
||||
# 设置对话框样式与主窗口保持一致
|
||||
self.setStyleSheet("""
|
||||
QDialog {
|
||||
background-color: #252538;
|
||||
color: #e0e0ff;
|
||||
}
|
||||
QGroupBox {
|
||||
background-color: #2d2d44;
|
||||
border: 1px solid #3a3a4a;
|
||||
border-radius: 6px;
|
||||
margin-top: 1ex; /* 保持这个设置 */
|
||||
color: #e0e0ff;
|
||||
font-weight: 500;
|
||||
padding-top: 10px; /* 增加顶部内边距,为标题留出空间 */
|
||||
}
|
||||
QGroupBox::title {
|
||||
subline-offset: -2px;
|
||||
padding: 0 8px;
|
||||
color: #c0c0e0;
|
||||
font-weight: 500;
|
||||
}
|
||||
QLineEdit {
|
||||
background-color: #2d2d44;
|
||||
color: #e0e0ff;
|
||||
border: 1px solid #3a3a4a;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
QLineEdit:disabled {
|
||||
background-color: #1e1e2e;
|
||||
color: #8888aa;
|
||||
}
|
||||
QPushButton {
|
||||
background-color: #8b5cf6;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #7c3aed;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #6d28d9;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #4c4c6e;
|
||||
color: #8888aa;
|
||||
}
|
||||
QLabel {
|
||||
color: #e0e0ff;
|
||||
}
|
||||
QLabel:disabled {
|
||||
color: #8888aa;
|
||||
}
|
||||
QDialogButtonBox QPushButton {
|
||||
min-width: 80px;
|
||||
}
|
||||
""")
|
||||
|
||||
# 创建布局
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
@ -1251,12 +1312,60 @@ class CustomConsoleDockWidget(QWidget):
|
||||
self.autoScrollBtn = QPushButton("自动滚动")
|
||||
self.autoScrollBtn.setCheckable(True)
|
||||
self.autoScrollBtn.setChecked(True)
|
||||
self.autoScrollBtn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #2d2d44;
|
||||
color: #e0e0ff;
|
||||
border: 1px solid #3a3a4a;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:checked {
|
||||
background-color: #8b5cf6;
|
||||
color: white;
|
||||
border: 1px solid #7c3aed;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #3a3a4a;
|
||||
}
|
||||
QPushButton:checked:hover {
|
||||
background-color: #7c3aed;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #6d28d9;
|
||||
}
|
||||
""")
|
||||
toolbar.addWidget(self.autoScrollBtn)
|
||||
|
||||
# 时间戳开关
|
||||
self.timestampBtn = QPushButton("显示时间")
|
||||
self.timestampBtn.setCheckable(True)
|
||||
self.timestampBtn.setChecked(True)
|
||||
self.timestampBtn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #2d2d44;
|
||||
color: #e0e0ff;
|
||||
border: 1px solid #3a3a4a;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:checked {
|
||||
background-color: #8b5cf6;
|
||||
color: white;
|
||||
border: 1px solid #7c3aed;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #3a3a4a;
|
||||
}
|
||||
QPushButton:checked:hover {
|
||||
background-color: #7c3aed;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #6d28d9;
|
||||
}
|
||||
""")
|
||||
toolbar.addWidget(self.timestampBtn)
|
||||
|
||||
toolbar.addStretch()
|
||||
@ -1419,34 +1528,54 @@ class CustomTreeWidget(QTreeWidget):
|
||||
|
||||
self.original_scales={}
|
||||
|
||||
self.setStyleSheet("""
|
||||
/* 设置折叠状态下,带子节点的箭头颜色 */
|
||||
QTreeWidget::branch:has-children:!open {
|
||||
color: #8b5cf6; /* 紫色 */
|
||||
}
|
||||
|
||||
/* 设置展开状态下,带子节点的箭头颜色 */
|
||||
QTreeWidget::branch:has-children:open {
|
||||
color: #9ca3af; /* 灰色,提供状态变化反馈 */
|
||||
}
|
||||
|
||||
/* 鼠标悬停在任意箭头上时,颜色变亮 */
|
||||
QTreeWidget::branch:hover {
|
||||
color: #a78bfa; /* 亮紫色 */
|
||||
}
|
||||
""")
|
||||
|
||||
def initData(self):
|
||||
"""初始化变量"""
|
||||
# 定义2D GUI元素类型
|
||||
self.gui_2d_types = {
|
||||
"GUI_BUTTON", # DirectButton
|
||||
"GUI_LABEL", # DirectLabel
|
||||
"GUI_ENTRY", # DirectEntry
|
||||
"GUI_IMAGE",
|
||||
"GUI_BUTTON", # GUI 按钮
|
||||
"GUI_LABEL", # GUI 标签
|
||||
"GUI_ENTRY", # GUI 输入框
|
||||
"GUI_IMAGE", # GUI 图片
|
||||
"GUI_2D_VIDEO_SCREEN", # GUI 2D视频
|
||||
"GUI_SPHERICAL_VIDEO", # GUI 3D球形视频
|
||||
"GUI_NODE" # 其他2D GUI容器
|
||||
}
|
||||
|
||||
# 定义3D GUI元素类型
|
||||
self.gui_3d_types = {
|
||||
"GUI_3DTEXT", # 3D TextNode
|
||||
"GUI_3DIMAGE",
|
||||
"GUI_VIRTUAL_SCREEN" # Virtual Screen
|
||||
"GUI_3DTEXT", # 3D 文本节点
|
||||
"GUI_3DIMAGE", # 3D 图片节点
|
||||
"GUI_VIRTUAL_SCREEN", # 3D视频
|
||||
"GUI_VirtualScreen" # 3D虚拟视频
|
||||
}
|
||||
|
||||
# 定义3D场景节点类型(可以接受3D GUI元素和其他3D场景元素)
|
||||
self.scene_3d_types = {
|
||||
"SCENE_ROOT",
|
||||
"SCENE_NODE",
|
||||
"LIGHT_NODE",
|
||||
"LIGHT_NODE", # 灯节点
|
||||
"CAMERA_NODE",
|
||||
"IMPORTED_MODEL_NODE",
|
||||
"IMPORTED_MODEL_NODE", # 导入模型节点
|
||||
"MODEL_NODE",
|
||||
"TERRAIN_NODE",
|
||||
"CESIUM_TILESET_NODE"
|
||||
"TERRAIN_NODE", # 地形节点
|
||||
"CESIUM_TILESET_NODE" # 3D Tileset
|
||||
}
|
||||
|
||||
# 这是一个最佳实践,它让代码的意图变得非常清晰。
|
||||
@ -2192,53 +2321,60 @@ class CustomTreeWidget(QTreeWidget):
|
||||
return top_item
|
||||
return None
|
||||
|
||||
def create_model_items(self, model):
|
||||
def create_model_items(self, model: NodePath):
|
||||
"""
|
||||
【此函数保持不变】
|
||||
创建模型项。
|
||||
只寻找模型下一层带有 'is_scene_element' 标签的子节点作为分支的根,
|
||||
然后完整地展示这些分支。
|
||||
"""
|
||||
if not model:
|
||||
print("传入的参数model为空")
|
||||
return
|
||||
# 创建根节点项
|
||||
# root_item = QTreeWidgetItem(self)
|
||||
# root_item.setText(0, model.getName() or "Unnamed Node")
|
||||
# root_item.setText(1, model.node().getTypeName())
|
||||
# root_item.setIcon(0, self.item_icons.get('model', self.item_icons['default']))
|
||||
|
||||
# 存储NodePath引用以便后续操作
|
||||
# root_item.setData(0, Qt.UserRole, model)
|
||||
# 找到场景树的根节点,我们将把模型节点添加到这里
|
||||
root_item = self._findSceneRoot()
|
||||
if not root_item:
|
||||
print("错误:未能找到场景根节点项")
|
||||
return
|
||||
|
||||
# 递归添加子节点
|
||||
self._add_children_recursive(root_item, model)
|
||||
# 1. 在模型的第一层子节点中进行筛选
|
||||
for child_node in model.getChildren():
|
||||
if child_node.hasTag("is_scene_element"):
|
||||
print(f"找到带标签的根节点:{child_node.getName()}")
|
||||
|
||||
return root_item
|
||||
# 为这个带标签的节点创建一个树项
|
||||
child_item = QTreeWidgetItem(root_item)
|
||||
child_item.setText(0, child_node.getName() or "Unnamed Tagged Node")
|
||||
child_item.setData(0, Qt.UserRole, child_node)
|
||||
child_item.setData(0, Qt.UserRole + 1, child_node.getTag("tree_item_type"))
|
||||
# self._add_node_info(child_item, child_node) # 可选信息
|
||||
|
||||
def _add_children_recursive(self, parent_item, node_path: NodePath):
|
||||
"""递归添加子节点到树项"""
|
||||
print(f'开始递归添加子节点')
|
||||
# 获取所有子节点
|
||||
children = node_path.getChildren()
|
||||
# 2. 对这个节点的所有后代进行“无条件”递归添加 (但会跳过碰撞体)
|
||||
self._add_all_children_unconditionally(child_item, child_node)
|
||||
|
||||
for i in range(children.getNumPaths()):
|
||||
child_node: NodePath = children.getPath(i)
|
||||
def _add_all_children_unconditionally(self, parent_item: QTreeWidgetItem, node_path: NodePath):
|
||||
"""
|
||||
【此函数已更新】
|
||||
无条件地、递归地添加一个节点下的所有子节点,但会跳过碰撞节点。
|
||||
"""
|
||||
for child_node in node_path.getChildren():
|
||||
|
||||
# 过滤条件
|
||||
if not child_node.hasTag("is_scene_element"):
|
||||
print(f"不存在------------------------{child_node.hasTag('is_scene_element')}")
|
||||
continue
|
||||
# 新增:检查节点是否为碰撞节点
|
||||
if isinstance(child_node.node(), CollisionNode):
|
||||
# print(f"跳过碰撞节点: {child_node.getName()}") # 用于调试
|
||||
continue # 如果是,则跳过此节点及其所有子节点
|
||||
|
||||
print(f"存在------------------------{child_node.getName()}")
|
||||
# 创建子项
|
||||
child_item = QTreeWidgetItem(parent_item)
|
||||
child_item.setText(0, child_node.getName() or f"Child_{i}")
|
||||
|
||||
# 存储NodePath引用
|
||||
child_item.setText(0, child_node.getName() or "Unnamed Child")
|
||||
child_item.setData(0, Qt.UserRole, child_node)
|
||||
child_item.setData(0, Qt.UserRole + 1, child_node.getTag("tree_item_type"))
|
||||
# self._add_node_info(child_item, child_node) # 可选信息
|
||||
|
||||
# 添加额外信息(可选)
|
||||
# self._add_node_info(child_item, child_node)
|
||||
|
||||
# 递归处理子节点的子节点
|
||||
if child_node.getNumChildren() > 0:
|
||||
self._add_children_recursive(child_item, child_node)
|
||||
# 继续无条件地递归
|
||||
if not child_node.is_empty():
|
||||
self._add_all_children_unconditionally(child_item, child_node)
|
||||
|
||||
# ==================== 辅助方法 ====================
|
||||
def _findSceneRoot(self):
|
||||
@ -2269,6 +2405,17 @@ class CustomTreeWidget(QTreeWidget):
|
||||
|
||||
def add_node_to_tree_widget(self, node, parent_item, node_type):
|
||||
"""将node元素添加到树形控件"""
|
||||
if hasattr(node, 'getTag'):
|
||||
if node.hasTag('tree_item_type'):
|
||||
print(f"node0: {node.getName()},{node.getTag('tree_item_type')}")
|
||||
tree_type = node.getTag('tree_item_type')
|
||||
else:
|
||||
node.setTag('tree_item_type', node_type)
|
||||
else:
|
||||
print(f"node2: {node.getName()},{node_type}")
|
||||
tree_type = node_type
|
||||
|
||||
|
||||
# BLACK_LIST 和依赖项导入保持不变
|
||||
BLACK_LIST = {'', '**', 'temp', 'collision'}
|
||||
from panda3d.core import CollisionNode, ModelRoot
|
||||
@ -2283,7 +2430,7 @@ class CustomTreeWidget(QTreeWidget):
|
||||
|
||||
nodeItem = QTreeWidgetItem(parentItem, [node.getName()])
|
||||
nodeItem.setData(0, Qt.UserRole, node)
|
||||
nodeItem.setData(0, Qt.UserRole + 1, node_type)
|
||||
nodeItem.setData(0, Qt.UserRole + 1, tree_type)
|
||||
|
||||
for child in node.getChildren():
|
||||
# 递归调用,但我们只关心顶级的nodeItem
|
||||
@ -2301,7 +2448,7 @@ class CustomTreeWidget(QTreeWidget):
|
||||
node_name = ""
|
||||
|
||||
try:
|
||||
if node_type == "IMPORTED_MODEL_NODE":
|
||||
if tree_type == "IMPORTED_MODEL_NODE":
|
||||
# getTag('file') 可能是你自己设置的tag,这里假设它存在
|
||||
node_name = node.getTag("file") if hasattr(node, 'getTag') and node.hasTag("file") else node.getName()
|
||||
|
||||
@ -2312,7 +2459,7 @@ class CustomTreeWidget(QTreeWidget):
|
||||
node_name = node.getName() if hasattr(node, 'getName') else "node"
|
||||
new_qt_item = QTreeWidgetItem(parent_item, [node_name])
|
||||
new_qt_item.setData(0, Qt.UserRole, node)
|
||||
new_qt_item.setData(0, Qt.UserRole + 1, node_type)
|
||||
new_qt_item.setData(0, Qt.UserRole + 1, tree_type)
|
||||
|
||||
# 确保 new_qt_item 成功创建后再继续操作
|
||||
if new_qt_item:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user