forked from Rowland/EG
3d视频屏幕和2d视频屏幕
This commit is contained in:
parent
d980330d9d
commit
5e68ff5ee6
File diff suppressed because one or more lines are too long
@ -98,7 +98,7 @@ class SelectionSystem:
|
|||||||
else:
|
else:
|
||||||
main_window.unsetCursor()
|
main_window.unsetCursor()
|
||||||
self._current_cursor = cursor_type
|
self._current_cursor = cursor_type
|
||||||
print(f"光标已设置:{cursor_type}")
|
#print(f"光标已设置:{cursor_type}")
|
||||||
self._current_cursor = cursor_type
|
self._current_cursor = cursor_type
|
||||||
else:
|
else:
|
||||||
print("警告:无法获取主窗口,光标设置失败")
|
print("警告:无法获取主窗口,光标设置失败")
|
||||||
@ -399,19 +399,24 @@ class SelectionSystem:
|
|||||||
is_scale_tool = self.world.tool_manager.isScaleTool() if self.world.tool_manager else False
|
is_scale_tool = self.world.tool_manager.isScaleTool() if self.world.tool_manager else False
|
||||||
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
|
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
|
||||||
|
|
||||||
|
import os
|
||||||
|
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
if is_scale_tool:
|
if is_scale_tool:
|
||||||
model_paths = [
|
model_paths = [
|
||||||
"core/UniformScaleHandle.fbx",
|
os.path.join(base_dir,"core/UniformScaleHandle.fbx"),
|
||||||
]
|
]
|
||||||
elif is_rotate_tool:
|
elif is_rotate_tool:
|
||||||
model_paths = [
|
model_paths = [
|
||||||
"core/RotationHandleQuarter.fbx",
|
os.path.join(base_dir,"core/RotationHandleQuarter.fbx"),
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
model_paths = [
|
model_paths = [
|
||||||
"core/TranslateArrowHandle.fbx",
|
os.path.join(base_dir, "core/TranslateArrowHandle.fbx"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
arrow_path = os.path.join(base_dir, "core/TranslateArrowHandle.fbx")
|
||||||
|
|
||||||
# model_paths = [
|
# model_paths = [
|
||||||
# "core/TranslateArrowHandle.fbx",
|
# "core/TranslateArrowHandle.fbx",
|
||||||
# "EG/core/TranslateArrowHandle.fbx",
|
# "EG/core/TranslateArrowHandle.fbx",
|
||||||
@ -421,7 +426,7 @@ class SelectionSystem:
|
|||||||
for path in model_paths:
|
for path in model_paths:
|
||||||
try:
|
try:
|
||||||
if is_rotate_tool:
|
if is_rotate_tool:
|
||||||
gizmo_model = self.world.loader.loadModel("core/TranslateArrowHandle.fbx")
|
gizmo_model = self.world.loader.loadModel(arrow_path)
|
||||||
gizmoRot_model = self.world.loader.loadModel(path)
|
gizmoRot_model = self.world.loader.loadModel(path)
|
||||||
else:
|
else:
|
||||||
gizmo_model = self.world.loader.loadModel(path)
|
gizmo_model = self.world.loader.loadModel(path)
|
||||||
@ -778,7 +783,7 @@ class SelectionSystem:
|
|||||||
self.gizmo.setScale(scale_factor)
|
self.gizmo.setScale(scale_factor)
|
||||||
|
|
||||||
# 限制缩放范围,避免过大或过小
|
# 限制缩放范围,避免过大或过小
|
||||||
min_scale = 0.08
|
min_scale = 0.001
|
||||||
max_scale = 100.0
|
max_scale = 100.0
|
||||||
final_scale = max(min_scale, min(max_scale, scale_factor))
|
final_scale = max(min_scale, min(max_scale, scale_factor))
|
||||||
|
|
||||||
@ -1614,7 +1619,7 @@ class SelectionSystem:
|
|||||||
if self.dragGizmoAxis == "x":
|
if self.dragGizmoAxis == "x":
|
||||||
new_hpr = Vec3(start_hpr.x+rotation_amount,start_hpr.y,start_hpr.z)
|
new_hpr = Vec3(start_hpr.x+rotation_amount,start_hpr.y,start_hpr.z)
|
||||||
elif self.dragGizmoAxis == "y":
|
elif self.dragGizmoAxis == "y":
|
||||||
new_hpr = Vec3(start_hpr.x,start_hpr.y+rotation_amount,start_hpr.z)
|
new_hpr = Vec3(start_hpr.x,start_hpr.y-rotation_amount,start_hpr.z)
|
||||||
elif self.dragGizmoAxis == "z":
|
elif self.dragGizmoAxis == "z":
|
||||||
new_hpr = Vec3(start_hpr.x,start_hpr.y,start_hpr.z+rotation_amount)
|
new_hpr = Vec3(start_hpr.x,start_hpr.y,start_hpr.z+rotation_amount)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -33,12 +33,73 @@ class CoreWorld(Panda3DWorld):
|
|||||||
self.mouseRightPressed = False
|
self.mouseRightPressed = False
|
||||||
|
|
||||||
# 初始化世界
|
# 初始化世界
|
||||||
|
self._setupResourcePaths()
|
||||||
self._setupCamera()
|
self._setupCamera()
|
||||||
self._setupLighting()
|
self._setupLighting()
|
||||||
self._setupGround()
|
self._setupGround()
|
||||||
self._loadFont()
|
self._loadFont()
|
||||||
#self.load_and_play_glb_model()
|
#self.load_and_play_glb_model()
|
||||||
|
|
||||||
|
def _setupResourcePaths(self):
|
||||||
|
"""设置Panda3D资源搜索路径,确保能正确找到Resources文件夹中的模型和贴图"""
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
from panda3d.core import getModelPath, DSearchPath, Filename
|
||||||
|
|
||||||
|
# 获取项目根目录
|
||||||
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
resources_dir = os.path.join(project_root, "Resources")
|
||||||
|
|
||||||
|
# 确保Resources目录存在
|
||||||
|
if not os.path.exists(resources_dir):
|
||||||
|
os.makedirs(resources_dir, exist_ok=True)
|
||||||
|
print(f"✓ 创建Resources目录: {resources_dir}")
|
||||||
|
|
||||||
|
# 添加Resources目录到Panda3D模型搜索路径
|
||||||
|
model_path = getModelPath()
|
||||||
|
resources_filename = Filename.from_os_specific(resources_dir)
|
||||||
|
|
||||||
|
# 检查路径是否已存在,避免重复添加
|
||||||
|
if not model_path.findFile(resources_filename):
|
||||||
|
model_path.appendDirectory(resources_filename)
|
||||||
|
print(f"✓ 添加Resources到模型搜索路径: {resources_dir}")
|
||||||
|
|
||||||
|
# 同时添加各个子目录到搜索路径
|
||||||
|
subdirs = ['models', 'textures', 'animations', 'icons', 'materials']
|
||||||
|
for subdir in subdirs:
|
||||||
|
subdir_path = os.path.join(resources_dir, subdir)
|
||||||
|
if os.path.exists(subdir_path):
|
||||||
|
subdir_filename = Filename.from_os_specific(subdir_path)
|
||||||
|
if not model_path.findFile(subdir_filename):
|
||||||
|
model_path.appendDirectory(subdir_filename)
|
||||||
|
print(f"✓ 添加子目录到搜索路径: {subdir}")
|
||||||
|
else:
|
||||||
|
# 创建不存在的子目录
|
||||||
|
os.makedirs(subdir_path, exist_ok=True)
|
||||||
|
subdir_filename = Filename.from_os_specific(subdir_path)
|
||||||
|
model_path.appendDirectory(subdir_filename)
|
||||||
|
print(f"✓ 创建并添加子目录: {subdir}")
|
||||||
|
|
||||||
|
# 设置纹理搜索路径
|
||||||
|
from panda3d.core import getTexturePath
|
||||||
|
texture_path = getTexturePath()
|
||||||
|
if not texture_path.findFile(resources_filename):
|
||||||
|
texture_path.appendDirectory(resources_filename)
|
||||||
|
|
||||||
|
for subdir in ['textures', 'materials', 'icons']:
|
||||||
|
subdir_path = os.path.join(resources_dir, subdir)
|
||||||
|
if os.path.exists(subdir_path):
|
||||||
|
subdir_filename = Filename.from_os_specific(subdir_path)
|
||||||
|
if not texture_path.findFile(subdir_filename):
|
||||||
|
texture_path.appendDirectory(subdir_filename)
|
||||||
|
|
||||||
|
print(f"✓ 资源路径设置完成")
|
||||||
|
print(f" 项目根目录: {project_root}")
|
||||||
|
print(f" Resources目录: {resources_dir}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ 设置资源路径失败: {e}")
|
||||||
|
|
||||||
def load_and_play_glb_model(self):
|
def load_and_play_glb_model(self):
|
||||||
"""加载 glTF 模型并播放动画"""
|
"""加载 glTF 模型并播放动画"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -861,6 +861,830 @@ class GUIManager:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def createVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None):
|
||||||
|
"""创建视频播放屏幕 - 改进版本"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import CardMaker, TransparencyAttrib, Texture, TextureStage
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 确保 pos 是有效的三维坐标元组
|
||||||
|
if not isinstance(pos, (tuple, list)) or len(pos) != 3:
|
||||||
|
print(f"⚠️ 位置参数无效,使用默认值 (0, 0, 0),原始值: {pos}")
|
||||||
|
pos = (0, 0, 0)
|
||||||
|
else:
|
||||||
|
# 确保所有坐标都是数值类型
|
||||||
|
try:
|
||||||
|
pos = (float(pos[0]), float(pos[1]), float(pos[2]))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
print(f"⚠️ 位置参数包含非数值,使用默认值 (0, 0, 0),原始值: {pos}")
|
||||||
|
pos = (0, 0, 0)
|
||||||
|
|
||||||
|
# 确保 size 是有效数值
|
||||||
|
try:
|
||||||
|
size = float(size)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
print(f"⚠️ 尺寸参数无效,使用默认值 0.2,原始值: {size}")
|
||||||
|
size = 0.2
|
||||||
|
|
||||||
|
print(f"📺 开始创建视频屏幕,位置: {pos}, 尺寸: {size}, 视频路径: {video_path}")
|
||||||
|
|
||||||
|
# 获取树形控件
|
||||||
|
tree_widget = self._get_tree_widget()
|
||||||
|
if not tree_widget:
|
||||||
|
print("❌ 无法访问树形控件")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取目标父节点列表
|
||||||
|
target_parents = tree_widget.get_target_parents_for_gui_creation()
|
||||||
|
if not target_parents:
|
||||||
|
print("❌ 没有找到有效的父节点")
|
||||||
|
return None
|
||||||
|
|
||||||
|
created_videoscreens = []
|
||||||
|
|
||||||
|
# 为每个有效的父节点创建视频屏幕
|
||||||
|
for parent_item, parent_node in target_parents:
|
||||||
|
try:
|
||||||
|
# 生成唯一名称
|
||||||
|
screen_name = f"VideoScreen_{len(self.gui_elements)}"
|
||||||
|
|
||||||
|
# 使用CardMaker创建视频屏幕框架
|
||||||
|
cm = CardMaker('video-screen')
|
||||||
|
cm.setFrame(-size, size, -size, size)
|
||||||
|
|
||||||
|
# 创建挂载节点 - 挂载到选中的父节点
|
||||||
|
video_screen = parent_node.attachNewNode(cm.generate())
|
||||||
|
video_screen.setPos(*pos)
|
||||||
|
video_screen.setName(screen_name)
|
||||||
|
video_screen.setBin('fixed', 10)
|
||||||
|
|
||||||
|
# 设置透明度支持
|
||||||
|
video_screen.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
# 设置初始颜色为白色,确保纹理能正确显示
|
||||||
|
video_screen.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
# 如果提供了视频路径,则加载视频纹理
|
||||||
|
movie_texture = None
|
||||||
|
if video_path and os.path.exists(video_path):
|
||||||
|
try:
|
||||||
|
print(f"🔍 尝试加载视频纹理: {video_path}")
|
||||||
|
# 加载视频纹理
|
||||||
|
movie_texture = self._loadMovieTexture(video_path)
|
||||||
|
if movie_texture:
|
||||||
|
# 创建纹理阶段
|
||||||
|
texture_stage = TextureStage("video")
|
||||||
|
texture_stage.setSort(0)
|
||||||
|
texture_stage.setMode(TextureStage.MModulate)
|
||||||
|
video_screen.setTexture(texture_stage, movie_texture)
|
||||||
|
|
||||||
|
print(f"✅ 视频纹理加载成功: {video_path}")
|
||||||
|
|
||||||
|
# 尝试自动播放视频(如果支持)
|
||||||
|
try:
|
||||||
|
if hasattr(movie_texture, 'play'):
|
||||||
|
movie_texture.play()
|
||||||
|
print("▶️ 视频已开始播放")
|
||||||
|
except Exception as play_error:
|
||||||
|
print(f"⚠️ 视频自动播放失败: {play_error}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 无法加载视频纹理: {video_path}")
|
||||||
|
# 使用默认颜色作为占位符
|
||||||
|
video_screen.setColor(0.1, 0.1, 0.3, 0.8)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载视频纹理失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
# 使用默认颜色作为占位符
|
||||||
|
video_screen.setColor(0.1, 0.1, 0.3, 0.8)
|
||||||
|
else:
|
||||||
|
# 没有视频文件时显示默认颜色
|
||||||
|
video_screen.setColor(0.1, 0.1, 0.3, 0.8)
|
||||||
|
if video_path:
|
||||||
|
print(f"⚠️ 视频文件不存在: {video_path}")
|
||||||
|
else:
|
||||||
|
print("ℹ️ 未提供视频文件,显示默认占位符")
|
||||||
|
|
||||||
|
# 确保视频屏幕有正确的材质
|
||||||
|
self._ensureVideoScreenMaterial(video_screen)
|
||||||
|
|
||||||
|
# 设置节点标签
|
||||||
|
video_screen.setTag("gui_type", "video_screen")
|
||||||
|
video_screen.setTag("gui_id", f"video_screen_{len(self.gui_elements)}")
|
||||||
|
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("created_by_user", "1")
|
||||||
|
if video_path and os.path.exists(video_path):
|
||||||
|
video_screen.setTag("video_path", video_path)
|
||||||
|
|
||||||
|
# 保存视频纹理引用以便后续控制
|
||||||
|
if movie_texture:
|
||||||
|
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||||
|
|
||||||
|
# 添加到GUI元素列表
|
||||||
|
self.gui_elements.append(video_screen)
|
||||||
|
|
||||||
|
print(f"✅ 为 {parent_item.text(0)} 创建视频屏幕成功: {screen_name}")
|
||||||
|
|
||||||
|
# 在Qt树形控件中添加对应节点
|
||||||
|
qt_item = tree_widget.add_node_to_tree_widget(video_screen, parent_item, "GUI_VIDEO_SCREEN")
|
||||||
|
if qt_item:
|
||||||
|
created_videoscreens.append((video_screen, qt_item))
|
||||||
|
else:
|
||||||
|
created_videoscreens.append((video_screen, None))
|
||||||
|
print("⚠️ Qt树节点添加失败,但Panda3D对象已创建")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 为 {parent_item.text(0)} 创建视频屏幕失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 处理创建结果
|
||||||
|
if not created_videoscreens:
|
||||||
|
print("❌ 没有成功创建任何视频屏幕")
|
||||||
|
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)
|
||||||
|
|
||||||
|
print(f"🎉 总共创建了 {len(created_videoscreens)} 个视频屏幕")
|
||||||
|
|
||||||
|
# 返回值处理
|
||||||
|
if len(created_videoscreens) == 1:
|
||||||
|
return created_videoscreens[0][0] # 单个屏幕返回NodePath
|
||||||
|
else:
|
||||||
|
return [screen_np for screen_np, _ in created_videoscreens] # 多个屏幕返回列表
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 创建视频屏幕过程失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _ensureVideoScreenMaterial(self, video_screen):
|
||||||
|
"""确保视频屏幕有正确的材质设置"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Material, LColor
|
||||||
|
|
||||||
|
# 如果还没有材质,则创建一个
|
||||||
|
if not video_screen.hasMaterial():
|
||||||
|
material = Material(f"video-material-{video_screen.getName()}")
|
||||||
|
material.setBaseColor(LColor(1, 1, 1, 1))
|
||||||
|
material.setDiffuse(LColor(1, 1, 1, 1))
|
||||||
|
material.setAmbient(LColor(1, 1, 1, 1)) # 确保环境光为白色
|
||||||
|
material.setEmission(LColor(0, 0, 0, 1))
|
||||||
|
material.setSpecular(LColor(0, 0, 0, 1))
|
||||||
|
material.setShininess(0)
|
||||||
|
video_screen.setMaterial(material, 1)
|
||||||
|
print(f"✅ 为视频屏幕创建了新材质: {video_screen.getName()}")
|
||||||
|
else:
|
||||||
|
# 更新现有材质确保正确设置
|
||||||
|
material = video_screen.getMaterial()
|
||||||
|
material.setBaseColor(LColor(1, 1, 1, 1))
|
||||||
|
material.setAmbient(LColor(1, 1, 1, 1)) # 确保环境光为白色
|
||||||
|
video_screen.setMaterial(material, 1)
|
||||||
|
print(f"✅ 更新了视频屏幕材质: {video_screen.getName()}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ 设置视频屏幕材质时出错: {e}")
|
||||||
|
|
||||||
|
def _debugVideoScreenTextures(self, video_screen):
|
||||||
|
"""调试视频屏幕的纹理状态"""
|
||||||
|
try:
|
||||||
|
print(f"调试视频屏幕 {video_screen.getName()}:")
|
||||||
|
|
||||||
|
# 检查PythonTag
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
if movie_texture:
|
||||||
|
print(f" - PythonTag movie_texture: {type(movie_texture)}")
|
||||||
|
if hasattr(movie_texture, 'is_playable'):
|
||||||
|
print(f" - is_playable: {movie_texture.is_playable()}")
|
||||||
|
else:
|
||||||
|
print(" - PythonTag movie_texture: None")
|
||||||
|
|
||||||
|
# 检查所有纹理阶段
|
||||||
|
texture_stages = video_screen.findAllTextureStages()
|
||||||
|
print(f" - 纹理阶段数: {texture_stages.getNumStages()}")
|
||||||
|
for i in range(texture_stages.getNumStages()):
|
||||||
|
stage = texture_stages.getStage(i)
|
||||||
|
texture = video_screen.getTexture(stage)
|
||||||
|
print(f" - 阶段 {i}: {stage.getName()}, 纹理: {texture.getName() if texture else 'None'}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"调试视频屏幕纹理时出错: {e}")
|
||||||
|
|
||||||
|
def playVideo(self, video_screen):
|
||||||
|
"""播放视频 - 改进版本,支持从暂停处继续播放"""
|
||||||
|
try:
|
||||||
|
# 获取视频纹理
|
||||||
|
movie_texture = self._getMovieTextureFromScreen(video_screen)
|
||||||
|
|
||||||
|
if movie_texture:
|
||||||
|
# 检查是否有播放方法
|
||||||
|
if hasattr(movie_texture, 'play'):
|
||||||
|
try:
|
||||||
|
movie_texture.play()
|
||||||
|
print(f"▶️ 继续播放视频: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as play_error:
|
||||||
|
print(f"⚠️ 播放视频时出错: {play_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 纹理对象没有播放方法: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"❌ 视频屏幕没有关联的视频纹理: {video_screen.getName()}")
|
||||||
|
self._debugVideoScreenTextures(video_screen)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 播放视频失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _getMovieTextureFromScreen(self, video_screen):
|
||||||
|
"""从视频屏幕获取视频纹理"""
|
||||||
|
try:
|
||||||
|
# 方法1: 从PythonTag获取
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
if movie_texture:
|
||||||
|
return movie_texture
|
||||||
|
|
||||||
|
# 方法2: 从纹理阶段获取
|
||||||
|
from panda3d.core import TextureStage
|
||||||
|
texture_stage = video_screen.findTextureStage("video")
|
||||||
|
if texture_stage:
|
||||||
|
movie_texture = video_screen.getTexture(texture_stage)
|
||||||
|
if movie_texture:
|
||||||
|
return movie_texture
|
||||||
|
|
||||||
|
# 方法3: 获取第一个纹理
|
||||||
|
if video_screen.hasTexture():
|
||||||
|
movie_texture = video_screen.getTexture()
|
||||||
|
if movie_texture:
|
||||||
|
return movie_texture
|
||||||
|
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"获取视频纹理时出错: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def pauseVideo(self, video_screen):
|
||||||
|
"""暂停视频"""
|
||||||
|
try:
|
||||||
|
movie_texture = self._getMovieTextureFromScreen(video_screen)
|
||||||
|
|
||||||
|
if movie_texture:
|
||||||
|
# 检查是否有暂停方法
|
||||||
|
if hasattr(movie_texture, 'stop'): # MovieTexture使用stop来暂停
|
||||||
|
try:
|
||||||
|
movie_texture.stop()
|
||||||
|
print(f"⏸️ 视频已暂停: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as stop_error:
|
||||||
|
print(f"⚠️ 暂停视频时出错: {stop_error}")
|
||||||
|
return False
|
||||||
|
elif hasattr(movie_texture, 'set play rate'): # 某些版本支持设置播放速率
|
||||||
|
try:
|
||||||
|
movie_texture.setPlayRate(0.0)
|
||||||
|
print(f"⏸️ 视频已暂停(播放速率设为0): {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as rate_error:
|
||||||
|
print(f"⚠️ 设置播放速率时出错: {rate_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 纹理对象没有暂停方法: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"❌ 视频屏幕没有关联的视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 暂停视频失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stopVideo(self, video_screen):
|
||||||
|
"""停止视频(回到开头)"""
|
||||||
|
try:
|
||||||
|
movie_texture = self._getMovieTextureFromScreen(video_screen)
|
||||||
|
|
||||||
|
if movie_texture:
|
||||||
|
# 停止并重置到开头
|
||||||
|
if hasattr(movie_texture, 'stop'):
|
||||||
|
try:
|
||||||
|
movie_texture.stop()
|
||||||
|
# 如果有重置方法,调用它
|
||||||
|
if hasattr(movie_texture, 'setTime'):
|
||||||
|
movie_texture.setTime(0.0)
|
||||||
|
print(f"⏹️ 视频已停止: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as stop_error:
|
||||||
|
print(f"⚠️ 停止视频时出错: {stop_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 纹理对象没有停止方法: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"❌ 视频屏幕没有关联的视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 停止视频失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def setVideoTime(self, video_screen, time_seconds):
|
||||||
|
"""设置视频播放时间"""
|
||||||
|
try:
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
|
||||||
|
# 备用获取方法
|
||||||
|
if not movie_texture:
|
||||||
|
from panda3d.core import TextureStage
|
||||||
|
texture_stage = video_screen.findTextureStage("video")
|
||||||
|
if texture_stage:
|
||||||
|
movie_texture = video_screen.getTexture(texture_stage)
|
||||||
|
|
||||||
|
if not movie_texture and video_screen.hasTexture():
|
||||||
|
movie_texture = video_screen.getTexture()
|
||||||
|
|
||||||
|
if movie_texture and hasattr(movie_texture, 'set_time'):
|
||||||
|
movie_texture.set_time(time_seconds)
|
||||||
|
print(f"🕒 设置视频时间 {time_seconds}s: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"❌ 视频屏幕没有关联的视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 设置视频时间失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def loadVideoFile(self, video_screen, video_path):
|
||||||
|
"""为视频屏幕加载新的视频文件"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Texture, TextureStage
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
print(f"❌ 视频文件不存在: {video_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 加载新的视频纹理
|
||||||
|
movie_texture = self._loadMovieTexture(video_path)
|
||||||
|
if movie_texture:
|
||||||
|
# 清除现有的纹理
|
||||||
|
video_screen.clearTexture()
|
||||||
|
|
||||||
|
# 设置视频纹理属性
|
||||||
|
movie_texture.setWrapU(Texture.WM_clamp)
|
||||||
|
movie_texture.setWrapV(Texture.WM_clamp)
|
||||||
|
movie_texture.setMinfilter(Texture.FT_linear)
|
||||||
|
movie_texture.setMagfilter(Texture.FT_linear)
|
||||||
|
|
||||||
|
# 如果视频纹理支持循环播放,设置循环
|
||||||
|
if hasattr(movie_texture, 'set_loop'):
|
||||||
|
movie_texture.set_loop(True)
|
||||||
|
|
||||||
|
# 如果视频纹理支持播放速率控制,设置正常速率
|
||||||
|
if hasattr(movie_texture, 'set_play_rate'):
|
||||||
|
movie_texture.set_play_rate(1.0)
|
||||||
|
|
||||||
|
# 重要:为视频纹理创建专用的纹理阶段
|
||||||
|
texture_stage = TextureStage("video")
|
||||||
|
texture_stage.setSort(0) # 使用第一个纹理槽
|
||||||
|
texture_stage.setMode(TextureStage.MModulate)
|
||||||
|
|
||||||
|
# 应用纹理到视频屏幕
|
||||||
|
video_screen.setTexture(texture_stage, movie_texture)
|
||||||
|
|
||||||
|
# 保存新的视频纹理引用到PythonTag
|
||||||
|
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||||
|
video_screen.setTag("video_path", video_path)
|
||||||
|
|
||||||
|
# 确保视频屏幕有正确的材质
|
||||||
|
self._ensureVideoScreenMaterial(video_screen)
|
||||||
|
|
||||||
|
print(f"✅ 成功加载新视频: {video_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"❌ 无法加载视频文件: {video_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载视频文件失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _loadMovieTexture(self, video_path):
|
||||||
|
"""加载视频纹理的兼容方法"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Texture, MovieTexture
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 检查文件是否存在
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
print(f"❌ 视频文件不存在: {video_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"🔍 尝试加载视频文件: {video_path}")
|
||||||
|
|
||||||
|
# 方法1: 尝试使用 MovieTexture(专门用于视频)
|
||||||
|
try:
|
||||||
|
movie_texture = MovieTexture(video_path)
|
||||||
|
if movie_texture.read(video_path):
|
||||||
|
print("✅ 使用 MovieTexture 成功加载视频")
|
||||||
|
self._configureVideoTexture(movie_texture)
|
||||||
|
return movie_texture
|
||||||
|
else:
|
||||||
|
print("⚠️ MovieTexture.read() 返回失败")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ MovieTexture 方法失败: {e}")
|
||||||
|
|
||||||
|
# 方法2: 尝试使用 loader.loadTexture
|
||||||
|
try:
|
||||||
|
movie_texture = self.world.loader.loadTexture(video_path)
|
||||||
|
if movie_texture and hasattr(movie_texture, 'is_playable') and movie_texture.is_playable():
|
||||||
|
print("✅ 使用 loader.loadTexture 成功加载视频纹理")
|
||||||
|
self._configureVideoTexture(movie_texture)
|
||||||
|
return movie_texture
|
||||||
|
else:
|
||||||
|
print("⚠️ loader.loadTexture 加载的不是可播放的视频纹理")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ loader.loadTexture 方法失败: {e}")
|
||||||
|
|
||||||
|
# 方法3: 尝试使用 Texture.read(作为最后备选)
|
||||||
|
try:
|
||||||
|
texture = Texture()
|
||||||
|
if texture.read(video_path):
|
||||||
|
print("✅ 使用 Texture.read 成功加载(可能作为静态纹理)")
|
||||||
|
self._configureVideoTexture(texture)
|
||||||
|
return texture
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Texture.read 方法失败: {e}")
|
||||||
|
|
||||||
|
print("❌ 所有视频纹理加载方法都失败")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载视频纹理时发生未知错误: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _configureVideoTexture(self, texture):
|
||||||
|
"""配置视频纹理属性"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Texture
|
||||||
|
|
||||||
|
# 设置纹理属性
|
||||||
|
texture.setWrapU(Texture.WM_clamp)
|
||||||
|
texture.setWrapV(Texture.WM_clamp)
|
||||||
|
texture.setMinfilter(Texture.FT_linear)
|
||||||
|
texture.setMagfilter(Texture.FT_linear)
|
||||||
|
|
||||||
|
# 如果是可播放的视频纹理,设置播放属性
|
||||||
|
if hasattr(texture, 'set_loop') and hasattr(texture, 'set_play_rate'):
|
||||||
|
texture.set_loop(True)
|
||||||
|
texture.set_play_rate(1.0)
|
||||||
|
|
||||||
|
print(f"✅ 视频纹理配置完成: {texture.getName()}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ 配置视频纹理时出错: {e}")
|
||||||
|
|
||||||
|
def createGUI2DVideoScreen(self, pos=(0, 0), size=0.2, video_path=None):
|
||||||
|
"""创建2D视频播放屏幕 - 使用2D坐标"""
|
||||||
|
try:
|
||||||
|
from direct.gui.DirectGui import DirectFrame
|
||||||
|
from panda3d.core import TransparencyAttrib, Texture, TextureStage
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 确保 pos 是有效的二维坐标元组
|
||||||
|
if pos is None or pos is False or not isinstance(pos, (tuple, list)) or len(pos) != 2:
|
||||||
|
print(f"⚠️ 位置参数无效,使用默认值 (0, 0),原始值: {pos}")
|
||||||
|
pos = (0, 0)
|
||||||
|
else:
|
||||||
|
# 确保所有坐标都是数值类型
|
||||||
|
try:
|
||||||
|
pos = (float(pos[0]), float(pos[1]))
|
||||||
|
except (ValueError, TypeError, IndexError) as e:
|
||||||
|
print(f"⚠️ 位置参数包含非数值或索引错误,使用默认值 (0, 0),原始值: {pos}, 错误: {e}")
|
||||||
|
pos = (0, 0)
|
||||||
|
|
||||||
|
# 确保 size 是有效数值
|
||||||
|
try:
|
||||||
|
size = float(size)
|
||||||
|
except (ValueError, TypeError) as e:
|
||||||
|
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:
|
||||||
|
print("❌ 无法访问树形控件")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取目标父节点列表
|
||||||
|
target_parents = tree_widget.get_target_parents_for_gui_creation()
|
||||||
|
if not target_parents:
|
||||||
|
print("❌ 没有找到有效的父节点")
|
||||||
|
return None
|
||||||
|
|
||||||
|
created_videoscreens = []
|
||||||
|
|
||||||
|
# 为每个有效的父节点创建2D视频屏幕
|
||||||
|
for parent_item, parent_node in target_parents:
|
||||||
|
try:
|
||||||
|
# 生成唯一名称
|
||||||
|
screen_name = f"GUI2DVideoScreen_{len(self.gui_elements)}"
|
||||||
|
|
||||||
|
# 使用DirectFrame创建2D视频屏幕
|
||||||
|
video_screen = DirectFrame(
|
||||||
|
frameSize=(-size, size, -size, size),
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
video_screen.setName(screen_name)
|
||||||
|
|
||||||
|
# 设置透明度支持
|
||||||
|
video_screen.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
# 设置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)}")
|
||||||
|
video_screen.setTag("is_gui_element", "1")
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 如果提供了视频路径,则加载视频纹理
|
||||||
|
movie_texture = None
|
||||||
|
if video_path and os.path.exists(video_path):
|
||||||
|
try:
|
||||||
|
print(f"🔍 尝试加载2D视频纹理: {video_path}")
|
||||||
|
# 加载视频纹理
|
||||||
|
movie_texture = self._loadMovieTexture(video_path)
|
||||||
|
if movie_texture:
|
||||||
|
# 应用纹理到视频屏幕
|
||||||
|
video_screen["frameTexture"] = movie_texture
|
||||||
|
print(f"✅ 2D视频纹理加载成功: {video_path}")
|
||||||
|
|
||||||
|
# 保存视频纹理引用以便后续控制
|
||||||
|
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||||
|
|
||||||
|
# 尝试自动播放视频(如果支持)
|
||||||
|
try:
|
||||||
|
if hasattr(movie_texture, 'play'):
|
||||||
|
movie_texture.play()
|
||||||
|
print("▶️ 2D视频已开始播放")
|
||||||
|
except Exception as play_error:
|
||||||
|
print(f"⚠️ 2D视频自动播放失败: {play_error}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 无法加载2D视频纹理: {video_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载2D视频纹理失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
else:
|
||||||
|
if video_path:
|
||||||
|
print(f"⚠️ 2D视频文件不存在: {video_path}")
|
||||||
|
|
||||||
|
# 添加到GUI元素列表
|
||||||
|
self.gui_elements.append(video_screen)
|
||||||
|
|
||||||
|
print(f"✅ 为 {parent_item.text(0)} 创建2D视频屏幕成功: {screen_name}")
|
||||||
|
|
||||||
|
# 在Qt树形控件中添加对应节点
|
||||||
|
qt_item = tree_widget.add_node_to_tree_widget(video_screen, parent_item, "GUI_2D_VIDEO_SCREEN")
|
||||||
|
if qt_item:
|
||||||
|
created_videoscreens.append((video_screen, qt_item))
|
||||||
|
else:
|
||||||
|
created_videoscreens.append((video_screen, None))
|
||||||
|
print("⚠️ Qt树节点添加失败,但Panda3D对象已创建")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 为 {parent_item.text(0)} 创建2D视频屏幕失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 处理创建结果
|
||||||
|
if not created_videoscreens:
|
||||||
|
print("❌ 没有成功创建任何2D视频屏幕")
|
||||||
|
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)
|
||||||
|
|
||||||
|
print(f"🎉 总共创建了 {len(created_videoscreens)} 个2D视频屏幕")
|
||||||
|
|
||||||
|
# 返回值处理
|
||||||
|
if len(created_videoscreens) == 1:
|
||||||
|
return created_videoscreens[0][0] # 单个屏幕返回NodePath
|
||||||
|
else:
|
||||||
|
return [screen_np for screen_np, _ in created_videoscreens] # 多个屏幕返回列表
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 创建2D视频屏幕过程失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load2DVideoFile(self, video_screen, video_path):
|
||||||
|
"""为2D视频屏幕加载新的视频文件"""
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
print(f"❌ 2D视频文件不存在: {video_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 加载新的视频纹理
|
||||||
|
movie_texture = self._loadMovieTexture(video_path)
|
||||||
|
if movie_texture:
|
||||||
|
# 应用纹理到2D视频屏幕
|
||||||
|
video_screen["frameTexture"] = movie_texture
|
||||||
|
|
||||||
|
# 保存视频纹理引用
|
||||||
|
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}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载2D视频文件失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _loadMovieTexture(self, video_path):
|
||||||
|
"""加载视频纹理的兼容方法"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Texture, MovieTexture
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 检查文件是否存在
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
print(f"❌ 视频文件不存在: {video_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"🔍 尝试加载视频文件: {video_path}")
|
||||||
|
|
||||||
|
# 方法1: 尝试使用 MovieTexture(专门用于视频)
|
||||||
|
try:
|
||||||
|
movie_texture = MovieTexture(video_path)
|
||||||
|
if movie_texture.read(video_path):
|
||||||
|
print("✅ 使用 MovieTexture 成功加载视频")
|
||||||
|
self._configureVideoTexture(movie_texture)
|
||||||
|
return movie_texture
|
||||||
|
else:
|
||||||
|
print("⚠️ MovieTexture.read() 返回失败")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ MovieTexture 方法失败: {e}")
|
||||||
|
|
||||||
|
# 方法2: 尝试使用 loader.loadTexture
|
||||||
|
try:
|
||||||
|
movie_texture = self.world.loader.loadTexture(video_path)
|
||||||
|
if movie_texture and hasattr(movie_texture, 'is_playable') and movie_texture.is_playable():
|
||||||
|
print("✅ 使用 loader.loadTexture 成功加载视频纹理")
|
||||||
|
self._configureVideoTexture(movie_texture)
|
||||||
|
return movie_texture
|
||||||
|
else:
|
||||||
|
print("⚠️ loader.loadTexture 加载的不是可播放的视频纹理")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ loader.loadTexture 方法失败: {e}")
|
||||||
|
|
||||||
|
# 方法3: 尝试使用 Texture.read(作为最后备选)
|
||||||
|
try:
|
||||||
|
texture = Texture()
|
||||||
|
if texture.read(video_path):
|
||||||
|
print("✅ 使用 Texture.read 成功加载(可能作为静态纹理)")
|
||||||
|
self._configureVideoTexture(texture)
|
||||||
|
return texture
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Texture.read 方法失败: {e}")
|
||||||
|
|
||||||
|
print("❌ 所有视频纹理加载方法都失败")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载视频纹理时发生未知错误: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def play2DVideo(self, video_screen):
|
||||||
|
"""播放2D视频"""
|
||||||
|
try:
|
||||||
|
# 获取视频纹理
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
|
||||||
|
# 备用获取方法
|
||||||
|
if not movie_texture:
|
||||||
|
# 尝试从frameTexture获取
|
||||||
|
if hasattr(video_screen, 'frameTexture'):
|
||||||
|
movie_texture = video_screen.frameTexture
|
||||||
|
|
||||||
|
if movie_texture and hasattr(movie_texture, 'play'):
|
||||||
|
try:
|
||||||
|
movie_texture.play()
|
||||||
|
print(f"▶️ 继续播放2D视频: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as play_error:
|
||||||
|
print(f"⚠️ 播放2D视频时出错: {play_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 2D视频屏幕没有可播放的视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 播放2D视频失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def pause2DVideo(self, video_screen):
|
||||||
|
"""暂停2D视频"""
|
||||||
|
try:
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
|
||||||
|
# 备用获取方法
|
||||||
|
if not movie_texture:
|
||||||
|
# 尝试从frameTexture获取
|
||||||
|
if hasattr(video_screen, 'frameTexture'):
|
||||||
|
movie_texture = video_screen.frameTexture
|
||||||
|
|
||||||
|
if movie_texture and hasattr(movie_texture, 'stop'): # MovieTexture使用stop来暂停
|
||||||
|
try:
|
||||||
|
movie_texture.stop()
|
||||||
|
print(f"⏸️ 2D视频已暂停: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as stop_error:
|
||||||
|
print(f"⚠️ 暂停2D视频时出错: {stop_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 2D视频屏幕没有可暂停的视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 暂停2D视频失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stop2DVideo(self, video_screen):
|
||||||
|
"""停止2D视频(回到开头)"""
|
||||||
|
try:
|
||||||
|
movie_texture = video_screen.getPythonTag("movie_texture")
|
||||||
|
|
||||||
|
# 备用获取方法
|
||||||
|
if not movie_texture:
|
||||||
|
# 尝试从frameTexture获取
|
||||||
|
if hasattr(video_screen, 'frameTexture'):
|
||||||
|
movie_texture = video_screen.frameTexture
|
||||||
|
|
||||||
|
if movie_texture:
|
||||||
|
try:
|
||||||
|
if hasattr(movie_texture, 'stop'):
|
||||||
|
movie_texture.stop()
|
||||||
|
# 重置到开头
|
||||||
|
if hasattr(movie_texture, 'setTime'):
|
||||||
|
movie_texture.setTime(0.0)
|
||||||
|
print(f"⏹️ 2D视频已停止: {video_screen.getName()}")
|
||||||
|
return True
|
||||||
|
except Exception as stop_error:
|
||||||
|
print(f"⚠️ 停止2D视频时出错: {stop_error}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 2D视频屏幕没有视频纹理: {video_screen.getName()}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 停止2D视频失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def createGUIVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
def createGUIVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
||||||
"""创建3D虚拟屏幕 - 支持多选创建,优化版本"""
|
"""创建3D虚拟屏幕 - 支持多选创建,优化版本"""
|
||||||
try:
|
try:
|
||||||
@ -1209,7 +2033,7 @@ class GUIManager:
|
|||||||
if hasattr(gui_element, 'getScale'):
|
if hasattr(gui_element, 'getScale'):
|
||||||
scale = gui_element.getScale()
|
scale = gui_element.getScale()
|
||||||
scaleEdit = QDoubleSpinBox()
|
scaleEdit = QDoubleSpinBox()
|
||||||
scaleEdit.setRange(0.01, 10)
|
scaleEdit.setRange(0.01, 100)
|
||||||
scaleEdit.setSingleStep(0.1)
|
scaleEdit.setSingleStep(0.1)
|
||||||
scaleEdit.setValue(scale.getX())
|
scaleEdit.setValue(scale.getX())
|
||||||
form.addRow("缩放:", scaleEdit)
|
form.addRow("缩放:", scaleEdit)
|
||||||
@ -1815,7 +2639,7 @@ class GUIManager:
|
|||||||
# 宽度控件
|
# 宽度控件
|
||||||
transform_layout.addWidget(QLabel("宽度"), 4, 0)
|
transform_layout.addWidget(QLabel("宽度"), 4, 0)
|
||||||
widthSpinBox = QDoubleSpinBox()
|
widthSpinBox = QDoubleSpinBox()
|
||||||
widthSpinBox.setRange(0.1, 10)
|
widthSpinBox.setRange(0.01, 100)
|
||||||
widthSpinBox.setSingleStep(0.1)
|
widthSpinBox.setSingleStep(0.1)
|
||||||
widthSpinBox.setValue(width)
|
widthSpinBox.setValue(width)
|
||||||
widthSpinBox.valueChanged.connect(
|
widthSpinBox.valueChanged.connect(
|
||||||
@ -1825,7 +2649,7 @@ class GUIManager:
|
|||||||
# 高度控件
|
# 高度控件
|
||||||
transform_layout.addWidget(QLabel("高度"), 4, 2)
|
transform_layout.addWidget(QLabel("高度"), 4, 2)
|
||||||
heightSpinBox = QDoubleSpinBox()
|
heightSpinBox = QDoubleSpinBox()
|
||||||
heightSpinBox.setRange(0.1, 10)
|
heightSpinBox.setRange(0.01, 100)
|
||||||
heightSpinBox.setSingleStep(0.1)
|
heightSpinBox.setSingleStep(0.1)
|
||||||
heightSpinBox.setValue(height)
|
heightSpinBox.setValue(height)
|
||||||
heightSpinBox.valueChanged.connect(
|
heightSpinBox.valueChanged.connect(
|
||||||
@ -1885,7 +2709,7 @@ class GUIManager:
|
|||||||
|
|
||||||
# 缩放数值输入框
|
# 缩放数值输入框
|
||||||
scale_x = QDoubleSpinBox()
|
scale_x = QDoubleSpinBox()
|
||||||
scale_x.setRange(0.01, 10)
|
scale_x.setRange(0.01, 100)
|
||||||
scale_x.setSingleStep(0.1)
|
scale_x.setSingleStep(0.1)
|
||||||
scale_x.setValue(
|
scale_x.setValue(
|
||||||
scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale, (tuple, list)) else scale)
|
scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale, (tuple, list)) else scale)
|
||||||
@ -1893,7 +2717,7 @@ class GUIManager:
|
|||||||
transform_layout.addWidget(scale_x, 3, 1)
|
transform_layout.addWidget(scale_x, 3, 1)
|
||||||
|
|
||||||
scale_y = QDoubleSpinBox()
|
scale_y = QDoubleSpinBox()
|
||||||
scale_y.setRange(0.01, 10)
|
scale_y.setRange(0.01, 100)
|
||||||
scale_y.setSingleStep(0.1)
|
scale_y.setSingleStep(0.1)
|
||||||
scale_y.setValue(
|
scale_y.setValue(
|
||||||
scale.getY() if hasattr(scale, 'getY') else scale[1] if isinstance(scale, (tuple, list)) and len(
|
scale.getY() if hasattr(scale, 'getY') else scale[1] if isinstance(scale, (tuple, list)) and len(
|
||||||
@ -1902,7 +2726,7 @@ class GUIManager:
|
|||||||
transform_layout.addWidget(scale_y, 3, 2)
|
transform_layout.addWidget(scale_y, 3, 2)
|
||||||
|
|
||||||
scale_z = QDoubleSpinBox()
|
scale_z = QDoubleSpinBox()
|
||||||
scale_z.setRange(0.01, 10)
|
scale_z.setRange(0.01, 100)
|
||||||
scale_z.setSingleStep(0.1)
|
scale_z.setSingleStep(0.1)
|
||||||
scale_z.setValue(
|
scale_z.setValue(
|
||||||
scale.getZ() if hasattr(scale, 'getZ') else scale[2] if isinstance(scale, (tuple, list)) and len(
|
scale.getZ() if hasattr(scale, 'getZ') else scale[2] if isinstance(scale, (tuple, list)) and len(
|
||||||
@ -1917,7 +2741,7 @@ class GUIManager:
|
|||||||
scale = gui_element.getScale()
|
scale = gui_element.getScale()
|
||||||
|
|
||||||
scaleSpinBox = QDoubleSpinBox()
|
scaleSpinBox = QDoubleSpinBox()
|
||||||
scaleSpinBox.setRange(0.01, 10)
|
scaleSpinBox.setRange(0.01, 100)
|
||||||
scaleSpinBox.setSingleStep(0.1)
|
scaleSpinBox.setSingleStep(0.1)
|
||||||
scaleSpinBox.setValue(scale.getX())
|
scaleSpinBox.setValue(scale.getX())
|
||||||
scaleSpinBox.valueChanged.connect(lambda v: self.editGUIElement(gui_element, "scale", v))
|
scaleSpinBox.valueChanged.connect(lambda v: self.editGUIElement(gui_element, "scale", v))
|
||||||
@ -2099,7 +2923,7 @@ class GUIManager:
|
|||||||
try:
|
try:
|
||||||
gui_type = gui_element.getTag("gui_type")
|
gui_type = gui_element.getTag("gui_type")
|
||||||
|
|
||||||
if gui_type in ["button", "label", "entry", "2d_image"]:
|
if gui_type in ["button", "label", "entry", "2d_image","2d_video_screen"]:
|
||||||
# 2D元素使用屏幕坐标,需要转换
|
# 2D元素使用屏幕坐标,需要转换
|
||||||
current_pos = gui_element.getPos()
|
current_pos = gui_element.getPos()
|
||||||
|
|
||||||
@ -2134,7 +2958,7 @@ class GUIManager:
|
|||||||
try:
|
try:
|
||||||
gui_type = gui_element.getTag("gui_type")
|
gui_type = gui_element.getTag("gui_type")
|
||||||
|
|
||||||
if gui_type in ["3d_text", "3d_image"]:
|
if gui_type in ["3d_text", "3d_image", "video_screen"]:
|
||||||
current_pos = gui_element.getPos()
|
current_pos = gui_element.getPos()
|
||||||
|
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
@ -2168,7 +2992,7 @@ class GUIManager:
|
|||||||
if value == 0:
|
if value == 0:
|
||||||
value = 0.01
|
value = 0.01
|
||||||
|
|
||||||
if gui_type in ["3d_text", "3d_image"]:
|
if gui_type in ["3d_text", "3d_image","video_screen","virtual_screen"]:
|
||||||
# 3D元素处理
|
# 3D元素处理
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
new_scale = (value, current_scale.getY(), current_scale.getZ())
|
new_scale = (value, current_scale.getY(), current_scale.getZ())
|
||||||
@ -2214,7 +3038,6 @@ class GUIManager:
|
|||||||
# 对于其他2D元素,使用统一缩放
|
# 对于其他2D元素,使用统一缩放
|
||||||
gui_element.setScale(value)
|
gui_element.setScale(value)
|
||||||
|
|
||||||
print(f"✓ 更新GUI元素缩放: {axis}={value}")
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"✗ 更新GUI元素缩放失败: {e}")
|
print(f"✗ 更新GUI元素缩放失败: {e}")
|
||||||
|
|||||||
8
main.py
8
main.py
@ -234,6 +234,14 @@ class MyWorld(CoreWorld):
|
|||||||
"""创建2D GUI图片"""
|
"""创建2D GUI图片"""
|
||||||
return self.gui_manager.createGUI2DImage(pos, image_path, size)
|
return self.gui_manager.createGUI2DImage(pos, image_path, size)
|
||||||
|
|
||||||
|
def createVideoScreen(self,pos=(0,0,0),size=1,video_path=None):
|
||||||
|
"""创建视频屏幕"""
|
||||||
|
return self.gui_manager.createVideoScreen(pos,size,video_path)
|
||||||
|
|
||||||
|
def create2DVideoScreen(self,pos=(0,0,0),size=0.2,video_path=None):
|
||||||
|
"""创建2D视频屏幕"""
|
||||||
|
return self.gui_manager.createGUI2DVideoScreen(pos,size,video_path)
|
||||||
|
|
||||||
def createSpotLight(self,pos=(0,0,5)):
|
def createSpotLight(self,pos=(0,0,5)):
|
||||||
"""创建聚光灯"""
|
"""创建聚光灯"""
|
||||||
return self.scene_manager.createSpotLight(pos)
|
return self.scene_manager.createSpotLight(pos)
|
||||||
|
|||||||
@ -404,6 +404,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.createImageAction = self.createGUIaddMenu.addAction('创建图片')
|
self.createImageAction = self.createGUIaddMenu.addAction('创建图片')
|
||||||
self.createGUIaddMenu.addSeparator()
|
self.createGUIaddMenu.addSeparator()
|
||||||
self.createVideoScreen = self.createGUIaddMenu.addAction('创建视频屏幕')
|
self.createVideoScreen = self.createGUIaddMenu.addAction('创建视频屏幕')
|
||||||
|
self.create2DVideoScreen = self.createGUIaddMenu.addAction('创建2D视频屏幕')
|
||||||
self.createSphericalVideo = self.createGUIaddMenu.addAction('创建球形视频')
|
self.createSphericalVideo = self.createGUIaddMenu.addAction('创建球形视频')
|
||||||
self.createGUIaddMenu.addSeparator()
|
self.createGUIaddMenu.addSeparator()
|
||||||
self.createVirtualScreenAction = self.createGUIaddMenu.addAction('创建虚拟屏幕')
|
self.createVirtualScreenAction = self.createGUIaddMenu.addAction('创建虚拟屏幕')
|
||||||
@ -426,7 +427,8 @@ class MainWindow(QMainWindow):
|
|||||||
self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
||||||
self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
||||||
self.createImageAction.triggered.connect(lambda: self.world.createGUI2DImage())
|
self.createImageAction.triggered.connect(lambda: self.world.createGUI2DImage())
|
||||||
# self.createVideoScreen.triggered.connect(self.world.createVideoScreen)
|
self.createVideoScreen.triggered.connect(self.world.createVideoScreen)
|
||||||
|
self.create2DVideoScreen.triggered.connect(self.world.create2DVideoScreen)
|
||||||
# self.createSphericalVideo.triggered.connect(self.world.createSphericalVideo)
|
# self.createSphericalVideo.triggered.connect(self.world.createSphericalVideo)
|
||||||
self.createVirtualScreenAction.triggered.connect(lambda: self.world.createGUIVirtualScreen())
|
self.createVirtualScreenAction.triggered.connect(lambda: self.world.createGUIVirtualScreen())
|
||||||
self.createSpotLightAction.triggered.connect(lambda :self.world.createSpotLight())
|
self.createSpotLightAction.triggered.connect(lambda :self.world.createSpotLight())
|
||||||
@ -451,6 +453,7 @@ class MainWindow(QMainWindow):
|
|||||||
'createEntry': self.createEntryAction,
|
'createEntry': self.createEntryAction,
|
||||||
'createImage': self.createImageAction,
|
'createImage': self.createImageAction,
|
||||||
'createVideoScreen': self.createVideoScreen,
|
'createVideoScreen': self.createVideoScreen,
|
||||||
|
'create2DVideoScreen':self.create2DVideoScreen,
|
||||||
'createSphericalVideo': self.createSphericalVideo,
|
'createSphericalVideo': self.createSphericalVideo,
|
||||||
'createVirtualScreen': self.createVirtualScreenAction,
|
'createVirtualScreen': self.createVirtualScreenAction,
|
||||||
'createSpotLight': self.createSpotLightAction,
|
'createSpotLight': self.createSpotLightAction,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from typing import Hashable
|
|||||||
|
|
||||||
from PyQt5.QtWidgets import (QLabel, QLineEdit, QDoubleSpinBox, QPushButton,
|
from PyQt5.QtWidgets import (QLabel, QLineEdit, QDoubleSpinBox, QPushButton,
|
||||||
QTreeWidget, QTreeWidgetItem, QMenu, QCheckBox, QComboBox, QHBoxLayout, QWidget,
|
QTreeWidget, QTreeWidgetItem, QMenu, QCheckBox, QComboBox, QHBoxLayout, QWidget,
|
||||||
QVBoxLayout, QGroupBox, QGridLayout, QSpinBox)
|
QVBoxLayout, QGroupBox, QGridLayout, QSpinBox, QFileDialog)
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from deploy_libs.unicodedata import normalize
|
from deploy_libs.unicodedata import normalize
|
||||||
from direct.actor.Actor import Actor
|
from direct.actor.Actor import Actor
|
||||||
@ -299,20 +299,20 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(self.pos_z,1,3)
|
transform_layout.addWidget(self.pos_z,1,3)
|
||||||
|
|
||||||
transform_layout.addWidget(QLabel("旋转"),2,0)
|
transform_layout.addWidget(QLabel("旋转"),2,0)
|
||||||
self.rot_h = QDoubleSpinBox()
|
self.rot_x = QDoubleSpinBox()
|
||||||
self.rot_p = QDoubleSpinBox()
|
self.rot_y = QDoubleSpinBox()
|
||||||
self.rot_r = QDoubleSpinBox()
|
self.rot_z = QDoubleSpinBox()
|
||||||
|
|
||||||
for rot_widget in [self.rot_h,self.rot_p,self.rot_r]:
|
for rot_widget in [self.rot_x,self.rot_y,self.rot_z]:
|
||||||
rot_widget.setRange(-360,360)
|
rot_widget.setRange(-360,360)
|
||||||
|
|
||||||
self.rot_h.setValue(terrain_node.getH())
|
self.rot_x.setValue(terrain_node.getH())
|
||||||
self.rot_p.setValue(terrain_node.getP())
|
self.rot_y.setValue(terrain_node.getP())
|
||||||
self.rot_r.setValue(terrain_node.getR())
|
self.rot_z.setValue(terrain_node.getR())
|
||||||
|
|
||||||
self.rot_h.valueChanged.connect(lambda v:terrain_node.setH(v))
|
self.rot_x.valueChanged.connect(lambda v:terrain_node.setH(v))
|
||||||
self.rot_p.valueChanged.connect(lambda v:terrain_node.setP(v))
|
self.rot_y.valueChanged.connect(lambda v:terrain_node.setP(v))
|
||||||
self.rot_r.valueChanged.connect(lambda v:terrain_node.setR(v))
|
self.rot_z.valueChanged.connect(lambda v:terrain_node.setR(v))
|
||||||
|
|
||||||
h_label = QLabel("H")
|
h_label = QLabel("H")
|
||||||
p_label = QLabel("P")
|
p_label = QLabel("P")
|
||||||
@ -324,9 +324,9 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(h_label,2,1)
|
transform_layout.addWidget(h_label,2,1)
|
||||||
transform_layout.addWidget(p_label,2,2)
|
transform_layout.addWidget(p_label,2,2)
|
||||||
transform_layout.addWidget(r_label,2,3)
|
transform_layout.addWidget(r_label,2,3)
|
||||||
transform_layout.addWidget(self.rot_h,3,1)
|
transform_layout.addWidget(self.rot_x,3,1)
|
||||||
transform_layout.addWidget(self.rot_p,3,2)
|
transform_layout.addWidget(self.rot_y,3,2)
|
||||||
transform_layout.addWidget(self.rot_r,3,3)
|
transform_layout.addWidget(self.rot_z,3,3)
|
||||||
|
|
||||||
transform_layout.addWidget(QLabel("缩放"),4,0)
|
transform_layout.addWidget(QLabel("缩放"),4,0)
|
||||||
self.scale_x = QDoubleSpinBox()
|
self.scale_x = QDoubleSpinBox()
|
||||||
@ -633,10 +633,16 @@ class PropertyPanelManager:
|
|||||||
self._safeUpdateSpinBox('pos_x', logical_x)
|
self._safeUpdateSpinBox('pos_x', logical_x)
|
||||||
self._safeUpdateSpinBox('pos_z', logical_z)
|
self._safeUpdateSpinBox('pos_z', logical_z)
|
||||||
else:
|
else:
|
||||||
# 3D GUI组件使用世界坐标
|
# 3D GUI组件使用世界坐标(包括 video_screen)
|
||||||
self._safeUpdateSpinBox('pos_x', pos.getX())
|
pos = gui_element.getPos()
|
||||||
self._safeUpdateSpinBox('pos_y', pos.getY())
|
|
||||||
self._safeUpdateSpinBox('pos_z', pos.getZ())
|
# 修复:确保 video_screen 也能正确更新位置控件
|
||||||
|
if hasattr(self, 'pos_x') and self.pos_x:
|
||||||
|
self._safeUpdateSpinBox('pos_x', pos.getX())
|
||||||
|
if hasattr(self, 'pos_y') and self.pos_y:
|
||||||
|
self._safeUpdateSpinBox('pos_y', pos.getY())
|
||||||
|
if hasattr(self, 'pos_z') and self.pos_z:
|
||||||
|
self._safeUpdateSpinBox('pos_z', pos.getZ())
|
||||||
|
|
||||||
# 更新缩放属性
|
# 更新缩放属性
|
||||||
if hasattr(self, 'scale_x') and self.scale_x:
|
if hasattr(self, 'scale_x') and self.scale_x:
|
||||||
@ -1107,22 +1113,22 @@ class PropertyPanelManager:
|
|||||||
|
|
||||||
# 旋转 (Rotation)
|
# 旋转 (Rotation)
|
||||||
transform_layout.addWidget(QLabel("旋转"), 4, 0)
|
transform_layout.addWidget(QLabel("旋转"), 4, 0)
|
||||||
self.rot_h = QDoubleSpinBox()
|
self.rot_x = QDoubleSpinBox()
|
||||||
self.rot_p = QDoubleSpinBox()
|
self.rot_y = QDoubleSpinBox()
|
||||||
self.rot_r = QDoubleSpinBox()
|
self.rot_z = QDoubleSpinBox()
|
||||||
|
|
||||||
# 设置旋转控件属性
|
# 设置旋转控件属性
|
||||||
for rot_widget in [self.rot_h, self.rot_p, self.rot_r]:
|
for rot_widget in [self.rot_x, self.rot_y, self.rot_z]:
|
||||||
rot_widget.setRange(-360, 360)
|
rot_widget.setRange(-360, 360)
|
||||||
|
|
||||||
self.rot_h.setValue(model.getH())
|
self.rot_x.setValue(model.getH())
|
||||||
self.rot_p.setValue(model.getP())
|
self.rot_y.setValue(model.getP())
|
||||||
self.rot_r.setValue(model.getR())
|
self.rot_z.setValue(model.getR())
|
||||||
|
|
||||||
# 连接旋转变化事件
|
# 连接旋转变化事件
|
||||||
self.rot_h.valueChanged.connect(lambda v: model.setH(v))
|
self.rot_x.valueChanged.connect(lambda v: model.setH(v))
|
||||||
self.rot_p.valueChanged.connect(lambda v: model.setP(v))
|
self.rot_y.valueChanged.connect(lambda v: model.setP(v))
|
||||||
self.rot_r.valueChanged.connect(lambda v: model.setR(v))
|
self.rot_z.valueChanged.connect(lambda v: model.setR(v))
|
||||||
|
|
||||||
# 创建并设置 H, P, R 标签居中
|
# 创建并设置 H, P, R 标签居中
|
||||||
h_label = QLabel("H")
|
h_label = QLabel("H")
|
||||||
@ -1135,9 +1141,9 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(h_label, 4, 1)
|
transform_layout.addWidget(h_label, 4, 1)
|
||||||
transform_layout.addWidget(p_label, 4, 2)
|
transform_layout.addWidget(p_label, 4, 2)
|
||||||
transform_layout.addWidget(r_label, 4, 3)
|
transform_layout.addWidget(r_label, 4, 3)
|
||||||
transform_layout.addWidget(self.rot_h, 5, 1)
|
transform_layout.addWidget(self.rot_x, 5, 1)
|
||||||
transform_layout.addWidget(self.rot_p, 5, 2)
|
transform_layout.addWidget(self.rot_y, 5, 2)
|
||||||
transform_layout.addWidget(self.rot_r, 5, 3)
|
transform_layout.addWidget(self.rot_z, 5, 3)
|
||||||
|
|
||||||
# 缩放 (Scale)
|
# 缩放 (Scale)
|
||||||
transform_layout.addWidget(QLabel("缩放"), 6, 0)
|
transform_layout.addWidget(QLabel("缩放"), 6, 0)
|
||||||
@ -1253,6 +1259,8 @@ class PropertyPanelManager:
|
|||||||
|
|
||||||
def updateGUIPropertyPanel(self, gui_element):
|
def updateGUIPropertyPanel(self, gui_element):
|
||||||
"""更新GUI元素属性面板"""
|
"""更新GUI元素属性面板"""
|
||||||
|
self.clearPropertyPanel()
|
||||||
|
|
||||||
gui_type = gui_element.getTag("gui_type")
|
gui_type = gui_element.getTag("gui_type")
|
||||||
gui_text = gui_element.getTag("gui_text")
|
gui_text = gui_element.getTag("gui_text")
|
||||||
|
|
||||||
@ -1289,7 +1297,7 @@ class PropertyPanelManager:
|
|||||||
# 变换属性组(合并位置和变换)
|
# 变换属性组(合并位置和变换)
|
||||||
if hasattr(gui_element, 'getPos'):
|
if hasattr(gui_element, 'getPos'):
|
||||||
# 根据GUI类型设置组名——
|
# 根据GUI类型设置组名——
|
||||||
if gui_type in ["button", "label", "entry","2d_image"]:
|
if gui_type in ["button", "label", "entry","2d_image","2d_video_screen"]:
|
||||||
transform_group = QGroupBox("变换 Rect Transform")
|
transform_group = QGroupBox("变换 Rect Transform")
|
||||||
else:
|
else:
|
||||||
transform_group = QGroupBox("变换 Transform")
|
transform_group = QGroupBox("变换 Transform")
|
||||||
@ -1299,7 +1307,7 @@ class PropertyPanelManager:
|
|||||||
pos = gui_element.getPos()
|
pos = gui_element.getPos()
|
||||||
|
|
||||||
# 根据GUI类型决定位置编辑方式
|
# 根据GUI类型决定位置编辑方式
|
||||||
if gui_type in ["button", "label", "entry","2d_image"]:
|
if gui_type in ["button", "label", "entry","2d_image","2d_video_screen"]:
|
||||||
# 2D GUI组件使用屏幕坐标
|
# 2D GUI组件使用屏幕坐标
|
||||||
logical_x = pos.getX() / 0.1 # 反向转换为逻辑坐标
|
logical_x = pos.getX() / 0.1 # 反向转换为逻辑坐标
|
||||||
logical_z = pos.getZ() / 0.1
|
logical_z = pos.getZ() / 0.1
|
||||||
@ -1317,14 +1325,13 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(z_label, 0, 2)
|
transform_layout.addWidget(z_label, 0, 2)
|
||||||
|
|
||||||
self.pos_x = QDoubleSpinBox()
|
self.pos_x = QDoubleSpinBox()
|
||||||
self.pos_x.setRange(-50, 50)
|
self.pos_x.setRange(-100, 100)
|
||||||
self.pos_x.setValue(logical_x)
|
self.pos_x.setValue(logical_x)
|
||||||
self.pos_x.valueChanged.connect(lambda v: self.world.gui_manager.editGUI2DPosition(gui_element, "x", v))
|
self.pos_x.valueChanged.connect(lambda v: self.world.gui_manager.editGUI2DPosition(gui_element, "x", v))
|
||||||
|
|
||||||
transform_layout.addWidget(self.pos_x, 1, 1)
|
transform_layout.addWidget(self.pos_x, 1, 1)
|
||||||
|
|
||||||
self.pos_z = QDoubleSpinBox()
|
self.pos_z = QDoubleSpinBox()
|
||||||
self.pos_z.setRange(-50, 50)
|
self.pos_z.setRange(-100, 100)
|
||||||
self.pos_z.setValue(logical_z)
|
self.pos_z.setValue(logical_z)
|
||||||
self.pos_z.valueChanged.connect(lambda v: self.world.gui_manager.editGUI2DPosition(gui_element, "z", v))
|
self.pos_z.valueChanged.connect(lambda v: self.world.gui_manager.editGUI2DPosition(gui_element, "z", v))
|
||||||
transform_layout.addWidget(self.pos_z, 1, 2)
|
transform_layout.addWidget(self.pos_z, 1, 2)
|
||||||
@ -1340,13 +1347,10 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(actualXLabel, 3, 1)
|
transform_layout.addWidget(actualXLabel, 3, 1)
|
||||||
transform_layout.addWidget(actualZLabel, 3, 2)
|
transform_layout.addWidget(actualZLabel, 3, 2)
|
||||||
|
|
||||||
if gui_type == "2d_image":
|
if gui_type in ["2d_image","2d_video_screen"]:
|
||||||
scale = gui_element.getScale()
|
scale = gui_element.getScale()
|
||||||
width = scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale,
|
width = scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale,(tuple, list)) else scale
|
||||||
(tuple, list)) else scale
|
height = scale.getZ() if hasattr(scale, 'getZ') else scale[1] if isinstance(scale,(tuple, list)) and len(scale) > 1 else scale
|
||||||
height = scale.getZ() if hasattr(scale, 'getZ') else scale[1] if isinstance(scale,
|
|
||||||
(tuple, list)) and len(
|
|
||||||
scale) > 1 else scale
|
|
||||||
|
|
||||||
transform_layout.addWidget(QLabel("宽度"),4,0)
|
transform_layout.addWidget(QLabel("宽度"),4,0)
|
||||||
self.scale_x = QDoubleSpinBox()
|
self.scale_x = QDoubleSpinBox()
|
||||||
@ -1426,7 +1430,7 @@ class PropertyPanelManager:
|
|||||||
|
|
||||||
# 缩放数值输入框
|
# 缩放数值输入框
|
||||||
self.scale_x = QDoubleSpinBox()
|
self.scale_x = QDoubleSpinBox()
|
||||||
self.scale_x.setRange(0.01, 10)
|
self.scale_x.setRange(0.01, 100)
|
||||||
self.scale_x.setSingleStep(0.1)
|
self.scale_x.setSingleStep(0.1)
|
||||||
self.scale_x.setValue(
|
self.scale_x.setValue(
|
||||||
scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale, (tuple, list)) else scale)
|
scale.getX() if hasattr(scale, 'getX') else scale[0] if isinstance(scale, (tuple, list)) else scale)
|
||||||
@ -1434,7 +1438,7 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(self.scale_x, 3, 1)
|
transform_layout.addWidget(self.scale_x, 3, 1)
|
||||||
|
|
||||||
self.scale_y = QDoubleSpinBox()
|
self.scale_y = QDoubleSpinBox()
|
||||||
self.scale_y.setRange(0.01, 10)
|
self.scale_y.setRange(0.01, 100)
|
||||||
self.scale_y.setSingleStep(0.1)
|
self.scale_y.setSingleStep(0.1)
|
||||||
self.scale_y.setValue(
|
self.scale_y.setValue(
|
||||||
scale.getY() if hasattr(scale, 'getY') else scale[1] if isinstance(scale, (tuple, list)) and len(
|
scale.getY() if hasattr(scale, 'getY') else scale[1] if isinstance(scale, (tuple, list)) and len(
|
||||||
@ -1443,7 +1447,7 @@ class PropertyPanelManager:
|
|||||||
transform_layout.addWidget(self.scale_y, 3, 2)
|
transform_layout.addWidget(self.scale_y, 3, 2)
|
||||||
|
|
||||||
self.scale_z = QDoubleSpinBox()
|
self.scale_z = QDoubleSpinBox()
|
||||||
self.scale_z.setRange(0.01, 10)
|
self.scale_z.setRange(0.01, 100)
|
||||||
self.scale_z.setSingleStep(0.1)
|
self.scale_z.setSingleStep(0.1)
|
||||||
self.scale_z.setValue(
|
self.scale_z.setValue(
|
||||||
scale.getZ() if hasattr(scale, 'getZ') else scale[2] if isinstance(scale, (tuple, list)) and len(
|
scale.getZ() if hasattr(scale, 'getZ') else scale[2] if isinstance(scale, (tuple, list)) and len(
|
||||||
@ -1455,8 +1459,8 @@ class PropertyPanelManager:
|
|||||||
transform_group.setLayout(transform_layout)
|
transform_group.setLayout(transform_layout)
|
||||||
self._propertyLayout.addWidget(transform_group)
|
self._propertyLayout.addWidget(transform_group)
|
||||||
|
|
||||||
# 为2D图像添加Sort属性
|
# 为2D图像和视频屏幕添加Sort属性
|
||||||
if gui_type == "2d_image":
|
if gui_type in ["2d_image","2d_video_screen"]:
|
||||||
sort_group = QGroupBox("显示顺序")
|
sort_group = QGroupBox("显示顺序")
|
||||||
sort_layout = QGridLayout()
|
sort_layout = QGridLayout()
|
||||||
|
|
||||||
@ -1474,17 +1478,13 @@ class PropertyPanelManager:
|
|||||||
gui_element.setTag("sort", str(value))
|
gui_element.setTag("sort", str(value))
|
||||||
# 应用sort到节点
|
# 应用sort到节点
|
||||||
gui_element.setBin("fixed", value)
|
gui_element.setBin("fixed", value)
|
||||||
print(f"✓ 更新2D图像渲染顺序: {value}")
|
print(f"✓ 更新{gui_type}渲染顺序: {value}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"✗ 更新2D图像渲染顺序失败: {e}")
|
print(f"✗ 更新{gui_type}渲染顺序失败: {e}")
|
||||||
|
|
||||||
sort_spin.valueChanged.connect(updateSort)
|
sort_spin.valueChanged.connect(updateSort)
|
||||||
sort_layout.addWidget(sort_spin, 0, 1)
|
sort_layout.addWidget(sort_spin, 0, 1)
|
||||||
|
|
||||||
# sort_help = QLabel("数值越小越先渲染\n负数在背景,正数在前景")
|
|
||||||
# sort_help.setStyleSheet("font-size: 10px; color: gray;")
|
|
||||||
# sort_layout.addWidget(sort_help, 1, 0, 1, 2)
|
|
||||||
|
|
||||||
sort_group.setLayout(sort_layout)
|
sort_group.setLayout(sort_layout)
|
||||||
self._propertyLayout.addWidget(sort_group)
|
self._propertyLayout.addWidget(sort_group)
|
||||||
|
|
||||||
@ -1570,9 +1570,9 @@ class PropertyPanelManager:
|
|||||||
|
|
||||||
# 显示当前贴图路径(简化显示)
|
# 显示当前贴图路径(简化显示)
|
||||||
current_texture_path = gui_element.getTag("texture_path") or gui_element.getTag("image_path") or "未设置"
|
current_texture_path = gui_element.getTag("texture_path") or gui_element.getTag("image_path") or "未设置"
|
||||||
#texture_label = QLabel(current_texture_path)
|
texture_label = QLabel(current_texture_path)
|
||||||
#texture_label.setWordWrap(True)
|
texture_label.setWordWrap(True)
|
||||||
#image_layout.addWidget(texture_label, 0, 1)
|
image_layout.addWidget(texture_label, 0, 1)
|
||||||
|
|
||||||
# 选择图片按钮
|
# 选择图片按钮
|
||||||
select_texture_button = QPushButton("选择图片...")
|
select_texture_button = QPushButton("选择图片...")
|
||||||
@ -1595,7 +1595,7 @@ class PropertyPanelManager:
|
|||||||
gui_element.setTag("texture_path", file_path)
|
gui_element.setTag("texture_path", file_path)
|
||||||
gui_element.setTag("image_path", file_path)
|
gui_element.setTag("image_path", file_path)
|
||||||
# 更新显示
|
# 更新显示
|
||||||
#texture_label.setText(file_path)
|
texture_label.setText(file_path)
|
||||||
# 可选:刷新场景树或其他 UI
|
# 可选:刷新场景树或其他 UI
|
||||||
# self.world.scene_manager.updateSceneTree()
|
# self.world.scene_manager.updateSceneTree()
|
||||||
|
|
||||||
@ -1605,6 +1605,12 @@ class PropertyPanelManager:
|
|||||||
self._propertyLayout.addWidget(image_group)
|
self._propertyLayout.addWidget(image_group)
|
||||||
|
|
||||||
# 添加弹性空间
|
# 添加弹性空间
|
||||||
|
|
||||||
|
if gui_type == "video_screen":
|
||||||
|
self._addVideoScreenProperties(gui_element)
|
||||||
|
if gui_type == "2d_video_screen":
|
||||||
|
self._add2DVideoScreenProperties(gui_element)
|
||||||
|
|
||||||
self._propertyLayout.addStretch()
|
self._propertyLayout.addStretch()
|
||||||
|
|
||||||
# 强制更新布局
|
# 强制更新布局
|
||||||
@ -1614,7 +1620,188 @@ class PropertyPanelManager:
|
|||||||
if propertyWidget:
|
if propertyWidget:
|
||||||
propertyWidget.update()
|
propertyWidget.update()
|
||||||
|
|
||||||
# 在gui_manager.py或其他相关文件中添加以下方法
|
def _add2DVideoScreenProperties(self, video_screen):
|
||||||
|
"""为2D视频屏幕添加属性控制面板"""
|
||||||
|
try:
|
||||||
|
from PyQt5.QtWidgets import (QGroupBox, QGridLayout, QPushButton, QLabel,
|
||||||
|
QFileDialog, QHBoxLayout)
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 视频信息组
|
||||||
|
video_info_group = QGroupBox("2D视频信息")
|
||||||
|
video_info_layout = QGridLayout()
|
||||||
|
|
||||||
|
# 显示当前视频文件路径
|
||||||
|
video_path = video_screen.getTag("video_path")
|
||||||
|
if video_path and os.path.exists(video_path):
|
||||||
|
video_info_layout.addWidget(QLabel("视频文件:"), 0, 0)
|
||||||
|
path_label = QLabel(os.path.basename(video_path))
|
||||||
|
path_label.setWordWrap(True)
|
||||||
|
path_label.setStyleSheet("color: #00AAFF;")
|
||||||
|
video_info_layout.addWidget(path_label, 0, 1)
|
||||||
|
else:
|
||||||
|
video_info_layout.addWidget(QLabel("状态:"), 0, 0)
|
||||||
|
status_label = QLabel("无视频文件" if not video_path else "文件不存在")
|
||||||
|
status_label.setStyleSheet("color: red;")
|
||||||
|
video_info_layout.addWidget(status_label, 0, 1)
|
||||||
|
video_screen.setBin("fixed",0)
|
||||||
|
|
||||||
|
video_info_group.setLayout(video_info_layout)
|
||||||
|
self._propertyLayout.addWidget(video_info_group)
|
||||||
|
|
||||||
|
# 视频控制组
|
||||||
|
video_control_group = QGroupBox("2D视频控制")
|
||||||
|
video_control_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# 播放按钮
|
||||||
|
play_btn = QPushButton("▶️ 播放")
|
||||||
|
play_btn.clicked.connect(lambda: self.world.gui_manager.play2DVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(play_btn)
|
||||||
|
|
||||||
|
# 暂停按钮
|
||||||
|
pause_btn = QPushButton("⏸️ 暂停")
|
||||||
|
pause_btn.clicked.connect(lambda: self.world.gui_manager.pause2DVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(pause_btn)
|
||||||
|
|
||||||
|
# 停止按钮
|
||||||
|
stop_btn = QPushButton("⏹️ 停止")
|
||||||
|
stop_btn.clicked.connect(lambda: self.world.gui_manager.stop2DVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(stop_btn)
|
||||||
|
|
||||||
|
video_control_group.setLayout(video_control_layout)
|
||||||
|
self._propertyLayout.addWidget(video_control_group)
|
||||||
|
|
||||||
|
# 加载新视频按钮
|
||||||
|
load_btn = QPushButton("📁 加载新视频...")
|
||||||
|
load_btn.clicked.connect(lambda: self._loadNew2DVideo(video_screen))
|
||||||
|
self._propertyLayout.addWidget(load_btn)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"添加2D视频屏幕属性失败: {e}")
|
||||||
|
|
||||||
|
def _loadNew2DVideo(self, video_screen):
|
||||||
|
"""为2D视频屏幕加载新视频文件"""
|
||||||
|
try:
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
|
None,
|
||||||
|
"选择视频文件",
|
||||||
|
"",
|
||||||
|
"视频文件 (*.mp4 *.avi *.mov *.mkv *.webm *.ogg)"
|
||||||
|
)
|
||||||
|
if file_path:
|
||||||
|
success = self.world.gui_manager.load2DVideoFile(video_screen, file_path)
|
||||||
|
if success:
|
||||||
|
print(f"成功加载新视频: {file_path}")
|
||||||
|
# 刷新属性面板以显示新视频信息
|
||||||
|
self.updateGUIPropertyPanel(video_screen)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"加载新视频失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def load2DVideoFile(self, video_screen, video_path):
|
||||||
|
"""为2D视频屏幕加载新的视频文件"""
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
print(f"❌ 2D视频文件不存在: {video_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 加载新的视频纹理
|
||||||
|
movie_texture = self._loadMovieTexture(video_path)
|
||||||
|
if movie_texture:
|
||||||
|
# 应用纹理到2D视频屏幕
|
||||||
|
video_screen["frameTexture"] = movie_texture
|
||||||
|
|
||||||
|
# 保存视频纹理引用
|
||||||
|
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}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载2D视频文件失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _addVideoScreenProperties(self,video_screen):
|
||||||
|
try:
|
||||||
|
from PyQt5.QtWidgets import (QGroupBox,QGridLayout,QPushButton,QLabel,QSlider,QFileDialog,QHBoxLayout,QCheckBox)
|
||||||
|
import os
|
||||||
|
|
||||||
|
video_info_group = QGroupBox("视频信息")
|
||||||
|
video_info_layout = QGridLayout()
|
||||||
|
|
||||||
|
video_path = video_screen.getTag("video_path")
|
||||||
|
if video_path and os.path.exists(video_path):
|
||||||
|
video_info_layout.addWidget(QLabel("视频文件:"),0,0)
|
||||||
|
path_label = QLabel(os.path.basename(video_path))
|
||||||
|
path_label.setWordWrap(True)
|
||||||
|
path_label.setStyleSheet("color:#00AAFF;")
|
||||||
|
video_info_layout.addWidget(path_label,0,1)
|
||||||
|
else:
|
||||||
|
video_info_layout.addWidget(QLabel("状态:"),0,0)
|
||||||
|
status_label = QLabel("无视频文件"if not video_path else "文件不存在")
|
||||||
|
status_label.setStyleSheet("color:red;")
|
||||||
|
video_info_layout.addWidget(status_label,0,1)
|
||||||
|
|
||||||
|
video_info_group.setLayout(video_info_layout)
|
||||||
|
self._propertyLayout.addWidget(video_info_group)
|
||||||
|
|
||||||
|
video_info_group.setLayout(video_info_layout)
|
||||||
|
self._propertyLayout.addWidget(video_info_group)
|
||||||
|
|
||||||
|
video_control_group = QGroupBox("视频控制")
|
||||||
|
video_control_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# 播放按钮
|
||||||
|
play_btn = QPushButton("▶️ 播放")
|
||||||
|
play_btn.clicked.connect(lambda: self.world.gui_manager.playVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(play_btn)
|
||||||
|
|
||||||
|
# 暂停按钮
|
||||||
|
pause_btn = QPushButton("⏸️ 暂停")
|
||||||
|
pause_btn.clicked.connect(lambda: self.world.gui_manager.pauseVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(pause_btn)
|
||||||
|
|
||||||
|
# 停止按钮
|
||||||
|
stop_btn = QPushButton("⏹️ 停止")
|
||||||
|
stop_btn.clicked.connect(lambda: self.world.gui_manager.stopVideo(video_screen))
|
||||||
|
video_control_layout.addWidget(stop_btn)
|
||||||
|
|
||||||
|
video_control_group.setLayout(video_control_layout)
|
||||||
|
self._propertyLayout.addWidget(video_control_group)
|
||||||
|
|
||||||
|
# 加载新视频按钮
|
||||||
|
load_btn = QPushButton("📁 加载新视频...")
|
||||||
|
load_btn.clicked.connect(lambda: self._loadNewVideo(video_screen))
|
||||||
|
self._propertyLayout.addWidget(load_btn)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"添加视频屏幕属性失败{e}")
|
||||||
|
|
||||||
|
def _loadNewVideo(self,video_screen):
|
||||||
|
try:
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
|
None,
|
||||||
|
"选择视频文件",
|
||||||
|
"",
|
||||||
|
"视频文件(*.mp4 *.avi *.mov *.mkv *.webm *.ogg)"
|
||||||
|
)
|
||||||
|
if file_path:
|
||||||
|
success = self.world.gui_manager.loadVideoFile(video_screen,file_path)
|
||||||
|
if success:
|
||||||
|
print(f"成功加载新视频{file_path}")
|
||||||
|
self.updateGUIPropertyPanel(video_screen)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"加载新视频失败{e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def editGUI2DPosition(self, gui_element, axis, value):
|
def editGUI2DPosition(self, gui_element, axis, value):
|
||||||
"""编辑2D GUI元素位置"""
|
"""编辑2D GUI元素位置"""
|
||||||
@ -1647,35 +1834,6 @@ class PropertyPanelManager:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def editGUI3DPosition(self, gui_element, axis, value):
|
|
||||||
"""编辑3D GUI元素位置"""
|
|
||||||
try:
|
|
||||||
gui_type = gui_element.getTag("gui_type")
|
|
||||||
|
|
||||||
if gui_type in ["3d_text", "3d_image"]:
|
|
||||||
current_pos = gui_element.getPos()
|
|
||||||
|
|
||||||
if axis == "x":
|
|
||||||
new_pos = (value, current_pos.getY(), current_pos.getZ())
|
|
||||||
elif axis == "y":
|
|
||||||
new_pos = (current_pos.getX(), value, current_pos.getZ())
|
|
||||||
elif axis == "z":
|
|
||||||
new_pos = (current_pos.getX(), current_pos.getY(), value)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
gui_element.setPos(*new_pos)
|
|
||||||
print(f"✓ 更新3D GUI元素位置: {axis}={value}")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"✗ 不支持的GUI类型进行3D位置编辑: {gui_type}")
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
print(f"✗ 更新3D GUI元素位置失败: {e}")
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def editGUIScale(self, gui_element, axis, value):
|
def editGUIScale(self, gui_element, axis, value):
|
||||||
"""编辑GUI元素缩放"""
|
"""编辑GUI元素缩放"""
|
||||||
try:
|
try:
|
||||||
@ -1686,7 +1844,7 @@ class PropertyPanelManager:
|
|||||||
if value == 0:
|
if value == 0:
|
||||||
value = 0.01
|
value = 0.01
|
||||||
|
|
||||||
if gui_type in ["3d_text", "3d_image","2d_image"]:
|
if gui_type in ["3d_text", "3d_image","2d_image","video_screen","2d_video_screen"]:
|
||||||
# 3D元素处理
|
# 3D元素处理
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
new_scale = (value, current_scale.getY(), current_scale.getZ())
|
new_scale = (value, current_scale.getY(), current_scale.getZ())
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user