This commit is contained in:
Rowland 2026-01-08 14:25:40 +08:00
parent 69e2bda47e
commit 1fc3e154d1
5 changed files with 5551 additions and 5573 deletions

View File

@ -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()

View File

@ -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)}")

1631
main.py

File diff suppressed because it is too large Load Diff

View File

@ -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 进程")

File diff suppressed because it is too large Load Diff