diff --git a/config/vr_settings.json b/config/vr_settings.json index 3ff1646b..902d31fb 100644 --- a/config/vr_settings.json +++ b/config/vr_settings.json @@ -11,8 +11,5 @@ "enable_ssr": false, "shadow_quality": "medium", "ao_quality": "low" - }, - "anti_aliasing": "4x", - "refresh_rate": "144Hz", - "async_reprojection": true + } } \ No newline at end of file diff --git a/core/vr_joystick_config.py b/core/vr_joystick_config.py index 13401e59..b8c24087 100644 --- a/core/vr_joystick_config.py +++ b/core/vr_joystick_config.py @@ -45,6 +45,7 @@ class VRJoystickConfig: self.teleport_arc_resolution = 50 # 抛物线精度 self.teleport_initial_velocity = 10.0 # 传送初始速度 self.min_teleport_distance = 1.0 # 最小传送距离 + self.player_height_offset = 1.7 # 玩家站立高度偏移(米) # 反馈设置 self.haptic_feedback_enabled = True # 是否启用震动反馈 @@ -151,6 +152,15 @@ class VRJoystickConfig: self.teleport_range = max(5.0, min(50.0, range_meters)) print(f"✓ 传送范围设置为: {self.teleport_range}米") + def set_player_height(self, height_meters: float): + """设置玩家站立高度偏移 + + Args: + height_meters: 站立高度偏移(米),推荐范围1.5-2.0米 + """ + self.player_height_offset = max(1.0, min(2.5, height_meters)) + print(f"✓ 玩家站立高度偏移设置为: {self.player_height_offset}米") + def enable_haptic_feedback(self, enabled: bool): """启用或禁用震动反馈 @@ -200,6 +210,7 @@ class VRJoystickConfig: teleport_sys.arc_resolution = self.teleport_arc_resolution teleport_sys.initial_velocity = self.teleport_initial_velocity teleport_sys.min_teleport_distance = self.min_teleport_distance + teleport_sys.player_height_offset = self.player_height_offset print("✅ 配置已成功应用到摇杆管理器") diff --git a/core/vr_manager.py b/core/vr_manager.py index c08e3b55..327a0bb5 100644 --- a/core/vr_manager.py +++ b/core/vr_manager.py @@ -913,6 +913,10 @@ class VRManager(DirectObject): self.render_pipeline_enabled = True print("✅ VR Pipeline控制器已初始化(将在相机设置时创建完整管线)") + + # 检查天空盒状态 + self._check_skybox_status() + return True except Exception as e: @@ -942,6 +946,130 @@ class VRManager(DirectObject): except Exception as e: print(f"⚠️ 应用RenderPipeline VR效果失败: {e}") + def _check_skybox_status(self): + """检查并报告天空盒状态""" + try: + print("\n🌌 检查天空盒状态...") + + # 方法1:在render节点下搜索所有名字包含skybox的节点 + skybox_nodes = self.world.render.findAllMatches("**/skybox*") + if skybox_nodes and skybox_nodes.getNumPaths() > 0: + print(f" ✓ 找到 {skybox_nodes.getNumPaths()} 个天空盒节点(使用名称搜索)") + for i in range(skybox_nodes.getNumPaths()): + skybox = skybox_nodes.getPath(i) + print(f" 天空盒 #{i+1}:") + print(f" 名称: {skybox.getName()}") + print(f" 位置: {skybox.getPos()}") + print(f" 缩放: {skybox.getScale()}") + print(f" 父节点: {skybox.getParent().getName()}") + + # 检查是否有shader + if skybox.hasShader(): + print(f" ✓ 已应用shader效果") + else: + print(f" ⚠️ 未应用shader效果") + + # 检查bin设置 + if skybox.hasBin(): + print(f" Bin: {skybox.getBinName()}") + else: + print(" ⚠️ 未找到天空盒(名称搜索)") + + # 方法2:搜索所有GeomNode(几何节点),天空盒通常是一个大的几何体 + print(" 搜索所有几何节点...") + all_geoms = self.world.render.findAllMatches("**/+GeomNode") + print(f" 找到 {all_geoms.getNumPaths()} 个几何节点") + + # 查找大型几何体(缩放值很大,可能是天空盒) + skybox_candidates = [] + for i in range(all_geoms.getNumPaths()): + geom_node = all_geoms.getPath(i) + scale = geom_node.getScale() + # 天空盒通常缩放很大(如40000) + if scale[0] > 1000 or scale[1] > 1000 or scale[2] > 1000: + print(f" ✓ 找到大型几何体(可能是天空盒):") + print(f" 名称: {geom_node.getName()}") + print(f" 缩放: {scale}") + print(f" 位置: {geom_node.getPos()}") + if geom_node.hasShader(): + print(f" ✓ 已应用shader") + skybox_candidates.append(geom_node) + + # 方法3:检查render节点的所有直接子节点(显示全部) + print(" 检查render的所有直接子节点...") + render_children = self.world.render.getChildren() + print(f" render有 {render_children.getNumPaths()} 个直接子节点:") + for i in range(render_children.getNumPaths()): + child = render_children.getPath(i) + scale = child.getScale() + # 标记大型节点(可能是天空盒) + if scale[0] > 1000 or scale[1] > 1000 or scale[2] > 1000: + print(f" - {child.getName()} ⭐ (大型节点,缩放: {scale})") + else: + print(f" - {child.getName()}") + + # 报告结果但不自动创建 + if len(skybox_candidates) == 0: + print(" ⚠️ 未找到明显的天空盒(缩放>1000的几何体)") + print(" 💡 RenderPipeline的天空盒可能在上述列表中,但缩放值不同") + print(" 💡 或者可能RenderPipeline未在VR模式下自动创建天空盒") + else: + print(f" ✓ 找到 {len(skybox_candidates)} 个可能的天空盒") + + print("🌌 天空盒状态检查完成\n") + + except Exception as e: + print(f"⚠️ 天空盒状态检查失败: {e}") + import traceback + traceback.print_exc() + + def _create_vr_skybox(self): + """为VR创建天空盒""" + try: + print(" 🎨 创建VR天空盒...") + + # 检查RenderPipeline是否可用 + if hasattr(self.world, 'render_pipeline') and self.world.render_pipeline: + pipeline = self.world.render_pipeline + + # 使用RenderPipeline的load_default_skybox方法 + print(" 使用RenderPipeline方法创建天空盒...") + skybox = pipeline.common_resources.load_default_skybox() + + if skybox: + # 设置天空盒属性 + skybox.set_scale(40000) # 大型缩放 + skybox.reparent_to(self.world.render) + skybox.set_bin("unsorted", 10000) # 最后渲染 + + # 应用天空盒shader效果 + pipeline.set_effect(skybox, "effects/skybox.yaml", { + "render_shadow": False, + "render_envmap": False, + "render_voxelize": False, + "alpha_testing": False, + "normal_mapping": False, + "parallax_mapping": False + }, 1000) + + print(f" ✅ VR天空盒已创建") + print(f" 名称: {skybox.getName()}") + print(f" 缩放: {skybox.getScale()}") + print(f" 位置: {skybox.getPos()}") + return skybox + else: + print(" ❌ 无法加载天空盒模型") + return None + else: + print(" ❌ RenderPipeline未初始化,无法创建天空盒") + return None + + except Exception as e: + print(f" ❌ 创建VR天空盒失败: {e}") + import traceback + traceback.print_exc() + return None + def _setup_vr_cameras(self): """设置VR相机 - 使用锚点层级系统""" try: diff --git a/core/vr_stages.py b/core/vr_stages.py index 060574f1..5ba80289 100644 --- a/core/vr_stages.py +++ b/core/vr_stages.py @@ -74,6 +74,29 @@ class VRGBufferStage: self.target.prepare_render(vr_camera) self._camera = vr_camera + # 🌌 关键修复:确保VR相机能看到天空盒 + # RenderPipeline的天空盒在render节点下,使用unsorted bin和shader effects + if self.target._source_region: + # 确保DisplayRegion支持所有bin排序 + self.target._source_region.setSort(20) # 设置合理的sort值 + print(f" ✓ DisplayRegion sort已设置") + + # 🔑 关键:设置VR相机的initial state为render的state + # 这样VR相机才能继承RenderPipeline应用在render节点上的所有shader effects(包括天空盒shader) + if vr_camera and vr_camera.node(): + # 使用Panda3D的内置render节点(通过builtins) + try: + from panda3d.core import NodePath + import builtins + if hasattr(builtins, 'render'): + render = builtins.render + vr_camera.node().setInitialState(render.getState()) + print(f" ✓ VR相机initial state已设置为render的state") + else: + print(f" ⚠️ builtins.render不存在,跳过initial state设置") + except Exception as e: + print(f" ⚠️ 设置VR相机initial state失败: {e}") + # 设置正常的背景色(与主窗口一致的天空色) if self.target.internal_buffer: buffer = self.target.internal_buffer diff --git a/core/vr_teleport.py b/core/vr_teleport.py index 25dd7b53..fc03757f 100644 --- a/core/vr_teleport.py +++ b/core/vr_teleport.py @@ -38,6 +38,7 @@ class VRTeleportSystem(DirectObject): self.gravity = -9.8 # 重力系数 self.initial_velocity = 10.0 # 初始速度 self.min_teleport_distance = 1.0 # 最小传送距离 + self.player_height_offset = 1.7 # 玩家站立高度偏移(米) # 可视化元素 self.teleport_arc_node = None # 抛物线节点 @@ -359,13 +360,23 @@ class VRTeleportSystem(DirectObject): # 计算传送偏移 if self.vr_manager.tracking_space: current_pos = self.vr_manager.tracking_space.getPos() - target_offset = self.teleport_target_pos - self.active_controller.get_world_position() - new_pos = current_pos + target_offset + + # 计算水平偏移(只考虑XY平面) + controller_pos = self.active_controller.get_world_position() + horizontal_offset = Vec3( + self.teleport_target_pos.x - controller_pos.x, + self.teleport_target_pos.y - controller_pos.y, + 0 + ) + + # 计算新位置:保持水平偏移,设置固定站立高度 + new_pos = current_pos + horizontal_offset + new_pos.z = self.teleport_target_pos.z + self.player_height_offset # 执行传送 self.vr_manager.tracking_space.setPos(new_pos) - print(f"✅ 传送成功: {current_pos} → {new_pos}") + print(f"✅ 传送成功: {current_pos} → {new_pos} (高度偏移: {self.player_height_offset}m)") # 停止预览 self.stop_teleport_preview()