From 944ee53d645091089e5ab217bf773089e57e0940 Mon Sep 17 00:00:00 2001
From: Hector <145347438+hudomn@users.noreply.github.com>
Date: Mon, 27 Oct 2025 17:56:46 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dwindows=E6=97=A0=E6=B3=95?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=9D=90=E6=A0=87=E8=BD=B4=E7=9A=84=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/EG.iml | 2 +-
.idea/misc.xml | 2 +-
QMeta3D/Helpers/Env_Grid_Maker.py | 8 -
QMeta3D/Helpers/__init__.py | 2 +-
QMeta3D/Meta3DWorld.py | 24 +--
QMeta3D/QMeta3DWidget.py | 145 +++---------------
QMeta3D/QMeta3D_Buttons_Translation.py | 9 --
QMeta3D/QMeta3D_Keys_Translation.py | 9 --
QMeta3D/QMeta3D_Modifiers_Translation.py | 9 --
QMeta3D/Tools/__init__.py | 2 +-
.../Tools/generate_qt_to_pd3d_translator.py | 8 +-
QMeta3D/__init__.py | 2 +-
core/selection.py | 47 +++---
core/world.py | 8 +-
14 files changed, 65 insertions(+), 212 deletions(-)
diff --git a/.idea/EG.iml b/.idea/EG.iml
index ba1e88cf..c608c0d0 100644
--- a/.idea/EG.iml
+++ b/.idea/EG.iml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index b4e62875..51b9fc17 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/QMeta3D/Helpers/Env_Grid_Maker.py b/QMeta3D/Helpers/Env_Grid_Maker.py
index 364abf05..a498611e 100644
--- a/QMeta3D/Helpers/Env_Grid_Maker.py
+++ b/QMeta3D/Helpers/Env_Grid_Maker.py
@@ -1,11 +1,3 @@
-# -*- coding: utf-8-*-
-"""
-Module : Env_Grid_Maker
-Author : Saifeddine ALOUI + code from Forklift 's code snippet could be found on panda3D's website
-Description :
- Creates a 3D implementation of grid that shows axes in 3 possible planes
-
-"""
from panda3d.core import *
from direct.interval.IntervalGlobal import *
diff --git a/QMeta3D/Helpers/__init__.py b/QMeta3D/Helpers/__init__.py
index fc125075..e58d61a7 100644
--- a/QMeta3D/Helpers/__init__.py
+++ b/QMeta3D/Helpers/__init__.py
@@ -1,2 +1,2 @@
-name="QPanda3D"
+name="QMeta3D"
__all__ = ["Env_Grid_Maker"]
\ No newline at end of file
diff --git a/QMeta3D/Meta3DWorld.py b/QMeta3D/Meta3DWorld.py
index f490791d..180a274e 100644
--- a/QMeta3D/Meta3DWorld.py
+++ b/QMeta3D/Meta3DWorld.py
@@ -1,10 +1,3 @@
-# -*- coding: utf-8-*-
-"""
-Module : Panda3DWorld
-Author : Saifeddine ALOUI
-Description :
- Inherit this object to create your custom world
-"""
import sys
import os
@@ -29,9 +22,6 @@ from PyQt5.QtWidgets import *
# Panda imports
from panda3d.core import *
-# from panda3d.core import loadPrcFileData
-# loadPrcFileData("", "window-type none") # Set Panda to draw its main window in an offscreen buffer
-from direct.showbase.DirectObject import DirectObject
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
# Set up Panda environment
@@ -49,12 +39,8 @@ import builtins
class Meta3DWorld(ShowBase):
- """
- Panda3DWorld : A class to handle all panda3D world manipulation
- """
-
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
- name="qpanda3D"):
+ name="qMeta3D"):
global _global_world_instance
global _global_render_pipeline
@@ -75,8 +61,8 @@ class Meta3DWorld(ShowBase):
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
loadPrcFileData("", "sync-video false") # 禁用默认VSync,让OpenVR控制
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
- loadPrcFileData("", "clock-mode non-real-time") # 禁用Panda3D帧率控制,让OpenVR控制
- # loadPrcFileData("", "gl-debug true") # 调试时可启用OpenGL调试
+ loadPrcFileData("", "clock-mode non-real-time")
+ # loadPrcFileData("", "gl-debug true")
if (is_fullscreen):
loadPrcFileData("", "fullscreen #t")
@@ -192,12 +178,10 @@ def get_render_pipeline():
"""获取全局 RenderPipeline 单例"""
if _global_render_pipeline is None:
raise RuntimeError(
- "RenderPipeline has not been initialized yet. Please create a Panda3DWorld instance first.")
+ "RenderPipeline has not been initialized yet. Please create a 3DWorld instance first.")
return _global_render_pipeline
def resize_buffer(self, width: int, height: int):
- """根据新窗口尺寸调整 Panda3D 渲染输出尺寸"""
- # 设置 Panda3D 的窗口尺寸(offscreen 模式下对应输出区域)
props = WindowProperties()
props.set_size(width, height)
self.win.request_properties(props)
diff --git a/QMeta3D/QMeta3DWidget.py b/QMeta3D/QMeta3DWidget.py
index 9262811c..a39e1869 100644
--- a/QMeta3D/QMeta3DWidget.py
+++ b/QMeta3D/QMeta3DWidget.py
@@ -1,23 +1,9 @@
-# -*- coding: utf-8-*-
-"""
-Module : QPanda3DWidget
-Author : Saifeddine ALOUI
-Description :
- This is the QWidget to be inserted in your standard PyQt5 application.
- It takes a Panda3DWorld object at init time.
- You should first create the Panda3DWorkd object before creating this widget.
-"""
-# PyQt imports
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from direct.task.TaskManagerGlobal import taskMgr
-# Panda imports
-from panda3d.core import Texture, WindowProperties, CallbackGraphicsWindow
-from panda3d.core import loadPrcFileData
-
from QMeta3D.QMeta3D_Buttons_Translation import QMeta3D_Button_translation
from QMeta3D.QMeta3D_Keys_Translation import QMeta3D_Key_translation
from QMeta3D.QMeta3D_Modifiers_Translation import QMeta3D_Modifier_translation
@@ -26,9 +12,9 @@ __all__ = ["QMeta3DWidget"]
class QMeta3DSynchronizer(QTimer):
- def __init__(self, qPanda3DWidget, FPS=60):
+ def __init__(self, qMeta3DWidget, FPS=60):
QTimer.__init__(self)
- self.qPanda3DWidget = qPanda3DWidget
+ self.qMeta3DWidget = qMeta3DWidget
dt = 1000 / FPS
self.setInterval(int(dt))
self.timeout.connect(self.tick)
@@ -40,7 +26,7 @@ class QMeta3DSynchronizer(QTimer):
TransformState.clear_cache()
taskMgr.step()
- self.qPanda3DWidget.update()
+ self.qMeta3DWidget.update()
except AssertionError as e:
# 专门处理 TransformState has_mat() 断言错误
if "has_mat" in str(e):
@@ -52,7 +38,7 @@ class QMeta3DSynchronizer(QTimer):
TransformState.clear_cache()
RenderState.clear_cache()
taskMgr.step()
- self.qPanda3DWidget.update()
+ self.qMeta3DWidget.update()
except:
pass
else:
@@ -84,19 +70,12 @@ def get_panda_key_modifiers_prefix(evt):
class QMeta3DWidget(QWidget):
- """
- An interactive panda3D QWidget
- Parent : Parent QT Widget
- FPS : Number of frames per socond to refresh the screen
- debug: Switch printing key events to console on/off
- """
-
- def __init__(self, panda3DWorld, parent=None, FPS=60, debug=False):
+ def __init__(self, Meta3DWorld, parent=None, FPS=60, debug=False):
QWidget.__init__(self, parent)
self.rp_sync_requested = False
# set fixed geometry
- self.panda3DWorld = panda3DWorld
- self.panda3DWorld.set_parent(self)
+ self.Meta3DWorld = Meta3DWorld
+ self.Meta3DWorld.set_parent(self)
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
# pandaTimer = QTimer(self)
# pandaTimer.timeout.connect()
@@ -114,7 +93,7 @@ class QMeta3DWidget(QWidget):
self.rotate.rotate(180)
self.out_image = QImage()
- size = self.panda3DWorld.cam.node().get_lens().get_film_size()
+ size = self.Meta3DWorld.cam.node().get_lens().get_film_size()
self.initial_film_size = QSizeF(size.x, size.y)
self.initial_size = self.size()
@@ -190,92 +169,14 @@ class QMeta3DWidget(QWidget):
#print(f"height:{height}")
from Meta3DWorld import resize_buffer
- #resize_buffer(width, height)
- lens = self.panda3DWorld.cam.node().get_lens()
- # lens.set_film_size(self.initial_film_size.width() * evt.size().width() / self.initial_size.width(),
- # self.initial_film_size.height() * evt.size().height() / self.initial_size.height())
- #self.sync_panda3d_window_size(width, height)
-
- #self.panda3DWorld.buff.setSize(evt.size().width(), evt.size().height())
+ lens = self.Meta3DWorld.cam.node().get_lens()
def minimumSizeHint(self):
return QSize(400, 300)
- # Use the paint event to pull the contents of the panda texture to the widget
- # def paintEvent(self, event):
- # if self.panda3DWorld.screenTexture.mightHaveRamImage():
- # tex = self.panda3DWorld.screenTexture
- # gsg = base.win.getGsg()
- # #self.panda3DWorld.screenTexture.store(gsg)
- # base.graphicsEngine.extractTextureData(tex, gsg)
- # self.panda3DWorld.screenTexture.setFormat(Texture.FRgba32)
- # data = self.panda3DWorld.screenTexture.getRamImage().getData()
- # img = QImage(data, self.panda3DWorld.screenTexture.getXSize(), self.panda3DWorld.screenTexture.getYSize(),
- # QImage.Format_ARGB32).mirrored()
- # self.paintSurface.begin(self)
- # self.paintSurface.drawImage(0, 0, img)
- # self.paintSurface.end()
-
- # def paintEvent(self, event):
- # tex = self.panda3DWorld.qt_output_tex
- #
- # gsg = base.win.getGsg()
- #
- #
- # if not self.rp_sync_requested:
- # base.graphicsEngine.extractTextureData(tex, gsg)
- # self.rp_sync_requested = True
- # self.update()
- # return
- #
- # if tex.hasRamImage():
- # data = tex.getRamImage().getData()
- # width = tex.getXSize()
- # height = tex.getYSize()
- #
- # # ✅ 应该 data 长度 = width * height * 4
- # img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
- #
- # painter = QPainter(self)
- # painter.drawImage(0, 0, img)
- # painter.end()
- #
- # self.rp_sync_requested = False
- # else:
- # print("⚠️ Texture has no RAM image yet, retrying next frame")
- # self.rp_sync_requested = False
- # self.update()
-
- # def paintEvent(self, event):
- # tex = self.panda3DWorld.qt_output_tex
- #
- # gsg = base.win.getGsg()
- #
- # if not tex.hasRamImage():
- # base.graphicsEngine.extractTextureData(tex, gsg)
- # self.update() # 请求下一帧更新
- # return
- #
- # data = tex.getRamImage().getData()
- # width = tex.getXSize()
- # height = tex.getYSize()
- # expected_len = width * height * 4
- #
- # if len(data) != expected_len:
- # print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
- # self.update()
- # return
- #
- # # 一切正常才绘制
- # img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
- #
- # painter = QPainter(self)
- # painter.drawImage(0, 0, img)
- # painter.end()
-
def paintEvent(self, event):
- tex = self.panda3DWorld.qt_output_tex
+ tex = self.Meta3DWorld.qt_output_tex
gsg = base.win.getGsg()
if not gsg:
@@ -314,8 +215,7 @@ class QMeta3DWidget(QWidget):
painter.drawImage(x_offset, y_offset, scaled_img)
painter.end()
- def sync_panda3d_window_size(self, width, height):
- """同步 Panda3D 窗口尺寸到 Qt 窗口尺寸"""
+ def sync_Meta3d_window_size(self, width, height):
try:
from panda3d.core import WindowProperties, LVecBase2i
@@ -328,28 +228,25 @@ class QMeta3DWidget(QWidget):
props.setSize(adjusted_width, adjusted_height)
# 对于 offscreen 渲染,直接更新窗口属性
- if self.panda3DWorld.win:
- self.panda3DWorld.win.request_properties(props)
+ if self.Meta3DWorld.win:
+ self.Meta3DWorld.win.request_properties(props)
# 手动触发 RenderPipeline 的尺寸更新逻辑
- if hasattr(self.panda3DWorld, 'render_pipeline'):
+ if hasattr(self.Meta3DWorld, 'render_pipeline'):
# 更新全局分辨率
from RenderPipelineFile.rpcore.globals import Globals
Globals.native_resolution = LVecBase2i(adjusted_width, adjusted_height)
# 重新计算渲染分辨率
- self.panda3DWorld.render_pipeline._compute_render_resolution()
+ self.Meta3DWorld.render_pipeline._compute_render_resolution()
# 通知各个管理器处理尺寸变化
- self.panda3DWorld.render_pipeline.light_mgr.compute_tile_size()
- self.panda3DWorld.render_pipeline.stage_mgr.handle_window_resize()
- if hasattr(self.panda3DWorld.render_pipeline, 'debugger'):
- self.panda3DWorld.render_pipeline.debugger.handle_window_resize()
+ self.Meta3DWorld.render_pipeline.light_mgr.compute_tile_size()
+ self.Meta3DWorld.render_pipeline.stage_mgr.handle_window_resize()
+ if hasattr(self.Meta3DWorld.render_pipeline, 'debugger'):
+ self.Meta3DWorld.render_pipeline.debugger.handle_window_resize()
# 触发插件的窗口尺寸变化钩子
- self.panda3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
-
- print(f"Panda3D 窗口尺寸已同步为: {adjusted_width} x {adjusted_height}")
-
+ self.Meta3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
except Exception as e:
- print(f"同步 Panda3D 窗口尺寸失败: {str(e)}")
\ No newline at end of file
+ print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")
\ No newline at end of file
diff --git a/QMeta3D/QMeta3D_Buttons_Translation.py b/QMeta3D/QMeta3D_Buttons_Translation.py
index e0ae0328..4a69d0d6 100644
--- a/QMeta3D/QMeta3D_Buttons_Translation.py
+++ b/QMeta3D/QMeta3D_Buttons_Translation.py
@@ -1,12 +1,3 @@
-# -*- coding: utf-8-*-
-"""
-Module : QPanda3D_Translation_Buttons
-Author : Niklas Mevenkamp
-Description :
- Contains a dictionary that translates QT mouse events to panda3d
- mouse events.
-"""
-# PyQt imports
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
diff --git a/QMeta3D/QMeta3D_Keys_Translation.py b/QMeta3D/QMeta3D_Keys_Translation.py
index b8a7dcc5..0b0c8dda 100644
--- a/QMeta3D/QMeta3D_Keys_Translation.py
+++ b/QMeta3D/QMeta3D_Keys_Translation.py
@@ -1,12 +1,3 @@
-# -*- coding: utf-8-*-
-"""
-Module : QPanda3D_Translation_Keys
-Author : Saifeddine ALOUI
-Description :
- Contains a dictionary that translates QT keyboard events to panda3d
- keyboard events.
-"""
-# PyQt imports
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
diff --git a/QMeta3D/QMeta3D_Modifiers_Translation.py b/QMeta3D/QMeta3D_Modifiers_Translation.py
index 40866ecf..17684818 100644
--- a/QMeta3D/QMeta3D_Modifiers_Translation.py
+++ b/QMeta3D/QMeta3D_Modifiers_Translation.py
@@ -1,12 +1,3 @@
-# -*- coding: utf-8-*-
-"""
-Module : QPanda3D_Translation_Modifiers
-Author : Niklas Mevenkamp
-Description :
- Contains a dictionary that translates QT keyboard events to panda3d
- keyboard events.
-"""
-# PyQt imports
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
diff --git a/QMeta3D/Tools/__init__.py b/QMeta3D/Tools/__init__.py
index c353614c..449353ac 100644
--- a/QMeta3D/Tools/__init__.py
+++ b/QMeta3D/Tools/__init__.py
@@ -1,2 +1,2 @@
-name="QPanda3D"
+name="QMeta3D"
__all__ = ["generate_qt_to_pd3d_translator"]
\ No newline at end of file
diff --git a/QMeta3D/Tools/generate_qt_to_pd3d_translator.py b/QMeta3D/Tools/generate_qt_to_pd3d_translator.py
index f167e513..3f296230 100644
--- a/QMeta3D/Tools/generate_qt_to_pd3d_translator.py
+++ b/QMeta3D/Tools/generate_qt_to_pd3d_translator.py
@@ -4,8 +4,8 @@ from PyQt5.QtWidgets import *
H=Qt.__dict__
lst = [a for a in H if a.startswith("Key_")]
-QPanda3D_Key_translation ="QPanda3D_Key_translation ={"
+QMeta3D_Key_translation = "QMeta3D_Key_translation ={"
for i in range(len(lst)):
- QPanda3D_Key_translation +="Qt.{}:'unknown',\n".format(lst[i])
-QPanda3D_Key_translation += "}"
-print(QPanda3D_Key_translation)
\ No newline at end of file
+ QMeta3D_Key_translation += "Qt.{}:'unknown',\n".format(lst[i])
+QMeta3D_Key_translation += "}"
+print(QMeta3D_Key_translation)
\ No newline at end of file
diff --git a/QMeta3D/__init__.py b/QMeta3D/__init__.py
index 5eac2f06..b94cb4e0 100644
--- a/QMeta3D/__init__.py
+++ b/QMeta3D/__init__.py
@@ -1,2 +1,2 @@
-name="QPanda3D"
+name="QMeta3D"
__all__ = ["QMeta3DWidget.py", "Meta3DWorld.py", "QMeta3D_Keys_Translation.py"]
\ No newline at end of file
diff --git a/core/selection.py b/core/selection.py
index 66295b8f..5d70c9d8 100644
--- a/core/selection.py
+++ b/core/selection.py
@@ -422,22 +422,26 @@ class SelectionSystem:
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
import os
+ from panda3d.core import getModelPath, Filename
+
+ # 获取项目根目录
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+ # 确保core目录在模型搜索路径中
+ model_path = getModelPath()
+ core_dir = os.path.join(base_dir, "core")
+ core_filename = Filename.from_os_specific(core_dir)
+ if not model_path.findFile(core_filename):
+ model_path.appendDirectory(core_filename)
+ print(f"✓ 添加core目录到模型搜索路径: {core_dir}")
if is_scale_tool:
- model_paths = [
- os.path.join(base_dir,"core/UniformScaleHandle.fbx"),
- ]
+ model_path = "core/UniformScaleHandle.fbx"
elif is_rotate_tool:
- model_paths = [
- os.path.join(base_dir,"core/RotationHandleQuarter.fbx"),
- ]
+ model_path = "core/RotationHandleQuarter.fbx"
+ arrow_path = "core/TranslateArrowHandle.fbx"
else:
- model_paths = [
- os.path.join(base_dir, "core/TranslateArrowHandle.fbx"),
- ]
-
- arrow_path = os.path.join(base_dir, "core/TranslateArrowHandle.fbx")
+ model_path = "core/TranslateArrowHandle.fbx"
# model_paths = [
# "core/TranslateArrowHandle.fbx",
@@ -445,18 +449,15 @@ class SelectionSystem:
# ]
gizmo_model = None
gizmoRot_model = None
- for path in model_paths:
- try:
- if is_rotate_tool:
- gizmo_model = self.world.loader.loadModel(arrow_path)
- gizmoRot_model = self.world.loader.loadModel(path)
- else:
- gizmo_model = self.world.loader.loadModel(path)
- if gizmo_model:
- #print(f"成功加载模型: {path}")
- break
- except:
- continue
+ try:
+ if is_rotate_tool:
+ gizmo_model = self.world.loader.loadModel(arrow_path)
+ gizmoRot_model = self.world.loader.loadModel(model_path)
+ else:
+ gizmo_model = self.world.loader.loadModel(model_path)
+ except Exception as e:
+ print(f"加载模型失败: {e}")
+ return
x_rHandle = None
y_rHandle = None
diff --git a/core/world.py b/core/world.py
index 72ad100e..c4ad9420 100644
--- a/core/world.py
+++ b/core/world.py
@@ -63,6 +63,13 @@ class CoreWorld(Meta3DWorld):
model_path.appendDirectory(resources_filename)
print(f"✓ 添加Resources到模型搜索路径: {resources_dir}")
+ # 添加core目录到搜索路径
+ core_dir = os.path.join(project_root, "core")
+ core_filename = Filename.from_os_specific(core_dir)
+ if not model_path.findFile(core_filename):
+ model_path.appendDirectory(core_filename)
+ print(f"✓ 添加core目录到模型搜索路径: {core_dir}")
+
# 同时添加各个子目录到搜索路径
subdirs = ['models', 'textures', 'animations', 'icons', 'materials']
for subdir in subdirs:
@@ -199,7 +206,6 @@ class CoreWorld(Meta3DWorld):
temp_anim.removeNode() # 清理临时动画
except Exception as e:
print(f"❌ 动画文件加载失败: {e}")
- return None
# 4. 尝试创建Actor
print(f"4. Actor创建测试:")