import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) from panda3d.core import * from direct.showbase.DirectObject import DirectObject from direct.task import Task import sys class VRManager(DirectObject): """VR管理器 - 处理VR系统初始化、追踪和渲染""" def __init__(self, world): super().__init__() self.world = world self.vr_enabled = False self.vr_system = None self.vr_compositor = None self.render_width = 1920 self.render_height = 1080 self.alvr_enabled = False # 模拟模式设置 self.simulation_mode = False self.simulation_data = { 'head_pose': {'position': [0, 0, 1.6], 'rotation': [0, 0, 0, 1]}, 'controller_poses': { 0: {'position': [-0.3, 0, 1.2], 'rotation': [0, 0, 0, 1], 'connected': True}, 1: {'position': [0.3, 0, 1.2], 'rotation': [0, 0, 0, 1], 'connected': True} }, 'render_size': (1920, 1080) } # 立体渲染缓冲区 self.left_eye_buffer = None self.right_eye_buffer = None self.left_eye_camera = None self.right_eye_camera = None # 控制器相关 self.controller_nodes = {} self.controller_poses = {} print("✓ VR管理器初始化完成") def initialize_vr(self, force_simulation=False): """初始化VR系统""" try: # 检查是否强制使用模拟模式 if force_simulation: print("🔧 强制启用VR模拟模式") return self._init_simulation_mode() # 检查OpenVR支持 if not self._check_openvr_support(): print("⚠ OpenVR支持不可用,切换到模拟模式") return self._init_simulation_mode() # 尝试初始化OpenVR if not self._init_openvr(): print("⚠ OpenVR初始化失败,切换到模拟模式") print("提示: 请确保SteamVR正在运行且VR头盔已连接") return self._init_simulation_mode() # 真实VR模式初始化成功 print("✓ 真实VR模式初始化成功") return self._init_real_vr_mode() except Exception as e: print(f"VR初始化错误: {str(e)}") print("⚠ 切换到模拟模式") return self._init_simulation_mode() def _init_simulation_mode(self): """初始化模拟模式""" try: self.simulation_mode = True # 使用模拟数据设置渲染尺寸 self.render_width, self.render_height = self.simulation_data['render_size'] print(f"🎮 模拟VR渲染尺寸: {self.render_width}x{self.render_height}") # 设置模拟立体渲染 self._setup_stereo_rendering() # 启动模拟VR任务 self._start_simulation_tasks() self.vr_enabled = True print("✓ VR模拟模式初始化完成") print("ℹ 模拟模式说明:") print(" - 头盔追踪: 模拟数据") print(" - 控制器: 模拟两个控制器") print(" - 渲染: 立体渲染到窗口") print(" - 交互: 键盘鼠标模拟") return True except Exception as e: print(f"模拟模式初始化错误: {str(e)}") return False def _init_real_vr_mode(self): """初始化真实VR模式""" try: self.simulation_mode = False # 设置立体渲染 self._setup_stereo_rendering() # 初始化ALVR if self._init_alvr(): print("✓ ALVR串流已启用") self.alvr_enabled = True # 启动VR更新任务 self._start_vr_tasks() self.vr_enabled = True print("✓ 真实VR系统初始化完成") return True except Exception as e: print(f"真实VR模式初始化错误: {str(e)}") return False def _check_openvr_support(self): """检查OpenVR支持""" try: import openvr return True except ImportError: print("OpenVR库未安装") return False def _init_openvr(self): """初始化OpenVR""" try: import openvr # 初始化OpenVR self.vr_system = openvr.init(openvr.VRApplication_Scene) if not self.vr_system: return False # 获取合成器 self.vr_compositor = openvr.VRCompositor() if not self.vr_compositor: return False # 获取推荐的渲染尺寸 self.render_width, self.render_height = self.vr_system.getRecommendedRenderTargetSize() print(f"VR推荐渲染尺寸: {self.render_width}x{self.render_height}") return True except Exception as e: print(f"OpenVR初始化错误: {str(e)}") return False def _setup_stereo_rendering(self): """设置立体渲染""" try: # 创建眼部缓冲区 self._create_eye_buffers() # 创建眼部摄像机 self._create_eye_cameras() # 设置渲染目标 self._setup_render_targets() print("✓ 立体渲染设置完成") except Exception as e: print(f"立体渲染设置错误: {str(e)}") def _create_eye_buffers(self): """创建眼部渲染缓冲区""" try: # 创建左眼缓冲区 self.left_eye_buffer = self.world.win.makeTextureBuffer( "left_eye", self.render_width, self.render_height ) self.left_eye_buffer.setSort(-100) # 创建右眼缓冲区 self.right_eye_buffer = self.world.win.makeTextureBuffer( "right_eye", self.render_width, self.render_height ) self.right_eye_buffer.setSort(-99) # 获取纹理 self.left_eye_texture = self.left_eye_buffer.getTexture() self.right_eye_texture = self.right_eye_buffer.getTexture() print("✓ 眼部渲染缓冲区创建完成") except Exception as e: print(f"眼部缓冲区创建错误: {str(e)}") def _create_eye_cameras(self): """创建眼部摄像机""" try: # 创建左眼摄像机 self.left_eye_camera = self.world.makeCamera(self.left_eye_buffer) self.left_eye_camera.setPos(-0.032, 0, 0) # 瞳距的一半 # 创建右眼摄像机 self.right_eye_camera = self.world.makeCamera(self.right_eye_buffer) self.right_eye_camera.setPos(0.032, 0, 0) # 瞳距的一半 # 设置投影矩阵 if not self.simulation_mode: self._update_eye_projection(0, self.left_eye_camera.node().getLens()) self._update_eye_projection(1, self.right_eye_camera.node().getLens()) else: # 模拟模式使用标准透视投影 lens = PerspectiveLens() lens.setFov(110) # 模拟VR FOV lens.setNearFar(0.1, 1000) self.left_eye_camera.node().setLens(lens) self.right_eye_camera.node().setLens(lens) print("✓ 眼部摄像机创建完成") except Exception as e: print(f"眼部摄像机创建错误: {str(e)}") def _update_eye_projection(self, eye, lens): """更新眼部投影矩阵""" try: if self.simulation_mode: # 模拟模式使用标准投影 perspective_lens = PerspectiveLens() perspective_lens.setFov(110) perspective_lens.setNearFar(0.1, 1000) lens.copyFrom(perspective_lens) return import openvr # 获取投影矩阵 projection_matrix = self.vr_system.getProjectionMatrix(eye, 0.1, 1000.0) # 转换为Panda3D矩阵 panda_matrix = self._convert_openvr_matrix(projection_matrix) # 设置自定义投影矩阵 lens.setCustomProjectionMatrix(panda_matrix) except Exception as e: print(f"眼部投影更新错误: {str(e)}") def _setup_render_targets(self): """设置渲染目标""" try: # 在模拟模式下,可以选择将渲染结果显示到主窗口 if self.simulation_mode: # 创建并排显示的立体视图 self._setup_simulation_display() print("✓ 渲染目标设置完成") except Exception as e: print(f"渲染目标设置错误: {str(e)}") def _setup_simulation_display(self): """设置模拟显示""" try: # 创建卡片来显示眼部纹理 cm = CardMaker("stereo_display") # 左眼显示区域 cm.setFrame(-1, 0, -1, 1) left_card = self.world.render2d.attachNewNode(cm.generate()) left_card.setTexture(self.left_eye_texture) # 右眼显示区域 cm.setFrame(0, 1, -1, 1) right_card = self.world.render2d.attachNewNode(cm.generate()) right_card.setTexture(self.right_eye_texture) print("✓ 模拟立体显示设置完成") except Exception as e: print(f"模拟显示设置错误: {str(e)}") def _init_alvr(self): """初始化ALVR(仅在真实VR模式下)""" if self.simulation_mode: print("ℹ 模拟模式: ALVR串流已跳过") return False try: # ALVR初始化逻辑 # 这里应该连接到ALVR服务器 print("✓ ALVR初始化完成") return True except Exception as e: print(f"ALVR初始化错误: {str(e)}") return False def _start_vr_tasks(self): """启动VR更新任务(真实VR模式)""" if not self.simulation_mode: taskMgr.add(self._update_vr_tracking, "vr_tracking") taskMgr.add(self._update_vr_rendering, "vr_rendering") def _start_simulation_tasks(self): """启动模拟VR任务""" taskMgr.add(self._update_simulation_tracking, "simulation_tracking") taskMgr.add(self._update_simulation_rendering, "simulation_rendering") def _update_simulation_tracking(self, task): """更新模拟追踪数据""" try: # 模拟头部追踪(可以添加一些变化) import math time_factor = task.time * 0.5 # 模拟轻微的头部摆动 head_pos = self.simulation_data['head_pose']['position'] head_pos[1] = math.sin(time_factor) * 0.05 # 前后轻微摆动 # 更新主摄像机位置 if hasattr(self.world, 'camera'): self.world.camera.setPos(head_pos[0], head_pos[1], head_pos[2]) # 更新控制器位置(模拟手部动作) for controller_id, pose in self.simulation_data['controller_poses'].items(): if pose['connected']: # 模拟控制器轻微移动 pose['position'][1] = math.sin(time_factor + controller_id) * 0.1 # 更新控制器节点位置 if controller_id in self.controller_nodes: node = self.controller_nodes[controller_id] node.setPos(pose['position'][0], pose['position'][1], pose['position'][2]) return task.cont except Exception as e: print(f"模拟追踪更新错误: {str(e)}") return task.cont def _update_simulation_rendering(self, task): """更新模拟渲染""" try: # 在模拟模式下,渲染已经由Panda3D自动处理 # 这里可以添加任何特殊的渲染逻辑 return task.cont except Exception as e: print(f"模拟渲染更新错误: {str(e)}") return task.cont def _update_vr_tracking(self, task): """更新VR追踪数据(真实VR模式)""" try: if not self.vr_system or self.simulation_mode: return task.cont import openvr # 获取设备姿态 poses, game_poses = self.vr_compositor.waitGetPoses(None, None) # 更新头显位置 if poses[openvr.k_unTrackedDeviceIndex_Hmd].bPoseIsValid: self._update_main_camera_pose() # 更新眼部摄像机 self._update_eye_cameras() # 更新控制器姿态 self._update_controller_poses(poses) return task.cont except Exception as e: print(f"VR追踪更新错误: {str(e)}") return task.cont def _update_vr_rendering(self, task): """更新VR渲染(真实VR模式)""" try: if not self.vr_compositor or self.simulation_mode: return task.cont # 提交帧到合成器 self._submit_frames_to_compositor() return task.cont except Exception as e: print(f"VR渲染更新错误: {str(e)}") return task.cont def _convert_openvr_matrix(self, openvr_matrix): """转换OpenVR矩阵为Panda3D矩阵""" # 实现矩阵转换逻辑 mat = Mat4() # 这里需要实现具体的矩阵转换 return mat def _update_main_camera_pose(self): """更新主摄像机姿态""" try: if self.simulation_mode: return # 从VR系统获取头显姿态并应用到主摄像机 pass except Exception as e: print(f"主摄像机姿态更新错误: {str(e)}") def _update_eye_cameras(self): """更新眼部摄像机""" try: if self.simulation_mode: return # 更新左右眼摄像机位置 pass except Exception as e: print(f"眼部摄像机更新错误: {str(e)}") def _update_controller_poses(self, poses): """更新控制器姿态""" try: if self.simulation_mode: return # 更新控制器位置和姿态 pass except Exception as e: print(f"控制器姿态更新错误: {str(e)}") def _submit_frames_to_compositor(self): """提交帧到合成器""" try: if not self.vr_compositor or self.simulation_mode: return import openvr # 提交左眼纹理 left_eye_texture = openvr.Texture_t() left_eye_texture.handle = self.left_eye_texture.getTextureId() left_eye_texture.eType = openvr.TextureType_OpenGL left_eye_texture.eColorSpace = openvr.ColorSpace_Gamma self.vr_compositor.submit(openvr.Eye_Left, left_eye_texture) # 提交右眼纹理 right_eye_texture = openvr.Texture_t() right_eye_texture.handle = self.right_eye_texture.getTextureId() right_eye_texture.eType = openvr.TextureType_OpenGL right_eye_texture.eColorSpace = openvr.ColorSpace_Gamma self.vr_compositor.submit(openvr.Eye_Right, right_eye_texture) except Exception as e: print(f"帧提交错误: {str(e)}") def get_controller_input(self, controller_id): """获取控制器输入""" try: if self.simulation_mode: # 返回模拟的控制器输入 return { 'trigger': 0.0, 'grip': 0.0, 'touchpad': {'x': 0.0, 'y': 0.0, 'pressed': False}, 'menu': False, 'connected': controller_id in self.simulation_data['controller_poses'] } if not self.vr_system: return None import openvr # 获取控制器状态 result, controller_state = self.vr_system.getControllerState(controller_id) if not result: return None # 解析控制器输入 return { 'trigger': controller_state.rAxis[1].x, 'grip': controller_state.rAxis[2].x, 'touchpad': { 'x': controller_state.rAxis[0].x, 'y': controller_state.rAxis[0].y, 'pressed': controller_state.rAxis[0].x != 0 or controller_state.rAxis[0].y != 0 }, 'menu': controller_state.ulButtonPressed & (1 << openvr.k_EButton_ApplicationMenu) != 0, 'connected': True } except Exception as e: print(f"控制器输入获取错误: {str(e)}") return None def shutdown_vr(self): """关闭VR系统""" try: # 停止任务 if self.simulation_mode: taskMgr.remove("simulation_tracking") taskMgr.remove("simulation_rendering") else: taskMgr.remove("vr_tracking") taskMgr.remove("vr_rendering") # 关闭OpenVR if self.vr_system and not self.simulation_mode: import openvr openvr.shutdown() # 清理资源 self.left_eye_buffer = None self.right_eye_buffer = None self.left_eye_camera = None self.right_eye_camera = None self.vr_enabled = False self.simulation_mode = False print("✓ VR系统已关闭") except Exception as e: print(f"VR关闭错误: {str(e)}") def is_vr_enabled(self): """检查VR是否启用""" return self.vr_enabled def get_vr_info(self): """获取VR系统信息""" info = { 'enabled': self.vr_enabled, 'simulation_mode': self.simulation_mode, 'render_size': (self.render_width, self.render_height), 'alvr_enabled': self.alvr_enabled } if self.simulation_mode: info['mode'] = 'simulation' info['controllers'] = len(self.simulation_data['controller_poses']) else: info['mode'] = 'real_vr' info['openvr_connected'] = self.vr_system is not None return info # 便捷方法 def enable_simulation_mode(self): """启用模拟模式(调试用)""" return self.initialize_vr(force_simulation=True) def get_simulation_data(self): """获取模拟数据""" return self.simulation_data if self.simulation_mode else None def update_simulation_data(self, key, value): """更新模拟数据""" if self.simulation_mode and key in self.simulation_data: self.simulation_data[key] = value return True return False