ui替换
This commit is contained in:
parent
69e2bda47e
commit
1fc3e154d1
@ -1,192 +1,188 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from core.CustomMouseController import CustomMouseController
|
from core.CustomMouseController import CustomMouseController
|
||||||
|
|
||||||
# 获取 RenderPipelineFile 的路径
|
# 获取 RenderPipelineFile 的路径
|
||||||
render_pipeline_path = './RenderPipelineFile'
|
render_pipeline_path = './RenderPipelineFile'
|
||||||
# 将该路径添加到 sys.path 中,确保 Python 能够找到它
|
# 将该路径添加到 sys.path 中,确保 Python 能够找到它
|
||||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, project_root)
|
sys.path.insert(0, project_root)
|
||||||
sys.path.insert(0, render_pipeline_path)
|
sys.path.insert(0, render_pipeline_path)
|
||||||
|
|
||||||
from RenderPipelineFile.rpcore import RenderPipeline
|
from RenderPipelineFile.rpcore import RenderPipeline
|
||||||
_global_render_pipeline = None
|
_global_render_pipeline = None
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
from panda3d.core import *
|
from panda3d.core import *
|
||||||
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
|
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
|
||||||
|
|
||||||
from direct.showbase.ShowBase import ShowBase
|
from direct.showbase.ShowBase import ShowBase
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
from QMeta3D.QMouseWatcherNode import QMouseWatcherNode
|
from QMeta3D.QMouseWatcherNode import QMouseWatcherNode
|
||||||
|
|
||||||
from RenderPipelineFile.rpcore.render_target import RenderTarget
|
from RenderPipelineFile.rpcore.render_target import RenderTarget
|
||||||
__all__ = ["Meta3DWorld"]
|
__all__ = ["Meta3DWorld"]
|
||||||
|
|
||||||
_global_world_instance=None
|
_global_world_instance=None
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
|
|
||||||
class Meta3DWorld(ShowBase):
|
class Meta3DWorld(ShowBase):
|
||||||
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
|
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
|
||||||
name="qMeta3D"):
|
name="qMeta3D"):
|
||||||
|
|
||||||
global _global_world_instance
|
global _global_world_instance
|
||||||
global _global_render_pipeline
|
global _global_render_pipeline
|
||||||
|
|
||||||
_global_world_instance = self
|
_global_world_instance = self
|
||||||
|
|
||||||
sort = -100
|
sort = -100
|
||||||
self.parent = None
|
self.parent = None
|
||||||
|
|
||||||
# 设置基本配置
|
# 设置基本配置
|
||||||
loadPrcFileData("", "show-frame-rate-meter 0")
|
loadPrcFileData("", "show-frame-rate-meter 0")
|
||||||
loadPrcFileData("", "window-type offscreen") # 设置为离屏渲染
|
loadPrcFileData("", "window-type onscreen") # 改为正常窗口渲染
|
||||||
loadPrcFileData("", f"win-size {width} {height}")
|
loadPrcFileData("", f"win-size {width} {height}")
|
||||||
loadPrcFileData("", "win-fixed-size #f") # 允许窗口调整大小
|
loadPrcFileData("", "win-fixed-size #f") # 允许窗口调整大小
|
||||||
|
|
||||||
# 🚀 VR性能优化配置
|
# 🚀 VR性能优化配置
|
||||||
loadPrcFileData("", "prefer-single-buffer true") # 减少缓冲区交换开销
|
loadPrcFileData("", "prefer-single-buffer true") # 减少缓冲区交换开销
|
||||||
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
|
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
|
||||||
loadPrcFileData("", "sync-video false") # 禁用默认VSync,让OpenVR控制
|
loadPrcFileData("", "sync-video false") # 禁用默认VSync,让OpenVR控制
|
||||||
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
|
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
|
||||||
loadPrcFileData("", "clock-mode non-real-time")
|
loadPrcFileData("", "clock-mode non-real-time")
|
||||||
# loadPrcFileData("", "gl-debug true")
|
# loadPrcFileData("", "gl-debug true")
|
||||||
|
|
||||||
if (is_fullscreen):
|
if (is_fullscreen):
|
||||||
loadPrcFileData("", "fullscreen #t")
|
loadPrcFileData("", "fullscreen #t")
|
||||||
|
|
||||||
self.render_pipeline = RenderPipeline()
|
self.render_pipeline = RenderPipeline()
|
||||||
self.render_pipeline.pre_showbase_init()
|
self.render_pipeline.pre_showbase_init()
|
||||||
|
|
||||||
ShowBase.__init__(self)
|
ShowBase.__init__(self)
|
||||||
|
|
||||||
# 初始化渲染管线并设置可调整大小的标志
|
# 初始化渲染管线并设置可调整大小的标志
|
||||||
self.render_pipeline.create(self)
|
self.render_pipeline.create(self)
|
||||||
_global_render_pipeline = self.render_pipeline
|
_global_render_pipeline = self.render_pipeline
|
||||||
|
|
||||||
# 创建 Qt 能读的 RGBA8 贴图
|
# 正常窗口渲染不需要额外的输出纹理
|
||||||
self.qt_output_tex = Texture("qt_output_tex")
|
# 注释掉离屏渲染相关的纹理创建
|
||||||
self.qt_output_tex.set_format(Texture.F_rgba8)
|
# self.qt_output_tex = Texture("qt_output_tex")
|
||||||
self.qt_output_tex.set_component_type(Texture.T_unsigned_byte)
|
# self.qt_output_tex.set_format(Texture.F_rgba8)
|
||||||
|
# self.qt_output_tex.set_component_type(Texture.T_unsigned_byte)
|
||||||
# # 获取图形管线对象
|
# self.win.add_render_texture(self.qt_output_tex, GraphicsOutput.RTM_copy_ram)
|
||||||
# gsg = self.win.getGsg()
|
|
||||||
# host = gsg.getEngine().getHost()
|
#self.screenTexture = Texture()
|
||||||
|
#self.screenTexture.setMinfilter(Texture.FTLinear)
|
||||||
self.win.add_render_texture(self.qt_output_tex, GraphicsOutput.RTM_copy_ram)
|
#self.screenTexture.setFormat(Texture.FRgba32)
|
||||||
|
#self.screenTexture.set_wrap_u(Texture.WM_clamp)
|
||||||
#self.screenTexture = Texture()
|
#self.screenTexture.set_wrap_v(Texture.WM_clamp)
|
||||||
#self.screenTexture.setMinfilter(Texture.FTLinear)
|
|
||||||
#self.screenTexture.setFormat(Texture.FRgba32)
|
# buff_size_x = int(self.win.get_x_size() * size)
|
||||||
#self.screenTexture.set_wrap_u(Texture.WM_clamp)
|
# buff_size_y = int(self.win.get_y_size() * size)
|
||||||
#self.screenTexture.set_wrap_v(Texture.WM_clamp)
|
# winprops = WindowProperties()
|
||||||
|
# winprops.set_size(buff_size_x, buff_size_y)
|
||||||
# buff_size_x = int(self.win.get_x_size() * size)
|
#
|
||||||
# buff_size_y = int(self.win.get_y_size() * size)
|
#
|
||||||
# winprops = WindowProperties()
|
# props = FrameBufferProperties()
|
||||||
# winprops.set_size(buff_size_x, buff_size_y)
|
# props.set_rgb_color(True)
|
||||||
#
|
# props.set_rgba_bits(8, 8, 8, 8)
|
||||||
#
|
# props.set_depth_bits(8)
|
||||||
# props = FrameBufferProperties()
|
|
||||||
# props.set_rgb_color(True)
|
# self.buff = self.graphicsEngine.make_output(
|
||||||
# props.set_rgba_bits(8, 8, 8, 8)
|
# self.pipe, name, sort,
|
||||||
# props.set_depth_bits(8)
|
# props, winprops,
|
||||||
|
# GraphicsPipe.BF_resizeable,
|
||||||
# self.buff = self.graphicsEngine.make_output(
|
# self.win.get_gsg(), self.win)
|
||||||
# self.pipe, name, sort,
|
|
||||||
# props, winprops,
|
#self.screenTexture = render_pipeline._final_stage.target.color_tex
|
||||||
# GraphicsPipe.BF_resizeable,
|
|
||||||
# self.win.get_gsg(), self.win)
|
#self.buff.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
|
||||||
|
# self.buff.set_sort(sort)
|
||||||
#self.screenTexture = render_pipeline._final_stage.target.color_tex
|
|
||||||
|
|
||||||
#self.buff.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
|
|
||||||
# self.buff.set_sort(sort)
|
#self.cam = self.makeCamera(self.buff)
|
||||||
|
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||||
|
|
||||||
|
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||||
#self.cam = self.makeCamera(self.buff)
|
|
||||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
#self.render_pipeline._showbase.camera.reparentTo(self.render)
|
||||||
|
#base.camera.reparentTo(self.render)
|
||||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
#self.cam.reparentTo(self.render) # 可选同步
|
||||||
|
|
||||||
#self.render_pipeline._showbase.camera.reparentTo(self.render)
|
#render_pipeline.set_camera(self.cam)
|
||||||
#base.camera.reparentTo(self.render)
|
|
||||||
#self.cam.reparentTo(self.render) # 可选同步
|
#添加渲染效果
|
||||||
|
#self.cam = self.render_pipeline._showbase.cam
|
||||||
#render_pipeline.set_camera(self.cam)
|
#self.camNode = self.cam.node()
|
||||||
|
#self.camLens = self.camNode.get_lens()
|
||||||
#添加渲染效果
|
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
||||||
#self.cam = self.render_pipeline._showbase.cam
|
#self.render_pipeline.daytime_mgr.update()
|
||||||
#self.camNode = self.cam.node()
|
|
||||||
#self.camLens = self.camNode.get_lens()
|
|
||||||
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
# if clear_color is None:
|
||||||
#self.render_pipeline.daytime_mgr.update()
|
# self.buff.set_clear_active(GraphicsOutput.RTPColor, False)
|
||||||
|
# else:
|
||||||
|
# self.buff.set_clear_color(clear_color)
|
||||||
# if clear_color is None:
|
# self.buff.set_clear_active(GraphicsOutput.RTPColor, True)
|
||||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, False)
|
|
||||||
# else:
|
# self.disableMouse()
|
||||||
# self.buff.set_clear_color(clear_color)
|
self.mouse_controller = CustomMouseController(self)
|
||||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, True)
|
self.mouse_controller.setUp()
|
||||||
|
|
||||||
# self.disableMouse()
|
# 添加错误处理钩子
|
||||||
self.mouse_controller = CustomMouseController(self)
|
self.accept("transform_state_error", self._handle_transform_error)
|
||||||
self.mouse_controller.setUp()
|
|
||||||
|
def _handle_transform_error(self):
|
||||||
# 添加错误处理钩子
|
"""处理TransformState相关的错误"""
|
||||||
self.accept("transform_state_error", self._handle_transform_error)
|
try:
|
||||||
|
from panda3d.core import TransformState, RenderState
|
||||||
def _handle_transform_error(self):
|
TransformState.clear_cache()
|
||||||
"""处理TransformState相关的错误"""
|
RenderState.clear_cache()
|
||||||
try:
|
print("已清理TransformState和RenderState缓存")
|
||||||
from panda3d.core import TransformState, RenderState
|
except Exception as e:
|
||||||
TransformState.clear_cache()
|
print(f"清理缓存时出错: {e}")
|
||||||
RenderState.clear_cache()
|
|
||||||
print("已清理TransformState和RenderState缓存")
|
def render_pipeline(self):
|
||||||
except Exception as e:
|
"""获取 RenderPipeline 实例"""
|
||||||
print(f"清理缓存时出错: {e}")
|
return self._render_pipeline
|
||||||
|
|
||||||
def render_pipeline(self):
|
|
||||||
"""获取 RenderPipeline 实例"""
|
def set_parent(self, parent: QWidget):
|
||||||
return self._render_pipeline
|
self.parent = parent
|
||||||
|
self.mouseWatcherNode = QMouseWatcherNode(parent)
|
||||||
|
|
||||||
def set_parent(self, parent: QWidget):
|
def getAspectRatio(self, win = None):
|
||||||
self.parent = parent
|
if win is None and self.parent is not None:
|
||||||
self.mouseWatcherNode = QMouseWatcherNode(parent)
|
return float(self.parent.width()) / float(self.parent.height())
|
||||||
|
else:
|
||||||
def getAspectRatio(self, win = None):
|
return super().getAspectRatio(win)
|
||||||
if win is None and self.parent is not None:
|
|
||||||
return float(self.parent.width()) / float(self.parent.height())
|
def get_render_pipeline():
|
||||||
else:
|
"""获取全局 RenderPipeline 单例"""
|
||||||
return super().getAspectRatio(win)
|
if _global_render_pipeline is None:
|
||||||
|
raise RuntimeError(
|
||||||
def get_render_pipeline():
|
"RenderPipeline has not been initialized yet. Please create a 3DWorld instance first.")
|
||||||
"""获取全局 RenderPipeline 单例"""
|
return _global_render_pipeline
|
||||||
if _global_render_pipeline is None:
|
|
||||||
raise RuntimeError(
|
def resize_buffer(self, width: int, height: int):
|
||||||
"RenderPipeline has not been initialized yet. Please create a 3DWorld instance first.")
|
props = WindowProperties()
|
||||||
return _global_render_pipeline
|
props.set_size(width, height)
|
||||||
|
self.win.request_properties(props)
|
||||||
def resize_buffer(self, width: int, height: int):
|
|
||||||
props = WindowProperties()
|
# 重新分配输出贴图的大小
|
||||||
props.set_size(width, height)
|
self.qt_output_tex.set_x_size(width)
|
||||||
self.win.request_properties(props)
|
self.qt_output_tex.set_y_size(height)
|
||||||
|
|
||||||
# 重新分配输出贴图的大小
|
# 更新 lens 的 aspect ratio
|
||||||
self.qt_output_tex.set_x_size(width)
|
if self.camLens:
|
||||||
self.qt_output_tex.set_y_size(height)
|
self.camLens.set_film_size(width, height) # 或 set_aspect_ratio(width / height)
|
||||||
|
|
||||||
# 更新 lens 的 aspect ratio
|
# 强制更新窗口(有时在 Qt 内嵌时需要)
|
||||||
if self.camLens:
|
|
||||||
self.camLens.set_film_size(width, height) # 或 set_aspect_ratio(width / height)
|
|
||||||
|
|
||||||
# 强制更新窗口(有时在 Qt 内嵌时需要)
|
|
||||||
self.graphicsEngine.open_windows()
|
self.graphicsEngine.open_windows()
|
||||||
@ -1,252 +1,236 @@
|
|||||||
from PyQt5 import QtWidgets, QtGui
|
from PyQt5 import QtWidgets, QtGui
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
from direct.task.TaskManagerGlobal import taskMgr
|
from direct.task.TaskManagerGlobal import taskMgr
|
||||||
|
|
||||||
from QMeta3D.QMeta3D_Buttons_Translation import QMeta3D_Button_translation
|
from QMeta3D.QMeta3D_Buttons_Translation import QMeta3D_Button_translation
|
||||||
from QMeta3D.QMeta3D_Keys_Translation import QMeta3D_Key_translation
|
from QMeta3D.QMeta3D_Keys_Translation import QMeta3D_Key_translation
|
||||||
from QMeta3D.QMeta3D_Modifiers_Translation import QMeta3D_Modifier_translation
|
from QMeta3D.QMeta3D_Modifiers_Translation import QMeta3D_Modifier_translation
|
||||||
|
|
||||||
__all__ = ["QMeta3DWidget"]
|
__all__ = ["QMeta3DWidget"]
|
||||||
|
|
||||||
|
|
||||||
class QMeta3DSynchronizer(QTimer):
|
class QMeta3DSynchronizer(QTimer):
|
||||||
def __init__(self, qMeta3DWidget, FPS=60):
|
def __init__(self, qMeta3DWidget, FPS=60):
|
||||||
QTimer.__init__(self)
|
QTimer.__init__(self)
|
||||||
self.qMeta3DWidget = qMeta3DWidget
|
self.qMeta3DWidget = qMeta3DWidget
|
||||||
dt = 1000 / FPS
|
dt = 1000 / FPS
|
||||||
self.setInterval(int(dt))
|
self.setInterval(int(dt))
|
||||||
self.timeout.connect(self.tick)
|
self.timeout.connect(self.tick)
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
try:
|
try:
|
||||||
# 在渲染前清理可能损坏的TransformState对象
|
# 在渲染前清理可能损坏的TransformState对象
|
||||||
from panda3d.core import TransformState
|
from panda3d.core import TransformState
|
||||||
TransformState.clear_cache()
|
TransformState.clear_cache()
|
||||||
|
|
||||||
taskMgr.step()
|
taskMgr.step()
|
||||||
self.qMeta3DWidget.update()
|
self.qMeta3DWidget.update()
|
||||||
except AssertionError as e:
|
except AssertionError as e:
|
||||||
# 专门处理 TransformState has_mat() 断言错误
|
# 专门处理 TransformState has_mat() 断言错误
|
||||||
if "has_mat" in str(e):
|
if "has_mat" in str(e):
|
||||||
print(f"警告: 检测到TransformState断言错误,已静默处理: {e}")
|
print(f"警告: 检测到TransformState断言错误,已静默处理: {e}")
|
||||||
# 尝试恢复渲染状态
|
# 尝试恢复渲染状态
|
||||||
try:
|
try:
|
||||||
# 强制清理缓存并重试
|
# 强制清理缓存并重试
|
||||||
from panda3d.core import TransformState, RenderState
|
from panda3d.core import TransformState, RenderState
|
||||||
TransformState.clear_cache()
|
TransformState.clear_cache()
|
||||||
RenderState.clear_cache()
|
RenderState.clear_cache()
|
||||||
taskMgr.step()
|
taskMgr.step()
|
||||||
self.qMeta3DWidget.update()
|
self.qMeta3DWidget.update()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# 重新抛出其他断言错误
|
# 重新抛出其他断言错误
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 静默处理其他所有异常
|
# 静默处理其他所有异常
|
||||||
print(f"警告: 检测到异常,已静默处理: {e}")
|
print(f"警告: 检测到异常,已静默处理: {e}")
|
||||||
|
|
||||||
|
|
||||||
def get_panda_key_modifiers(evt):
|
def get_panda_key_modifiers(evt):
|
||||||
panda_mods = []
|
panda_mods = []
|
||||||
qt_mods = evt.modifiers()
|
qt_mods = evt.modifiers()
|
||||||
for qt_mod, panda_mod in QMeta3D_Modifier_translation.items():
|
for qt_mod, panda_mod in QMeta3D_Modifier_translation.items():
|
||||||
if (qt_mods & qt_mod) == qt_mod:
|
if (qt_mods & qt_mod) == qt_mod:
|
||||||
panda_mods.append(panda_mod)
|
panda_mods.append(panda_mod)
|
||||||
return panda_mods
|
return panda_mods
|
||||||
|
|
||||||
|
|
||||||
def get_panda_key_modifiers_prefix(evt):
|
def get_panda_key_modifiers_prefix(evt):
|
||||||
# join all modifiers (except NoModifier, which is None) with '-'
|
# join all modifiers (except NoModifier, which is None) with '-'
|
||||||
prefix = "-".join([mod for mod in get_panda_key_modifiers(evt) if mod is not None])
|
prefix = "-".join([mod for mod in get_panda_key_modifiers(evt) if mod is not None])
|
||||||
|
|
||||||
# if the prefix is not empty, append a '-'
|
# if the prefix is not empty, append a '-'
|
||||||
if prefix:
|
if prefix:
|
||||||
prefix += '-'
|
prefix += '-'
|
||||||
|
|
||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
|
|
||||||
class QMeta3DWidget(QWidget):
|
class QMeta3DWidget(QWidget):
|
||||||
def __init__(self, Meta3DWorld, parent=None, FPS=60, debug=False):
|
def __init__(self, Meta3DWorld, parent=None, FPS=60, debug=False):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
self.rp_sync_requested = False
|
self.rp_sync_requested = False
|
||||||
# set fixed geometry
|
# set fixed geometry
|
||||||
self.Meta3DWorld = Meta3DWorld
|
self.Meta3DWorld = Meta3DWorld
|
||||||
self.Meta3DWorld.set_parent(self)
|
self.Meta3DWorld.set_parent(self)
|
||||||
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
|
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
|
||||||
# pandaTimer = QTimer(self)
|
# pandaTimer = QTimer(self)
|
||||||
# pandaTimer.timeout.connect()
|
# pandaTimer.timeout.connect()
|
||||||
# pandaTimer.start(0)
|
# pandaTimer.start(0)
|
||||||
|
|
||||||
self.setFocusPolicy(Qt.StrongFocus)
|
self.setFocusPolicy(Qt.StrongFocus)
|
||||||
|
|
||||||
# Setup another timer that redraws this widget in a specific FPS
|
# Setup another timer that redraws this widget in a specific FPS
|
||||||
# redrawTimer = QTimer(self)
|
# redrawTimer = QTimer(self)
|
||||||
# redrawTimer.timeout.connect(self.update)
|
# redrawTimer.timeout.connect(self.update)
|
||||||
# redrawTimer.start(1000/FPS)
|
# redrawTimer.start(1000/FPS)
|
||||||
|
|
||||||
self.paintSurface = QPainter()
|
self.paintSurface = QPainter()
|
||||||
self.rotate = QTransform()
|
self.rotate = QTransform()
|
||||||
self.rotate.rotate(180)
|
self.rotate.rotate(180)
|
||||||
self.out_image = QImage()
|
self.out_image = QImage()
|
||||||
|
|
||||||
size = self.Meta3DWorld.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_film_size = QSizeF(size.x, size.y)
|
||||||
self.initial_size = self.size()
|
self.initial_size = self.size()
|
||||||
|
|
||||||
self.synchronizer = QMeta3DSynchronizer(self, FPS)
|
self.synchronizer = QMeta3DSynchronizer(self, FPS)
|
||||||
self.synchronizer.start()
|
self.synchronizer.start()
|
||||||
|
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
def mousePressEvent(self, evt):
|
def mousePressEvent(self, evt):
|
||||||
button = evt.button()
|
button = evt.button()
|
||||||
try:
|
try:
|
||||||
b = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
b = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(b)
|
print(b)
|
||||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||||
except:
|
except:
|
||||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
def mouseMoveEvent(self, evt:QtGui.QMouseEvent):
|
def mouseMoveEvent(self, evt:QtGui.QMouseEvent):
|
||||||
button = evt.button()
|
button = evt.button()
|
||||||
try:
|
try:
|
||||||
b = "mouse-move"
|
b = "mouse-move"
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(b)
|
print(b)
|
||||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||||
except:
|
except:
|
||||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, evt):
|
def mouseReleaseEvent(self, evt):
|
||||||
button = evt.button()
|
button = evt.button()
|
||||||
try:
|
try:
|
||||||
b = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
b = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(b)
|
print(b)
|
||||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||||
except:
|
except:
|
||||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
def wheelEvent(self, evt):
|
def wheelEvent(self, evt):
|
||||||
delta = evt.angleDelta().y()
|
delta = evt.angleDelta().y()
|
||||||
try:
|
try:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(f"wheel {delta}")
|
print(f"wheel {delta}")
|
||||||
messenger.send('wheel',[{"delta":delta}])
|
messenger.send('wheel',[{"delta":delta}])
|
||||||
except:
|
except:
|
||||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
def keyPressEvent(self, evt):
|
def keyPressEvent(self, evt):
|
||||||
key = evt.key()
|
key = evt.key()
|
||||||
try:
|
try:
|
||||||
k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(k)
|
print(k)
|
||||||
messenger.send(k)
|
messenger.send(k)
|
||||||
except:
|
except:
|
||||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
def keyReleaseEvent(self, evt):
|
def keyReleaseEvent(self, evt):
|
||||||
key = evt.key()
|
key = evt.key()
|
||||||
try:
|
try:
|
||||||
k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(k)
|
print(k)
|
||||||
messenger.send(k)
|
messenger.send(k)
|
||||||
except:
|
except:
|
||||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||||
|
|
||||||
def resizeEvent(self, evt):
|
def resizeEvent(self, evt):
|
||||||
width = evt.size().width()
|
width = evt.size().width()
|
||||||
height = evt.size().height()
|
height = evt.size().height()
|
||||||
#print(f"width:{width}")
|
#print(f"width:{width}")
|
||||||
#print(f"height:{height}")
|
#print(f"height:{height}")
|
||||||
|
|
||||||
from Meta3DWorld import resize_buffer
|
from Meta3DWorld import resize_buffer
|
||||||
|
|
||||||
lens = self.Meta3DWorld.cam.node().get_lens()
|
lens = self.Meta3DWorld.cam.node().get_lens()
|
||||||
|
|
||||||
def minimumSizeHint(self):
|
def minimumSizeHint(self):
|
||||||
return QSize(400, 300)
|
return QSize(400, 300)
|
||||||
|
|
||||||
def paintEvent(self, event):
|
def paintEvent(self, event):
|
||||||
tex = self.Meta3DWorld.qt_output_tex
|
# 正常窗口渲染模式下,Panda3D 会直接渲染到窗口
|
||||||
gsg = base.win.getGsg()
|
# 不需要从纹理复制数据
|
||||||
|
# 只需要确保渲染循环继续运行
|
||||||
if not gsg:
|
|
||||||
self.update()
|
# 触发一次渲染更新
|
||||||
return
|
if hasattr(self.Meta3DWorld, 'win') and self.Meta3DWorld.win:
|
||||||
|
# 确保窗口大小匹配
|
||||||
if not tex.hasRamImage():
|
width = self.width()
|
||||||
base.graphicsEngine.extractTextureData(tex, gsg)
|
height = self.height()
|
||||||
self.update()
|
|
||||||
return
|
# 如果窗口大小不匹配,更新窗口属性
|
||||||
|
if (self.Meta3DWorld.win.get_x_size() != width or
|
||||||
data = tex.getRamImage().getData()
|
self.Meta3DWorld.win.get_y_size() != height):
|
||||||
tex_width = tex.getXSize()
|
from panda3d.core import WindowProperties
|
||||||
tex_height = tex.getYSize()
|
props = WindowProperties()
|
||||||
expected_len = tex_width * tex_height * 4
|
props.setSize(width, height)
|
||||||
|
self.Meta3DWorld.win.request_properties(props)
|
||||||
if len(data) != expected_len:
|
|
||||||
print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
|
# 继续下一次更新
|
||||||
self.update()
|
self.update()
|
||||||
return
|
|
||||||
|
def sync_Meta3d_window_size(self, width, height):
|
||||||
img = QImage(data, tex_width, tex_height, QImage.Format_ARGB32).mirrored()
|
try:
|
||||||
|
from panda3d.core import WindowProperties
|
||||||
widget_width = self.width()
|
|
||||||
widget_height = self.height()
|
# 更新窗口属性
|
||||||
|
props = WindowProperties()
|
||||||
painter = QPainter(self)
|
props.setSize(width, height)
|
||||||
|
|
||||||
# 【保持宽高比的缩放】
|
# 对于正常窗口渲染,直接更新窗口属性
|
||||||
scaled_img = img.scaled(widget_width, widget_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
if self.Meta3DWorld.win:
|
||||||
|
self.Meta3DWorld.win.request_properties(props)
|
||||||
# 居中绘制
|
|
||||||
x_offset = (widget_width - scaled_img.width()) // 2
|
# 如果使用 RenderPipeline,更新相关设置
|
||||||
y_offset = (widget_height - scaled_img.height()) // 2
|
if hasattr(self.Meta3DWorld, 'render_pipeline'):
|
||||||
|
try:
|
||||||
painter.drawImage(x_offset, y_offset, scaled_img)
|
from RenderPipelineFile.rpcore.globals import Globals
|
||||||
painter.end()
|
from panda3d.core import LVecBase2i
|
||||||
|
|
||||||
def sync_Meta3d_window_size(self, width, height):
|
# 更新全局分辨率
|
||||||
try:
|
Globals.native_resolution = LVecBase2i(width, height)
|
||||||
from panda3d.core import WindowProperties, LVecBase2i
|
|
||||||
|
# 重新计算渲染分辨率
|
||||||
# 确保尺寸是4的倍数(RenderPipeline 要求)
|
self.Meta3DWorld.render_pipeline._compute_render_resolution()
|
||||||
adjusted_width = width - width % 4
|
|
||||||
adjusted_height = height - height % 4
|
# 通知各个管理器处理尺寸变化
|
||||||
|
self.Meta3DWorld.render_pipeline.light_mgr.compute_tile_size()
|
||||||
# 更新窗口属性
|
self.Meta3DWorld.render_pipeline.stage_mgr.handle_window_resize()
|
||||||
props = WindowProperties()
|
|
||||||
props.setSize(adjusted_width, adjusted_height)
|
if hasattr(self.Meta3DWorld.render_pipeline, 'debugger'):
|
||||||
|
self.Meta3DWorld.render_pipeline.debugger.handle_window_resize()
|
||||||
# 对于 offscreen 渲染,直接更新窗口属性
|
|
||||||
if self.Meta3DWorld.win:
|
# 触发插件的窗口尺寸变化钩子
|
||||||
self.Meta3DWorld.win.request_properties(props)
|
self.Meta3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
|
||||||
|
except Exception as rp_e:
|
||||||
# 手动触发 RenderPipeline 的尺寸更新逻辑
|
print(f"RenderPipeline 尺寸更新失败: {rp_e}")
|
||||||
if hasattr(self.Meta3DWorld, 'render_pipeline'):
|
except Exception as e:
|
||||||
# 更新全局分辨率
|
|
||||||
from RenderPipelineFile.rpcore.globals import Globals
|
|
||||||
Globals.native_resolution = LVecBase2i(adjusted_width, adjusted_height)
|
|
||||||
|
|
||||||
# 重新计算渲染分辨率
|
|
||||||
self.Meta3DWorld.render_pipeline._compute_render_resolution()
|
|
||||||
|
|
||||||
# 通知各个管理器处理尺寸变化
|
|
||||||
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.Meta3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")
|
print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")
|
||||||
@ -199,11 +199,11 @@ class EmbeddedWebBrowser(QWidget):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# 设置标准输出编码为 UTF-8,避免 Windows GBK 编码问题
|
# 注释掉标准输出重定向,让输出正常显示在终端
|
||||||
if sys.platform == 'win32':
|
# if sys.platform == 'win32':
|
||||||
import io
|
# import io
|
||||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
# sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
# sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("[WebEngine] 启动独立 WebEngine 进程")
|
print("[WebEngine] 启动独立 WebEngine 进程")
|
||||||
|
|||||||
8619
ui/widgets.py
8619
ui/widgets.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user