2dGUI场景保存,3D模型,(地形,信息面板除外)
This commit is contained in:
parent
7fd52d3458
commit
fc7f0d55f3
@ -160,8 +160,8 @@ class QPanda3DWidget(QWidget):
|
||||
def resizeEvent(self, evt):
|
||||
width = evt.size().width()
|
||||
height = evt.size().height()
|
||||
print(f"width:{width}")
|
||||
print(f"height:{height}")
|
||||
#print(f"width:{width}")
|
||||
#print(f"height:{height}")
|
||||
|
||||
from Panda3DWorld import resize_buffer
|
||||
#resize_buffer(width, height)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1079,6 +1079,135 @@ class InfoPanelManager(DirectObject):
|
||||
property_panel_instance.createHTTPInfoPanel = types.MethodType(createHTTPInfoPanel, property_panel_instance)
|
||||
property_panel_instance.updateHTTPInfoPanel = types.MethodType(updateHTTPInfoPanel, property_panel_instance)
|
||||
|
||||
def serializePanelData(self, panel_id):
|
||||
"""序列化面板数据用于保存"""
|
||||
if panel_id not in self.panels:
|
||||
return None
|
||||
|
||||
panel_data = self.panels[panel_id]
|
||||
props = panel_data['properties']
|
||||
|
||||
# 获取面板类型
|
||||
panel_type = "2d"
|
||||
if panel_data['node'].hasTag("gui_type"):
|
||||
gui_type = panel_data['node'].getTag("gui_type")
|
||||
if "3d" in gui_type.lower():
|
||||
panel_type = "3d"
|
||||
|
||||
# 构建序列化数据
|
||||
serialized_data = {
|
||||
'panel_id': panel_id,
|
||||
'panel_type': panel_type,
|
||||
'position': props.get('position', (0, 0) if panel_type == "2d" else (0, 0, 0)),
|
||||
'size': props.get('size', (1.0, 0.6)),
|
||||
'bg_color': props.get('bg_color', (0.15, 0.15, 0.15, 0.9)),
|
||||
'border_color': props.get('border_color', (0.3, 0.3, 0.3, 1.0)),
|
||||
'title_color': props.get('title_color', (1.0, 1.0, 1.0, 1.0)),
|
||||
'content_color': props.get('content_color', (0.9, 0.9, 0.9, 1.0)),
|
||||
'title': panel_data['title_label'].getText() if 'title_label' in panel_data else "信息面板",
|
||||
'content': panel_data[
|
||||
'content_label'].getText() if 'content_label' in panel_data else "" if 'content_node' not in panel_data else
|
||||
panel_data['content_node'].getText(),
|
||||
'font_path': props.get('font', None),
|
||||
'bg_image': props.get('bg_image', None),
|
||||
'visible': not panel_data['node'].isHidden()
|
||||
}
|
||||
|
||||
# 添加HTTP面板特有数据
|
||||
if panel_id in self.data_sources and 'http_info' in self.data_sources[panel_id]:
|
||||
serialized_data['http_info'] = self.data_sources[panel_id]['http_info']
|
||||
|
||||
return serialized_data
|
||||
|
||||
def getAllPanelData(self):
|
||||
"""获取所有面板的序列化数据"""
|
||||
panel_data_list = []
|
||||
for panel_id in self.panels:
|
||||
data = self.serializePanelData(panel_id)
|
||||
if data:
|
||||
panel_data_list.append(data)
|
||||
return panel_data_list
|
||||
|
||||
def recreatePanelFromData(self, panel_data):
|
||||
"""从序列化数据重新创建面板"""
|
||||
try:
|
||||
panel_id = panel_data['panel_id']
|
||||
panel_type = panel_data['panel_type']
|
||||
position = panel_data['position']
|
||||
size = panel_data['size']
|
||||
|
||||
# 重建面板
|
||||
if panel_type == "3d":
|
||||
panel_node = self.create3DInfoPanel(
|
||||
panel_id=panel_id,
|
||||
position=position,
|
||||
size=size,
|
||||
bg_color=panel_data.get('bg_color', (0.15, 0.15, 0.15, 0.9)),
|
||||
border_color=panel_data.get('border_color', (0.3, 0.3, 0.3, 1.0)),
|
||||
title_color=panel_data.get('title_color', (1.0, 1.0, 1.0, 1.0)),
|
||||
content_color=panel_data.get('content_color', (0.9, 0.9, 0.9, 1.0)),
|
||||
visible=panel_data.get('visible', True),
|
||||
font=panel_data.get('font_path', None),
|
||||
bg_image=panel_data.get('bg_image', None)
|
||||
)
|
||||
|
||||
# 更新内容
|
||||
self.update3DPanelContent(
|
||||
panel_id,
|
||||
title=panel_data.get('title', '信息面板'),
|
||||
content=panel_data.get('content', '')
|
||||
)
|
||||
else:
|
||||
panel_node = self.createInfoPanel(
|
||||
panel_id=panel_id,
|
||||
position=(position[0], position[1]) if len(position) >= 2 else (0, 0),
|
||||
size=size,
|
||||
bg_color=panel_data.get('bg_color', (0.15, 0.15, 0.15, 0.9)),
|
||||
border_color=panel_data.get('border_color', (0.3, 0.3, 0.3, 1.0)),
|
||||
title_color=panel_data.get('title_color', (1.0, 1.0, 1.0, 1.0)),
|
||||
content_color=panel_data.get('content_color', (0.9, 0.9, 0.9, 1.0)),
|
||||
visible=panel_data.get('visible', True),
|
||||
font=panel_data.get('font_path', None),
|
||||
bg_image=panel_data.get('bg_image', None)
|
||||
)
|
||||
|
||||
# 更新内容
|
||||
self.updatePanelContent(
|
||||
panel_id,
|
||||
title=panel_data.get('title', '信息面板'),
|
||||
content=panel_data.get('content', '')
|
||||
)
|
||||
|
||||
# 设置标签
|
||||
if panel_node:
|
||||
panel_node.setTag("element_type", "info_panel")
|
||||
panel_node.setTag("is_scene_element", "1")
|
||||
panel_node.setTag("supports_3d_position_editing", "1")
|
||||
|
||||
# 如果是HTTP面板,重新注册数据源
|
||||
if 'http_info' in panel_data:
|
||||
http_info = panel_data['http_info']
|
||||
self.createHTTPInfoPanel(
|
||||
panel_id=panel_id,
|
||||
url=http_info['url'],
|
||||
method=http_info.get('method', 'GET'),
|
||||
headers=http_info.get('headers', None),
|
||||
data=http_info.get('data', None),
|
||||
position=position,
|
||||
size=size,
|
||||
update_interval=self.data_sources.get(panel_id, {}).get('interval',
|
||||
30.0) if panel_id in self.data_sources else 30.0
|
||||
)
|
||||
|
||||
print(f"✓ 信息面板 {panel_id} 已重建")
|
||||
return panel_node
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 重建信息面板 {panel_data.get('panel_id', 'unknown')} 失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
|
||||
# 示例数据源函数
|
||||
def getRealtimeData():
|
||||
|
||||
@ -212,7 +212,7 @@ class SelectionSystem:
|
||||
return
|
||||
|
||||
# 获取边界框的最小和最大点(世界坐标)
|
||||
print(f"世界边界框: min={minPoint}, max={maxPoint}")
|
||||
#print(f"世界边界框: min={minPoint}, max={maxPoint}")
|
||||
|
||||
# 创建线段对象
|
||||
lines = LineSegs()
|
||||
|
||||
@ -567,3 +567,88 @@ class TerrainManager:
|
||||
except Exception as e:
|
||||
print(f"应用地形纹理时出错: {e}")
|
||||
return False
|
||||
|
||||
def saveTerrainData(self, terrain_info, filename):
|
||||
"""保存地形数据到文件"""
|
||||
try:
|
||||
terrain_node = terrain_info['node']
|
||||
heightfield = terrain_info['heightfield']
|
||||
|
||||
# 保存高度图到文件
|
||||
if heightfield:
|
||||
# 创建保存路径
|
||||
terrain_dir = os.path.join(os.path.dirname(filename), "terrains")
|
||||
if not os.path.exists(terrain_dir):
|
||||
os.makedirs(terrain_dir)
|
||||
|
||||
# 生成唯一的地形文件名
|
||||
terrain_filename = f"terrain_{terrain_info.get('name', 'unnamed')}_{int(time.time())}.png"
|
||||
terrain_path = os.path.join(terrain_dir, terrain_filename)
|
||||
|
||||
# 保存高度图
|
||||
heightfield.write(Filename.fromOsSpecific(terrain_path))
|
||||
|
||||
# 保存地形信息到标签
|
||||
terrain_node.setTag("terrain_heightmap_path", terrain_path)
|
||||
terrain_node.setTag("terrain_scale", str(terrain_info['scale']))
|
||||
|
||||
print(f"✓ 地形数据已保存: {terrain_path}")
|
||||
return terrain_path
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"保存地形数据时出错: {e}")
|
||||
return None
|
||||
|
||||
def _recreateTerrain(self, terrain_node):
|
||||
"""重新创建地形"""
|
||||
try:
|
||||
print(f"重新创建地形: {terrain_node.getName()}")
|
||||
|
||||
# 获取保存的地形信息
|
||||
heightmap_path = terrain_node.getTag("terrain_heightmap_path") if terrain_node.hasTag(
|
||||
"terrain_heightmap_path") else None
|
||||
scale_str = terrain_node.getTag("terrain_scale") if terrain_node.hasTag("terrain_scale") else "(1, 1, 1)"
|
||||
|
||||
# 解析缩放信息
|
||||
try:
|
||||
scale_str = scale_str.strip("()")
|
||||
scale_values = [float(x.strip()) for x in scale_str.split(",")]
|
||||
scale = (scale_values[0], scale_values[1], scale_values[2]) if len(scale_values) >= 3 else (1, 1, 1)
|
||||
except:
|
||||
scale = (1, 1, 1)
|
||||
|
||||
# 恢复位置信息
|
||||
if terrain_node.hasTag("transform_pos"):
|
||||
try:
|
||||
pos_str = terrain_node.getTag("transform_pos")
|
||||
pos_str = pos_str.replace('LVecBase3f', '').replace('LPoint3f', '').strip('()')
|
||||
pos_values = [float(x.strip()) for x in pos_str.split(',')]
|
||||
if len(pos_values) >= 3:
|
||||
terrain_node.setPos(pos_values[0], pos_values[1], pos_values[2])
|
||||
except Exception as e:
|
||||
print(f"恢复地形位置失败: {e}")
|
||||
|
||||
# 如果有高度图路径,重新创建地形
|
||||
if heightmap_path and os.path.exists(heightmap_path):
|
||||
# 使用现有方法重新创建地形
|
||||
new_terrain = self.createTerrainFromHeightMap(heightmap_path, scale)
|
||||
if new_terrain:
|
||||
# 删除旧的地形节点
|
||||
if not terrain_node.isEmpty():
|
||||
terrain_node.removeNode()
|
||||
return new_terrain
|
||||
|
||||
# 如果没有高度图或创建失败,创建一个平面地形作为替代
|
||||
print("使用平面地形作为替代")
|
||||
new_terrain = self.createFlatTerrain(size=(scale[0], scale[1]), resolution=129)
|
||||
if new_terrain:
|
||||
# 删除旧的地形节点
|
||||
if not terrain_node.isEmpty():
|
||||
terrain_node.removeNode()
|
||||
return new_terrain
|
||||
|
||||
return terrain_node
|
||||
except Exception as e:
|
||||
print(f"重新创建地形失败: {e}")
|
||||
return terrain_node
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ class GUIManager:
|
||||
|
||||
# ==================== GUI元素创建方法 ====================
|
||||
|
||||
def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||||
def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=(0.1,0.1,0.1)):
|
||||
"""创建2D GUI按钮 - 支持多选创建和GUI父子关系,优化版本"""
|
||||
try:
|
||||
from direct.gui.DirectGui import DirectButton
|
||||
@ -180,9 +180,23 @@ class GUIManager:
|
||||
text_font=self.world.getChineseFont() if self.world.getChineseFont() else None,
|
||||
rolloverSound=None,
|
||||
clickSound=None,
|
||||
parent=parent_gui_node # 设置GUI父节点
|
||||
parent=parent_gui_node
|
||||
)
|
||||
|
||||
if not hasattr(button,'_tags'):
|
||||
button._tags = {}
|
||||
|
||||
# button._tags["gui_type"] = "button"
|
||||
# button._tags["gui_id"] = f"button_{len(self.gui_elements)}"
|
||||
# button._tags["gui_text"] = text
|
||||
# button._tags["is_gui_element"] = "1"
|
||||
# button._tags["is_scene_element"] = "1"
|
||||
# button._tags["saved_gui_type"] = "button"
|
||||
# button._tags["gui_element_type"] = "button"
|
||||
# button._tags["created_by_user"] = "1"
|
||||
# button._tags["name"] = button_name
|
||||
# button.setName(button_name)
|
||||
|
||||
# 设置节点标签
|
||||
button.setTag("gui_type", "button")
|
||||
button.setTag("gui_id", f"button_{len(self.gui_elements)}")
|
||||
@ -190,7 +204,7 @@ class GUIManager:
|
||||
button.setTag("is_gui_element", "1")
|
||||
button.setTag("is_scene_element", "1") # 确保这个标签被设置
|
||||
button.setTag("saved_gui_type", "button") # 添加这个标签以确保兼容性
|
||||
button.setTag("gui_element_type","button")
|
||||
button.setTag("gui_element_type", "button")
|
||||
button.setTag("created_by_user", "1")
|
||||
button.setTag("gui_parent_type", "gui" if parent_gui_node else "3d")
|
||||
button.setTag("name", button_name)
|
||||
@ -225,11 +239,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的按钮并更新场景树
|
||||
if created_buttons:
|
||||
last_button, last_qt_item = created_buttons[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_button, last_qt_item)
|
||||
# if created_buttons:
|
||||
# last_button, last_qt_item = created_buttons[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_button, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_buttons)} 个GUI按钮")
|
||||
|
||||
@ -338,11 +352,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的标签并更新场景树
|
||||
if created_labels:
|
||||
last_label, last_qt_item = created_labels[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_label, last_qt_item)
|
||||
# if created_labels:
|
||||
# last_label, last_qt_item = created_labels[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_label, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_labels)} 个GUI标签")
|
||||
|
||||
@ -449,11 +463,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的输入框并更新场景树
|
||||
if created_entries:
|
||||
last_entry, last_qt_item = created_entries[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_entry, last_qt_item)
|
||||
# if created_entries:
|
||||
# last_entry, last_qt_item = created_entries[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_entry, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_entries)} 个GUI输入框")
|
||||
|
||||
@ -530,6 +544,7 @@ class GUIManager:
|
||||
# 如果提供了图像路径,则加载纹理
|
||||
if image_path:
|
||||
try:
|
||||
image_node.setTag("image_path", image_path)
|
||||
texture = self.world.loader.loadTexture(image_path)
|
||||
if texture:
|
||||
image_node.setTexture(texture, 1)
|
||||
@ -581,11 +596,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的按钮并更新场景树
|
||||
if created_2dimage:
|
||||
last_button, last_qt_item = created_2dimage[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_button, last_qt_item)
|
||||
# if created_2dimage:
|
||||
# last_button, last_qt_item = created_2dimage[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_button, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_2dimage)} 个GUI按钮")
|
||||
|
||||
@ -725,11 +740,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的文本并更新场景树
|
||||
if created_texts:
|
||||
last_text, last_qt_item = created_texts[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_text, last_qt_item)
|
||||
# if created_texts:
|
||||
# last_text, last_qt_item = created_texts[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_text, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_texts)} 个3D文本")
|
||||
|
||||
@ -833,7 +848,7 @@ class GUIManager:
|
||||
image_node.setTag("gui_type", "3d_image")
|
||||
image_node.setTag("gui_id", f"3d_image_{len(self.gui_elements)}")
|
||||
if image_path:
|
||||
image_node.setTag("gui_image_path", image_path)
|
||||
image_node.setTag("image_path", image_path)
|
||||
image_node.setTag("is_gui_element", "1")
|
||||
image_node.setTag("is_scene_element", "1")
|
||||
image_node.setTag("created_by_user", "1")
|
||||
@ -861,11 +876,11 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的文本并更新场景树
|
||||
if created_3dimage:
|
||||
last_image, last_qt_item = created_3dimage[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
tree_widget.update_selection_and_properties(last_image, last_qt_item)
|
||||
# if created_3dimage:
|
||||
# last_image, last_qt_item = created_3dimage[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# tree_widget.update_selection_and_properties(last_image, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_3dimage)} 个3D文本")
|
||||
|
||||
@ -881,7 +896,7 @@ class GUIManager:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def createVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None):
|
||||
def createVideoScreen(self, pos=(0, 0, 0), size=1, video_path=None):
|
||||
"""创建3D视频播放屏幕 - 添加占位符纹理支持"""
|
||||
try:
|
||||
from panda3d.core import CardMaker, TransparencyAttrib, Texture, TextureStage
|
||||
@ -904,7 +919,7 @@ class GUIManager:
|
||||
size = float(size)
|
||||
except (ValueError, TypeError):
|
||||
print(f"⚠️ 尺寸参数无效,使用默认值 0.2,原始值: {size}")
|
||||
size = 0.2
|
||||
size = 0.2*5
|
||||
|
||||
print(f"📺 开始创建视频屏幕,位置: {pos}, 尺寸: {size}, 视频路径: {video_path}")
|
||||
|
||||
@ -1051,12 +1066,12 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的视频屏幕
|
||||
if created_videoscreens:
|
||||
last_screen_np, last_qt_item = created_videoscreens[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
# 更新选择和属性面板
|
||||
tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
# if created_videoscreens:
|
||||
# last_screen_np, last_qt_item = created_videoscreens[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# # 更新选择和属性面板
|
||||
# tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_videoscreens)} 个视频屏幕")
|
||||
|
||||
@ -1273,7 +1288,6 @@ class GUIManager:
|
||||
def loadVideoFile(self, video_screen, video_path):
|
||||
"""为视频屏幕加载新的视频文件"""
|
||||
try:
|
||||
from panda3d.core import Texture, TextureStage
|
||||
import os
|
||||
|
||||
if not os.path.exists(video_path):
|
||||
@ -1431,8 +1445,6 @@ class GUIManager:
|
||||
print(f"⚠️ 尺寸参数无效,使用默认值 0.2,原始值: {size}, 错误: {e}")
|
||||
size = 0.2
|
||||
|
||||
print(f"📺 开始创建2D视频屏幕,位置: {pos}, 尺寸: {size}, 视频路径: {video_path}")
|
||||
|
||||
# 获取树形控件
|
||||
tree_widget = self._get_tree_widget()
|
||||
if not tree_widget:
|
||||
@ -1459,7 +1471,9 @@ class GUIManager:
|
||||
frameColor=(1, 1, 1, 1), # 默认背景色
|
||||
pos=(pos[0] * 0.1, 0, pos[1] * 0.1), # 转换为屏幕坐标
|
||||
parent=parent_node if tree_widget.is_gui_element(parent_node) else self.world.aspect2d,
|
||||
suppressMouse=True
|
||||
suppressMouse=True,
|
||||
|
||||
|
||||
)
|
||||
|
||||
video_screen.setName(screen_name)
|
||||
@ -1467,7 +1481,7 @@ class GUIManager:
|
||||
# 设置透明度支持
|
||||
video_screen.setTransparency(TransparencyAttrib.MAlpha)
|
||||
|
||||
# 设置2D视频屏幕特有的标签
|
||||
#设置2D视频屏幕特有的标签
|
||||
video_screen.setTag("gui_type", "2d_video_screen")
|
||||
video_screen.setTag("gui_id", f"2d_video_screen_{len(self.gui_elements)}")
|
||||
video_screen.setTag("gui_text", f"2D视频屏幕_{len(self.gui_elements)}")
|
||||
@ -1475,11 +1489,8 @@ class GUIManager:
|
||||
video_screen.setTag("is_scene_element", "1")
|
||||
video_screen.setTag("created_by_user", "1")
|
||||
|
||||
# 设置视频路径标签
|
||||
if video_path and os.path.exists(video_path):
|
||||
video_screen.setTag("video_path", video_path)
|
||||
else:
|
||||
video_screen.setTag("video_path", "")
|
||||
video_screen.setTag("video_path", video_path if video_path else "")
|
||||
print(f"🔧 设置2D视频屏幕标签 - video_path: {video_path if video_path else '空'}")
|
||||
|
||||
# 关键修改:预先创建一个占位符纹理,为后续视频播放做准备
|
||||
placeholder_texture = Texture(f"placeholder_video_texture_{len(self.gui_elements)}")
|
||||
@ -1552,12 +1563,12 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的视频屏幕
|
||||
if created_videoscreens:
|
||||
last_screen_np, last_qt_item = created_videoscreens[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
# 更新选择和属性面板
|
||||
tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
# if created_videoscreens:
|
||||
# last_screen_np, last_qt_item = created_videoscreens[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# # 更新选择和属性面板
|
||||
# tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_videoscreens)} 个2D视频屏幕")
|
||||
|
||||
@ -1578,7 +1589,10 @@ class GUIManager:
|
||||
try:
|
||||
import os
|
||||
|
||||
if not os.path.exists(video_path):
|
||||
video_screen.setTag("video_path",video_path)
|
||||
print(f"🔧 更新2D视频屏幕标签 - video_path: {video_path if video_path else '空'}")
|
||||
|
||||
if not video_path or not os.path.exists(video_path):
|
||||
print(f"❌ 2D视频文件不存在: {video_path}")
|
||||
return False
|
||||
|
||||
@ -1590,7 +1604,6 @@ class GUIManager:
|
||||
|
||||
# 保存视频纹理引用
|
||||
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||
video_screen.setTag("video_path", video_path)
|
||||
|
||||
print(f"✅ 成功加载新2D视频: {video_path}")
|
||||
return True
|
||||
@ -1817,12 +1830,12 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的球形视频
|
||||
if created_spherical_videos:
|
||||
last_sphere_np, last_qt_item = created_spherical_videos[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
# 更新选择和属性面板
|
||||
tree_widget.update_selection_and_properties(last_sphere_np, last_qt_item)
|
||||
# if created_spherical_videos:
|
||||
# last_sphere_np, last_qt_item = created_spherical_videos[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# # 更新选择和属性面板
|
||||
# tree_widget.update_selection_and_properties(last_sphere_np, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_spherical_videos)} 个球形视频")
|
||||
|
||||
@ -2022,12 +2035,12 @@ class GUIManager:
|
||||
return None
|
||||
|
||||
# 选中最后创建的虚拟屏幕
|
||||
if created_screens:
|
||||
last_screen_np, last_qt_item = created_screens[-1]
|
||||
if last_qt_item:
|
||||
tree_widget.setCurrentItem(last_qt_item)
|
||||
# 更新选择和属性面板
|
||||
tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
# if created_screens:
|
||||
# last_screen_np, last_qt_item = created_screens[-1]
|
||||
# if last_qt_item:
|
||||
# tree_widget.setCurrentItem(last_qt_item)
|
||||
# # 更新选择和属性面板
|
||||
# tree_widget.update_selection_and_properties(last_screen_np, last_qt_item)
|
||||
|
||||
print(f"🎉 总共创建了 {len(created_screens)} 个虚拟屏幕")
|
||||
|
||||
|
||||
8
main.py
8
main.py
@ -233,9 +233,9 @@ class MyWorld(CoreWorld):
|
||||
"""创建3D图片"""
|
||||
return self.gui_manager.createGUI3DImage(pos,text,size)
|
||||
|
||||
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=0.2):
|
||||
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=1):
|
||||
"""创建2D GUI图片"""
|
||||
return self.gui_manager.createGUI2DImage(pos, image_path, size)
|
||||
return self.gui_manager.createGUI2DImage(pos, image_path, size*0.2)
|
||||
|
||||
def createVideoScreen(self,pos=(0,0,0),size=1,video_path=None):
|
||||
"""创建视频屏幕"""
|
||||
@ -492,10 +492,6 @@ class MyWorld(CoreWorld):
|
||||
"""异步导入模型"""
|
||||
return self.scene_manager.importModelAsync(filepath)
|
||||
|
||||
def loadAnimatedModel(self, model_path, anims=None):
|
||||
"""加载带动画的模型"""
|
||||
return self.scene_manager.loadAnimatedModel(model_path, anims)
|
||||
|
||||
# 材质和几何体处理方法 - 代理到scene_manager
|
||||
def processMaterials(self, model):
|
||||
"""处理模型材质"""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -296,7 +296,6 @@ class InterfaceManager:
|
||||
addNodeToTree(model, sceneRoot,force=True)
|
||||
|
||||
# 添加所有GUI元素
|
||||
print(f"GUIGUIGUIGUIGUIGUIGUIGUIGUIGUIGUIGUIUGIUGI{self.world.gui_elements}")
|
||||
for gui in self.world.gui_elements:
|
||||
# 检查是否是有效的GUI节点(具有getTag方法的NodePath)
|
||||
if hasattr(gui, 'getTag') and hasattr(gui, 'getName'):
|
||||
|
||||
@ -639,10 +639,10 @@ class MainWindow(QMainWindow):
|
||||
self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock)
|
||||
|
||||
# 创建底部停靠控制台
|
||||
self.consoleDock = QDockWidget("控制台", self)
|
||||
self.consoleView = CustomConsoleDockWidget(self.world)
|
||||
self.consoleDock.setWidget(self.consoleView)
|
||||
self.addDockWidget(Qt.BottomDockWidgetArea, self.consoleDock)
|
||||
# self.consoleDock = QDockWidget("控制台", self)
|
||||
# self.consoleView = CustomConsoleDockWidget(self.world)
|
||||
# self.consoleDock.setWidget(self.consoleView)
|
||||
# self.addDockWidget(Qt.BottomDockWidgetArea, self.consoleDock)
|
||||
|
||||
def setupToolbar(self):
|
||||
"""创建工具栏"""
|
||||
|
||||
@ -14,7 +14,7 @@ from direct.actor.Actor import Actor
|
||||
from direct.gui import DirectGui
|
||||
from idna import check_label
|
||||
from jinja2.compiler import has_safe_repr
|
||||
from panda3d.core import Vec3, Vec4, transpose, TransparencyAttrib, PartGroup, ColorAttrib
|
||||
from panda3d.core import Vec3, Vec4, transpose, TransparencyAttrib, PartGroup, ColorAttrib, NodePath
|
||||
from scene import util
|
||||
from direct.gui.DirectGui import DirectLabel, DirectFrame
|
||||
from panda3d.core import TextNode
|
||||
@ -3774,54 +3774,6 @@ class PropertyPanelManager:
|
||||
print(f"加载新视频失败: {e}")
|
||||
return False
|
||||
|
||||
def load2DVideoFile(self, video_screen, video_path):
|
||||
"""为2D视频屏幕加载新的视频文件"""
|
||||
try:
|
||||
import os
|
||||
|
||||
# 处理空路径情况 - 显示空白
|
||||
if not video_path or video_path == "":
|
||||
print("ℹ️ 空视频路径,显示空白")
|
||||
video_screen["frameColor"] = (0, 0, 0, 0) # 透明背景
|
||||
video_screen.clearPythonTag("movie_texture")
|
||||
video_screen.setTag("video_path", "")
|
||||
return True
|
||||
|
||||
# 检查文件是否存在
|
||||
if not os.path.exists(video_path):
|
||||
print(f"❌ 2D视频文件不存在: {video_path}")
|
||||
# 显示空白而不是红色错误提示
|
||||
video_screen["frameColor"] = (0, 0, 0, 0) # 透明背景
|
||||
return False
|
||||
|
||||
# 加载新的视频纹理
|
||||
movie_texture = self._loadMovieTexture(video_path)
|
||||
if movie_texture:
|
||||
# 应用纹理到2D视频屏幕
|
||||
video_screen["frameTexture"] = movie_texture
|
||||
# 设置白色背景以正确显示视频
|
||||
video_screen["frameColor"] = (1, 1, 1, 1)
|
||||
|
||||
# 保存视频纹理引用
|
||||
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||
video_screen.setTag("video_path", video_path)
|
||||
|
||||
print(f"✅ 成功加载新2D视频: {video_path}")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 无法加载2D视频文件: {video_path}")
|
||||
# 显示空白而不是红色错误提示
|
||||
video_screen["frameColor"] = (0, 0, 0, 0) # 透明背景
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 加载2D视频文件失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
# 显示空白而不是红色错误提示
|
||||
video_screen["frameColor"] = (0, 0, 0, 0) # 透明背景
|
||||
return False
|
||||
|
||||
def _loadVideoFromURLWithOpenCV_3D(self, video_screen, url):
|
||||
"""使用OpenCV从URL加载视频流并在3D视频屏幕上显示"""
|
||||
try:
|
||||
@ -8224,17 +8176,19 @@ class PropertyPanelManager:
|
||||
|
||||
# 其他格式使用标准 Actor 加载
|
||||
try:
|
||||
test_actor=Actor(filepath)
|
||||
import gltf
|
||||
print(f"[GLTF加载] 尝试加载: {filepath}")
|
||||
# test_actor=Actor(NodePath(gltf._loader.GltfLoader.load_file(filepath,None)))
|
||||
test_actor=Actor(NodePath(gltf.load_model(filepath,None)))
|
||||
anims = test_actor.getAnimNames()
|
||||
test_actor.reparentTo(self.world.render)
|
||||
self._actor_cache[origin_model] = test_actor
|
||||
print(f"[Actor加载] 标准加载检测到动画: {anims}")
|
||||
if not anims:
|
||||
test_actor.cleanup()
|
||||
test_actor.removeNode()
|
||||
return None
|
||||
actor = Actor(filepath)
|
||||
actor.reparentTo(self.world.render)
|
||||
self._actor_cache[origin_model] = actor
|
||||
return actor
|
||||
return test_actor
|
||||
except Exception as e:
|
||||
print(f"创建Actor失败: {e}")
|
||||
return None
|
||||
@ -8590,6 +8544,8 @@ except Exception as e:
|
||||
print(f"[系统转换] 系统转换失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def _playAnimation(self,origin_model):
|
||||
actor=self._getActor(origin_model)
|
||||
if not actor:
|
||||
@ -8702,7 +8658,7 @@ except Exception as e:
|
||||
anim_name = self.animation_combo.currentText()
|
||||
actor.setPos(origin_model.getPos())
|
||||
actor.setHpr(origin_model.getHpr())
|
||||
actor.setScale(origin_model.getScale())
|
||||
actor.setScale(origin_model.getScale()/100)
|
||||
|
||||
if cmd == "play":
|
||||
origin_model.hide()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user