""" VR输入处理器 处理VR控制器输入、手势识别和VR交互 支持多种VR控制器和手势输入 """ from direct.showbase.DirectObject import DirectObject from panda3d.core import Vec3, Point3, CollisionRay, CollisionNode, CollisionHandlerQueue from direct.task import Task import time class VRInputHandler(DirectObject): """VR输入处理器""" def __init__(self, world, vr_manager): super().__init__() self.world = world self.vr_manager = vr_manager # 控制器状态 self.controllers = {} self.controller_nodes = {} self.controller_rays = {} # 手势识别 self.gesture_enabled = True self.gesture_history = [] self.gesture_threshold = 0.1 # 交互系统 self.interaction_enabled = True self.selected_object = None self.grab_offset = Vec3(0, 0, 0) # 输入映射 self.input_mappings = { 'trigger': self._handle_trigger, 'grip': self._handle_grip, 'touchpad': self._handle_touchpad, 'menu': self._handle_menu, 'system': self._handle_system } print("✓ VR输入处理器初始化完成") def start_input_handling(self): """启动输入处理""" if not self.vr_manager.is_vr_enabled(): print("VR未启用,无法启动输入处理") return False # 启动输入更新任务 self.world.taskMgr.add(self._update_input, "vr_input_update") # 设置控制器可视化 self._setup_controller_visualization() print("✓ VR输入处理已启动") return True def stop_input_handling(self): """停止输入处理""" self.world.taskMgr.remove("vr_input_update") self._cleanup_controller_visualization() print("✓ VR输入处理已停止") def _update_input(self, task): """更新输入处理""" if not self.vr_manager.is_vr_enabled(): return Task.cont try: # 更新所有控制器 self._update_controllers() # 处理手势识别 if self.gesture_enabled: self._process_gestures() # 处理交互 if self.interaction_enabled: self._process_interactions() except Exception as e: print(f"VR输入更新错误: {str(e)}") return Task.cont def _update_controllers(self): """更新控制器状态""" # 获取控制器姿态 controller_poses = self.vr_manager.controller_poses for controller_id, pose in controller_poses.items(): # 获取控制器输入 input_data = self.vr_manager.get_controller_input(controller_id) if not input_data: continue # 更新控制器状态 if controller_id not in self.controllers: self.controllers[controller_id] = {} prev_state = self.controllers[controller_id].copy() self.controllers[controller_id] = input_data # 更新控制器可视化 self._update_controller_visualization(controller_id, pose) # 处理输入事件 self._process_controller_input(controller_id, input_data, prev_state) def _process_controller_input(self, controller_id, current_state, prev_state): """处理控制器输入""" # 检查按钮状态变化 for input_type, handler in self.input_mappings.items(): if input_type in current_state: current_value = current_state[input_type] prev_value = prev_state.get(input_type, 0) # 处理按钮按下/释放 if isinstance(current_value, (int, float)): if current_value > 0.5 and prev_value <= 0.5: handler(controller_id, 'press', current_value) elif current_value <= 0.5 and prev_value > 0.5: handler(controller_id, 'release', current_value) elif current_value > 0.5: handler(controller_id, 'hold', current_value) # 处理触摸板 elif isinstance(current_value, tuple) and len(current_value) == 2: if current_value != prev_value: handler(controller_id, 'move', current_value) def _handle_trigger(self, controller_id, action, value): """处理扳机输入""" if action == 'press': print(f"控制器 {controller_id} 扳机按下 (强度: {value:.2f})") self._try_grab_object(controller_id) elif action == 'release': print(f"控制器 {controller_id} 扳机释放") self._try_release_object(controller_id) def _handle_grip(self, controller_id, action, value): """处理握持输入""" if action == 'press': print(f"控制器 {controller_id} 握持按下 (强度: {value:.2f})") self._toggle_interaction_mode(controller_id) elif action == 'release': print(f"控制器 {controller_id} 握持释放") def _handle_touchpad(self, controller_id, action, value): """处理触摸板输入""" if action == 'move': x, y = value print(f"控制器 {controller_id} 触摸板: ({x:.2f}, {y:.2f})") # 根据触摸板位置执行不同操作 if abs(x) > 0.7: # 左右滑动 self._handle_horizontal_swipe(controller_id, x) elif abs(y) > 0.7: # 上下滑动 self._handle_vertical_swipe(controller_id, y) def _handle_menu(self, controller_id, action, value): """处理菜单按钮""" if action == 'press': print(f"控制器 {controller_id} 菜单按钮按下") self._show_vr_menu(controller_id) def _handle_system(self, controller_id, action, value): """处理系统按钮""" if action == 'press': print(f"控制器 {controller_id} 系统按钮按下") # 系统按钮通常由VR系统处理 def _handle_horizontal_swipe(self, controller_id, direction): """处理水平滑动""" if direction > 0: print(f"控制器 {controller_id} 右滑") self._switch_tool(controller_id, 'next') else: print(f"控制器 {controller_id} 左滑") self._switch_tool(controller_id, 'prev') def _handle_vertical_swipe(self, controller_id, direction): """处理垂直滑动""" if direction > 0: print(f"控制器 {controller_id} 上滑") self._zoom_in(controller_id) else: print(f"控制器 {controller_id} 下滑") self._zoom_out(controller_id) def _try_grab_object(self, controller_id): """尝试抓取对象""" if controller_id not in self.controllers: return # 获取控制器射线 ray = self._get_controller_ray(controller_id) if not ray: return # 执行射线检测 hit_object = self._raycast_from_controller(controller_id) if hit_object: self.selected_object = hit_object controller_pose = self.controllers[controller_id].get('pose') if controller_pose: # 计算抓取偏移 object_pos = hit_object.getPos() controller_pos = controller_pose.getTranslate() self.grab_offset = object_pos - controller_pos print(f"抓取对象: {hit_object.getName()}") # 发送抓取事件 self.world.event_handler.messenger.send('vr-object-grabbed', [hit_object, controller_id]) def _try_release_object(self, controller_id): """尝试释放对象""" if self.selected_object: print(f"释放对象: {self.selected_object.getName()}") # 发送释放事件 self.world.event_handler.messenger.send('vr-object-released', [self.selected_object, controller_id]) self.selected_object = None self.grab_offset = Vec3(0, 0, 0) def _raycast_from_controller(self, controller_id): """从控制器发射射线检测""" if controller_id not in self.controllers: return None controller_pose = self.controllers[controller_id].get('pose') if not controller_pose: return None # 获取控制器位置和方向 controller_pos = controller_pose.getTranslate() controller_forward = controller_pose.getQuat().getForward() # 创建射线 ray = CollisionRay() ray.setOrigin(controller_pos) ray.setDirection(controller_forward) # 执行碰撞检测 traverser = self.world.cTrav if hasattr(self.world, 'cTrav') else None if not traverser: return None handler = CollisionHandlerQueue() collision_node = CollisionNode('vr_controller_ray') collision_node.addSolid(ray) ray_np = self.world.render.attachNewNode(collision_node) traverser.addCollider(ray_np, handler) # 遍历碰撞 traverser.traverse(self.world.render) # 清理 ray_np.removeNode() # 返回最近的碰撞对象 if handler.getNumEntries() > 0: handler.sortEntries() entry = handler.getEntry(0) return entry.getIntoNodePath() return None def _get_controller_ray(self, controller_id): """获取控制器射线""" return self.controller_rays.get(controller_id) def _setup_controller_visualization(self): """设置控制器可视化""" print("设置控制器可视化...") # 为每个控制器创建可视化节点 for controller_id in self.controllers: self._create_controller_model(controller_id) def _create_controller_model(self, controller_id): """创建控制器模型""" # 创建简单的控制器模型(立方体) from panda3d.core import CardMaker cm = CardMaker(f"controller_{controller_id}") cm.setFrame(-0.05, 0.05, -0.05, 0.05) controller_node = self.world.render.attachNewNode(cm.generate()) controller_node.setColor(0.2, 0.8, 1.0, 0.8) controller_node.setScale(0.1, 0.2, 0.05) self.controller_nodes[controller_id] = controller_node # 创建控制器射线可视化 self._create_controller_ray_visual(controller_id) def _create_controller_ray_visual(self, controller_id): """创建控制器射线可视化""" from panda3d.core import LineSegs # 创建射线线段 lines = LineSegs() lines.setColor(1, 0, 0, 0.5) lines.moveTo(0, 0, 0) lines.drawTo(0, 2, 0) # 2米长的射线 ray_node = self.world.render.attachNewNode(lines.create()) ray_node.setRenderModeWireframe() ray_node.hide() # 默认隐藏 self.controller_rays[controller_id] = ray_node def _update_controller_visualization(self, controller_id, pose): """更新控制器可视化""" if controller_id in self.controller_nodes: node = self.controller_nodes[controller_id] node.setMat(pose) if controller_id in self.controller_rays: ray_node = self.controller_rays[controller_id] ray_node.setMat(pose) def _cleanup_controller_visualization(self): """清理控制器可视化""" for node in self.controller_nodes.values(): node.removeNode() for ray in self.controller_rays.values(): ray.removeNode() self.controller_nodes.clear() self.controller_rays.clear() def _process_gestures(self): """处理手势识别""" # 简单的手势识别逻辑 # 这里可以实现更复杂的手势识别算法 pass def _process_interactions(self): """处理交互逻辑""" # 如果有选中的对象,更新其位置 if self.selected_object: self._update_grabbed_object() def _update_grabbed_object(self): """更新被抓取对象的位置""" if not self.selected_object: return # 找到抓取该对象的控制器 grabbing_controller = None for controller_id, controller_state in self.controllers.items(): if controller_state.get('trigger', 0) > 0.5: grabbing_controller = controller_id break if not grabbing_controller: return # 更新对象位置 controller_pose = self.controllers[grabbing_controller].get('pose') if controller_pose: controller_pos = controller_pose.getTranslate() new_pos = controller_pos + self.grab_offset self.selected_object.setPos(new_pos) def _toggle_interaction_mode(self, controller_id): """切换交互模式""" self.interaction_enabled = not self.interaction_enabled print(f"交互模式: {'启用' if self.interaction_enabled else '禁用'}") def _show_vr_menu(self, controller_id): """显示VR菜单""" print(f"显示VR菜单 (控制器 {controller_id})") # 这里可以实现VR菜单显示逻辑 pass def _switch_tool(self, controller_id, direction): """切换工具""" print(f"切换工具: {direction} (控制器 {controller_id})") # 这里可以实现工具切换逻辑 pass def _zoom_in(self, controller_id): """放大""" print(f"放大 (控制器 {controller_id})") # 实现放大逻辑 pass def _zoom_out(self, controller_id): """缩小""" print(f"缩小 (控制器 {controller_id})") # 实现缩小逻辑 pass def show_controller_rays(self, show=True): """显示/隐藏控制器射线""" for ray in self.controller_rays.values(): if show: ray.show() else: ray.hide() def get_controller_state(self, controller_id): """获取控制器状态""" return self.controllers.get(controller_id, {}) def get_all_controllers(self): """获取所有控制器""" return list(self.controllers.keys()) def set_gesture_enabled(self, enabled): """设置手势识别启用状态""" self.gesture_enabled = enabled print(f"手势识别: {'启用' if enabled else '禁用'}") def set_interaction_enabled(self, enabled): """设置交互启用状态""" self.interaction_enabled = enabled print(f"VR交互: {'启用' if enabled else '禁用'}")