修复windows无法显示坐标轴的问题
This commit is contained in:
parent
6540870d7e
commit
944ee53d64
2
.idea/EG.iml
generated
2
.idea/EG.iml
generated
@ -5,7 +5,7 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.12 virtualenv at ~/EG/venv" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (EG)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -3,5 +3,5 @@
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (PythonProject)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 virtualenv at ~/EG/venv" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (EG)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@ -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 *
|
||||
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
name="QPanda3D"
|
||||
name="QMeta3D"
|
||||
__all__ = ["Env_Grid_Maker"]
|
||||
@ -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)
|
||||
|
||||
@ -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)}")
|
||||
print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")
|
||||
@ -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 *
|
||||
|
||||
@ -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 *
|
||||
|
||||
@ -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 *
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
name="QPanda3D"
|
||||
name="QMeta3D"
|
||||
__all__ = ["generate_qt_to_pd3d_translator"]
|
||||
@ -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)
|
||||
QMeta3D_Key_translation += "Qt.{}:'unknown',\n".format(lst[i])
|
||||
QMeta3D_Key_translation += "}"
|
||||
print(QMeta3D_Key_translation)
|
||||
@ -1,2 +1,2 @@
|
||||
name="QPanda3D"
|
||||
name="QMeta3D"
|
||||
__all__ = ["QMeta3DWidget.py", "Meta3DWorld.py", "QMeta3D_Keys_Translation.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
|
||||
|
||||
@ -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创建测试:")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user