diff --git a/config/vr_settings.json b/config/vr_settings.json index f65e22d1..3ff1646b 100644 --- a/config/vr_settings.json +++ b/config/vr_settings.json @@ -1,5 +1,5 @@ { - "render_mode": "normal", + "render_mode": "render_pipeline", "resolution_scale": 0.75, "pipeline_resolution_scale": 0.75, "quality_preset": "quality", @@ -13,6 +13,6 @@ "ao_quality": "low" }, "anti_aliasing": "4x", - "refresh_rate": "72Hz", + "refresh_rate": "144Hz", "async_reprojection": true } \ No newline at end of file diff --git a/core/vr_controller.py b/core/vr_controller.py index e293d07f..1b2af3f4 100644 --- a/core/vr_controller.py +++ b/core/vr_controller.py @@ -404,6 +404,34 @@ class VRController(DirectObject): except Exception as e: print(f"⚠️ 轴数据调试失败: {e}") + def recreate_visualizer(self): + """重新创建visualizer - 用于渲染模式切换后刷新 + + 当VR渲染模式在运行时改变时调用此方法,以确保visualizer + 使用正确的渲染设置(普通模式 vs RenderPipeline模式) + """ + # 清理旧visualizer + if self.visualizer: + try: + self.visualizer.cleanup() + self.visualizer = None + print(f"🧹 {self.name}手柄visualizer已清理") + except Exception as e: + print(f"⚠️ 清理{self.name}手柄visualizer失败: {e}") + + # 重新创建visualizer + if self.anchor_node: + self._create_visualizer() + if self.visualizer: + print(f"✨ {self.name}手柄visualizer已重建(使用当前渲染模式)") + return True + else: + print(f"❌ {self.name}手柄visualizer重建失败") + return False + else: + print(f"⚠️ {self.name}手柄anchor_node不存在,无法重建visualizer") + return False + def cleanup(self): """清理资源""" self.ignoreAll() diff --git a/core/vr_manager.py b/core/vr_manager.py index 49e34ac3..c08e3b55 100644 --- a/core/vr_manager.py +++ b/core/vr_manager.py @@ -567,19 +567,24 @@ class VRManager(DirectObject): self.game_poses = poses_t() # 游戏逻辑姿态(当前的) print("✓ VR渲染和游戏姿态数组已创建") - # 创建VR渲染缓冲区 - 根据渲染模式选择 - print(f"🎨 VR渲染模式: {self.vr_render_mode.value}") - if self.vr_render_mode == VRRenderMode.RENDER_PIPELINE: - if not self._create_vr_buffers_with_pipeline(): - print("⚠️ RenderPipeline模式创建失败,回退到普通渲染模式") - self.vr_render_mode = VRRenderMode.NORMAL - if not self._create_vr_buffers(): - print("❌ 创建VR渲染缓冲区失败") - return False + # 🔧 关键修复:统一初始化流程 + # 如果目标模式是RenderPipeline,先用普通模式初始化,然后切换 + # 这样两个场景都走相同的、已验证的代码路径 + target_render_mode = self.vr_render_mode + use_deferred_pipeline_switch = False + + if target_render_mode == VRRenderMode.RENDER_PIPELINE: + print("🎨 目标VR渲染模式: RenderPipeline") + print(" 策略:先用普通模式初始化,然后切换到RenderPipeline") + self.vr_render_mode = VRRenderMode.NORMAL + use_deferred_pipeline_switch = True else: - if not self._create_vr_buffers(): - print("❌ 创建VR渲染缓冲区失败") - return False + print(f"🎨 VR渲染模式: {self.vr_render_mode.value}") + + # 创建VR渲染缓冲区 - 始终用普通模式初始化 + if not self._create_vr_buffers(): + print("❌ 创建VR渲染缓冲区失败") + return False # 设置VR相机 if not self._setup_vr_cameras(): @@ -644,7 +649,18 @@ class VRManager(DirectObject): self._start_vr_task() self.vr_initialized = True - print("✅ VR系统初始化成功") + print("✅ VR系统初始化成功(普通模式)") + + # 🔧 关键修复:如果目标是RenderPipeline模式,现在切换过去 + # 这样场景2(先设RP再进VR)会走场景1(先VR再设RP)相同的代码路径 + if use_deferred_pipeline_switch: + print("\n🔄 现在切换到目标渲染模式: RenderPipeline") + print(" 这将触发buffer重建和visualizer刷新...") + if self.set_vr_render_mode(target_render_mode): + print("✅ 已成功切换到RenderPipeline模式") + else: + print("⚠️ 切换到RenderPipeline失败,保持普通模式") + return True except Exception as e: @@ -725,6 +741,13 @@ class VRManager(DirectObject): def _prepare_and_cache_textures(self): """准备纹理并缓存OpenGL ID - 解决重复准备问题""" try: + # 🔧 验证纹理对象存在 + if not self.vr_left_texture or not self.vr_right_texture: + print("❌ VR纹理对象不存在") + print(f" 左眼纹理: {self.vr_left_texture}") + print(f" 右眼纹理: {self.vr_right_texture}") + return False + # 获取graphics state guardian和prepared objects gsg = self.world.win.getGsg() if not gsg: @@ -737,32 +760,32 @@ class VRManager(DirectObject): return False # 准备左眼纹理并缓存ID - if self.vr_left_texture: - texture_context = self.vr_left_texture.prepareNow(0, prepared_objects, gsg) - if texture_context and hasattr(texture_context, 'getNativeId'): - self.left_texture_id = texture_context.getNativeId() - if self.left_texture_id > 0: - print(f" ✅ 左眼纹理准备完成 ({self.vr_render_mode.value}): ID={self.left_texture_id}") - else: - print(" ❌ 左眼纹理ID无效") - return False + print(f" 准备左眼纹理: {self.vr_left_texture.getXSize()}x{self.vr_left_texture.getYSize()}") + texture_context = self.vr_left_texture.prepareNow(0, prepared_objects, gsg) + if texture_context and hasattr(texture_context, 'getNativeId'): + self.left_texture_id = texture_context.getNativeId() + if self.left_texture_id > 0: + print(f" ✅ 左眼纹理准备完成 ({self.vr_render_mode.value}): ID={self.left_texture_id}") else: - print(" ❌ 左眼纹理准备失败") + print(" ❌ 左眼纹理ID无效") return False + else: + print(" ❌ 左眼纹理准备失败") + return False # 准备右眼纹理并缓存ID - if self.vr_right_texture: - texture_context = self.vr_right_texture.prepareNow(0, prepared_objects, gsg) - if texture_context and hasattr(texture_context, 'getNativeId'): - self.right_texture_id = texture_context.getNativeId() - if self.right_texture_id > 0: - print(f" ✅ 右眼纹理准备完成 ({self.vr_render_mode.value}): ID={self.right_texture_id}") - else: - print(" ❌ 右眼纹理ID无效") - return False + print(f" 准备右眼纹理: {self.vr_right_texture.getXSize()}x{self.vr_right_texture.getYSize()}") + texture_context = self.vr_right_texture.prepareNow(0, prepared_objects, gsg) + if texture_context and hasattr(texture_context, 'getNativeId'): + self.right_texture_id = texture_context.getNativeId() + if self.right_texture_id > 0: + print(f" ✅ 右眼纹理准备完成 ({self.vr_render_mode.value}): ID={self.right_texture_id}") else: - print(" ❌ 右眼纹理准备失败") + print(" ❌ 右眼纹理ID无效") return False + else: + print(" ❌ 右眼纹理准备失败") + return False # 标记纹理已准备 self.textures_prepared = True @@ -971,6 +994,13 @@ class VRManager(DirectObject): self.vr_left_eye_buffer = self.vr_pipeline_controller.get_left_buffer() self.vr_right_eye_buffer = self.vr_pipeline_controller.get_right_buffer() + # 🔧 关键修复:验证buffer有效性 + if not self.vr_left_eye_buffer or not self.vr_right_eye_buffer: + print("❌ VR Pipeline buffer创建失败") + print(f" 左眼buffer: {self.vr_left_eye_buffer}") + print(f" 右眼buffer: {self.vr_right_eye_buffer}") + return False + # 获取最终输出纹理(用于提交到OpenVR) left_textures = self.vr_pipeline_controller.get_left_textures() right_textures = self.vr_pipeline_controller.get_right_textures() @@ -998,10 +1028,26 @@ class VRManager(DirectObject): if self.vr_left_eye_buffer and self.vr_right_eye_buffer: print(" 设置RenderPipeline DisplayRegion回调...") try: + # 🔧 验证DisplayRegion数量 + left_dr_count = self.vr_left_eye_buffer.getNumDisplayRegions() + right_dr_count = self.vr_right_eye_buffer.getNumDisplayRegions() + + print(f" 左眼buffer DisplayRegion数量: {left_dr_count}") + print(f" 右眼buffer DisplayRegion数量: {right_dr_count}") + + if left_dr_count == 0 or right_dr_count == 0: + print(" ❌ DisplayRegion未创建,无法设置回调") + return False + # 获取RenderTarget创建的DisplayRegion left_dr = self.vr_left_eye_buffer.get_display_region(0) right_dr = self.vr_right_eye_buffer.get_display_region(0) + # 验证DisplayRegion有效性 + if not left_dr or not right_dr: + print(" ❌ DisplayRegion无效") + return False + # 设置渲染回调(与普通模式一致) left_dr.setDrawCallback(PythonCallbackObject(self.simple_left_cb)) right_dr.setDrawCallback(PythonCallbackObject(self.simple_right_cb)) @@ -1015,6 +1061,11 @@ class VRManager(DirectObject): print(f" ⚠️ 设置DisplayRegion回调失败: {e}") import traceback traceback.print_exc() + return False + + # 🔧 关键修复:强制同步GraphicsEngine,确保所有buffer完全初始化 + print(" 同步GraphicsEngine...") + self.world.graphicsEngine.renderFrame() # 准备纹理并缓存OpenGL ID if not self._prepare_and_cache_textures(): @@ -1779,6 +1830,22 @@ class VRManager(DirectObject): self.world.qtWidget.synchronizer.setInterval(int(1000/144)) print("✓ Qt Timer调整为144Hz,让OpenVR控制VR渲染节奏") + # 🔧 关键修复:检测并重建缺失的手柄visualizer + # 当渲染模式切换时,visualizer可能被清理但控制器对象仍存在 + if hasattr(self, 'left_controller') and self.left_controller: + if not self.left_controller.visualizer and self.left_controller.anchor_node: + print("🔧 检测到左手柄visualizer缺失,正在重建...") + self.left_controller._create_visualizer() + if self.left_controller.visualizer: + print("✅ 左手柄visualizer已重建") + + if hasattr(self, 'right_controller') and self.right_controller: + if not self.right_controller.visualizer and self.right_controller.anchor_node: + print("🔧 检测到右手柄visualizer缺失,正在重建...") + self.right_controller._create_visualizer() + if self.right_controller.visualizer: + print("✅ 右手柄visualizer已重建") + print("✅ VR模式已启用") return True @@ -1913,6 +1980,14 @@ class VRManager(DirectObject): print(" 重新启用VR...") self.enable_vr() + # 🔧 关键修复:重建所有手柄的visualizer以适配新渲染模式 + print(" 刷新手柄visualizer以适配新渲染模式...") + if hasattr(self, 'left_controller') and self.left_controller: + self.left_controller.recreate_visualizer() + + if hasattr(self, 'right_controller') and self.right_controller: + self.right_controller.recreate_visualizer() + print(f"✅ VR渲染模式已切换为 {self.vr_render_mode.value}") # 保存配置 diff --git a/core/vr_stages.py b/core/vr_stages.py index f027756b..060574f1 100644 --- a/core/vr_stages.py +++ b/core/vr_stages.py @@ -754,6 +754,16 @@ class VRPipelineController: return False self.left_gbuffer, self.left_lighting, self.left_ambient, self.left_final = result + # 🔧 关键修复:确保左眼buffer完全初始化后再创建右眼 + # 验证左眼buffer状态 + left_buffer = self.left_final.get_internal_buffer() if self.left_final else None + if not left_buffer: + print("❌ 左眼内部buffer无效") + self.cleanup_left() + return False + + print(" ✅ 左眼管线验证通过,准备创建右眼...") + # 创建右眼完整管线 result = self.create_eye_pipeline("Right", width, height, right_camera) if not all(result): diff --git a/core/vr_visualization.py b/core/vr_visualization.py index c331a299..678b5f4b 100644 --- a/core/vr_visualization.py +++ b/core/vr_visualization.py @@ -114,8 +114,8 @@ class VRControllerVisualizer: # 暂时注释身份标记功能,避免额外几何体造成悬空零件 # self._apply_controller_identity_marker(steamvr_model) - # 设置手柄始终显示在上层 - self._set_always_on_top(steamvr_model) + # 根据渲染模式设置渲染属性 + self._apply_render_mode_settings(steamvr_model) print(f"✅ {self.controller.name}手柄已加载SteamVR官方模型(缩放: 1.0,实体渲染模式)") else: @@ -363,6 +363,9 @@ class VRControllerVisualizer: trackpad_node.setColor(self.button_colors['trackpad']) trackpad_node.setMaterial(material) + # 应用渲染模式设置 + self._apply_render_mode_settings(self.model_node) + def _create_box_geometry(self, width, length, height): """创建立方体几何体""" # 创建顶点格式 @@ -683,8 +686,57 @@ class VRControllerVisualizer: self.ray_node.removeNode() self._create_interaction_ray() + def _apply_render_mode_settings(self, model_node): + """根据当前渲染模式应用渲染设置 + + Args: + model_node: 手柄模型节点 + """ + if not model_node: + return + + # 检测是否启用RenderPipeline模式 + is_render_pipeline = False + try: + # 通过VR管理器获取渲染模式 + vr_manager = self.controller.vr_manager + if hasattr(vr_manager, 'vr_render_mode'): + from core.vr_manager import VRRenderMode + is_render_pipeline = (vr_manager.vr_render_mode == VRRenderMode.RENDER_PIPELINE and + vr_manager.render_pipeline_enabled) + except Exception as e: + print(f"⚠️ 检测渲染模式失败: {e}") + + if is_render_pipeline: + # RenderPipeline模式:使用正常深度测试,添加着色器标签 + print(f"🎨 {self.controller.name}手柄:应用RenderPipeline渲染模式") + + # 设置着色器标签,使模型通过RenderPipeline的GBuffer渲染 + model_node.setTag("RenderPipeline", "1") + + # 使用正常的深度测试和深度写入 + model_node.setDepthTest(True) + model_node.setDepthWrite(True) + + # 设置合适的渲染bin(transparent bin用于透明度支持) + # 使用默认的opaque bin确保正常渲染 + model_node.clearBin() + + # 递归设置所有子节点 + for child in model_node.findAllMatches("**"): + child.setTag("RenderPipeline", "1") + child.setDepthTest(True) + child.setDepthWrite(True) + child.clearBin() + + print(f"✅ {self.controller.name}手柄已配置RenderPipeline渲染") + else: + # 普通模式:使用always-on-top设置 + print(f"🎨 {self.controller.name}手柄:应用普通渲染模式(always-on-top)") + self._set_always_on_top(model_node) + def _set_always_on_top(self, model_node): - """设置手柄模型始终显示在上层,不被其他物体遮挡""" + """设置手柄模型始终显示在上层,不被其他物体遮挡(仅普通渲染模式)""" if not model_node: return