diff --git a/core/vr_manager.py b/core/vr_manager.py index 37c289ab..8ab68ae9 100644 --- a/core/vr_manager.py +++ b/core/vr_manager.py @@ -144,6 +144,9 @@ class VRManager(DirectObject): # 帧同步标记 - 修复ATW闪烁 self._poses_updated_this_frame = False + # Running Start标记 - Valve最佳实践 + self._waitgetposes_called_this_frame = False + # 姿态缓存 - 修复时序不匹配 self._cached_render_poses = None # 用于渲染的缓存姿态 self._first_frame = True # 首帧标记 @@ -529,16 +532,19 @@ class VRManager(DirectObject): # VR更新策略选择 if self.pose_strategy == 'update_task': - # 策略1:在更新任务中调用waitGetPoses(推荐用于高性能) - timing = self._start_timing('wait_poses') - self._wait_get_poses_with_prediction() - self._end_timing(timing) + # 🚀 新的Running Start策略:WaitGetPoses在Submit后调用,此处只更新相机 + # 不在此处调用WaitGetPoses,避免错过VSync窗口 self.poses_updated_in_task = True - # 更新相机姿态 + # 使用上一帧获取的姿态更新相机 self._update_camera_poses() + + # 输出策略信息(仅第一次) + if not hasattr(self, '_running_start_logged'): + print("✓ Running Start模式已启用 - WaitGetPoses在Submit后调用") + self._running_start_logged = True else: - # 策略2:在渲染回调中调用waitGetPoses(默认策略) + # 策略2:在渲染回调中调用waitGetPoses(传统策略) self.poses_updated_in_task = False # 1. 更新手柄和其他跟踪设备 @@ -750,6 +756,11 @@ class VRManager(DirectObject): self._poses_updated_this_frame = False return task.done + def _reset_waitgetposes_flag(self, task): + """重置WaitGetPoses标记 - 确保下一帧可以调用WaitGetPoses""" + self._waitgetposes_called_this_frame = False + return task.done + def _update_tracking_data(self): """更新VR追踪数据""" try: @@ -1065,6 +1076,12 @@ class VRManager(DirectObject): # 禁用主相机避免干扰VR渲染 self._disable_main_cam() + # 优化VR性能:切换到update_task姿态策略 + print("🚀 正在优化VR性能...") + self.set_pose_strategy('update_task') + self.set_prediction_time(11.0) # 11ms预测时间 + print("✓ VR性能优化完成 - 姿态策略已切换至update_task模式") + print("✅ VR模式已启用") return True @@ -1437,6 +1454,18 @@ class VRManager(DirectObject): self.submit_texture(openvr.Eye_Right, self.vr_right_texture) self._end_timing(submit_timing) + # 🚀 Valve的"Running Start"技术:Submit后立即调用WaitGetPoses + # 这是获取下一帧姿态的最佳时机,避免错过VSync窗口 + if not hasattr(self, '_waitgetposes_called_this_frame') or not self._waitgetposes_called_this_frame: + pose_timing = self._start_timing('wait_poses') + self._wait_get_poses_immediate() + self._end_timing(pose_timing) + self._waitgetposes_called_this_frame = True + # print("✓ Running Start: 在Submit后立即获取下一帧姿态") + + # 重置标记,准备下一帧 + self.world.taskMgr.doMethodLater(0.001, self._reset_waitgetposes_flag, "reset_waitgetposes_flag") + except Exception as e: self._end_timing(render_timing) print(f"右眼渲染回调错误: {e}") @@ -1992,11 +2021,11 @@ class VRManager(DirectObject): if old_strategy != strategy: print(f"✓ VR姿态策略已切换: {old_strategy} → {strategy}") if strategy == 'update_task': - print(f" 使用预测时间: {self.use_prediction_time*1000:.1f}ms") - print(" 优势:降低VR回调延迟,提高性能") + print(" 🚀 Valve Running Start模式:Submit后立即获取姿态") + print(" 优势:避免错过VSync窗口,显著降低WaitGetPoses延迟") else: print(" 使用传统渲染回调策略") - print(" 优势:更低延迟,更精确的姿态") + print(" 缺点:可能在渲染前调用WaitGetPoses,容易错过VSync") # 重置相关标记 if hasattr(self, '_poses_updated_this_frame'): @@ -2025,8 +2054,8 @@ class VRManager(DirectObject): 'strategy': self.pose_strategy, 'prediction_time_ms': self.use_prediction_time * 1000, 'description': { - 'render_callback': '在渲染回调中获取姿态 - 低延迟,精确', - 'update_task': '在更新任务中获取姿态 - 高性能,预测' + 'render_callback': '在渲染回调中获取姿态 - 传统模式,可能错过VSync', + 'update_task': 'Valve Running Start模式 - Submit后立即获取姿态,避免VSync延迟' }.get(self.pose_strategy, '未知策略') } diff --git a/vr_actions/bindings_index.json b/vr_actions/bindings_index.json new file mode 100644 index 00000000..f7198f13 --- /dev/null +++ b/vr_actions/bindings_index.json @@ -0,0 +1,133 @@ +{ + "controller_type": "knuckles", + "description": "Valve Index\u63a7\u5236\u5668\u7ed1\u5b9a", + "name": "EG VR Editor - Index", + "bindings": { + "/actions/default": { + "sources": [ + { + "inputs": { + "click": { + "output": "/actions/default/in/Trigger" + } + }, + "mode": "button", + "path": "/user/hand/left/input/trigger" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/Trigger" + } + }, + "mode": "button", + "path": "/user/hand/right/input/trigger" + }, + { + "inputs": { + "value": { + "output": "/actions/default/in/Squeeze" + } + }, + "mode": "trigger", + "path": "/user/hand/left/input/grip" + }, + { + "inputs": { + "value": { + "output": "/actions/default/in/Squeeze" + } + }, + "mode": "trigger", + "path": "/user/hand/right/input/grip" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/AButton" + } + }, + "mode": "button", + "path": "/user/hand/right/input/a" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/BButton" + } + }, + "mode": "button", + "path": "/user/hand/right/input/b" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Trackpad" + }, + "click": { + "output": "/actions/default/in/TrackpadClick" + }, + "touch": { + "output": "/actions/default/in/TrackpadTouch" + } + }, + "mode": "trackpad", + "path": "/user/hand/left/input/trackpad" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Trackpad" + }, + "click": { + "output": "/actions/default/in/TrackpadClick" + }, + "touch": { + "output": "/actions/default/in/TrackpadTouch" + } + }, + "mode": "trackpad", + "path": "/user/hand/right/input/trackpad" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Joystick" + } + }, + "mode": "joystick", + "path": "/user/hand/left/input/thumbstick" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Joystick" + } + }, + "mode": "joystick", + "path": "/user/hand/right/input/thumbstick" + } + ], + "poses": [ + { + "output": "/actions/default/in/Pose", + "path": "/user/hand/left/pose/raw" + }, + { + "output": "/actions/default/in/Pose", + "path": "/user/hand/right/pose/raw" + } + ], + "haptics": [ + { + "output": "/actions/default/out/Haptic", + "path": "/user/hand/left/output/haptic" + }, + { + "output": "/actions/default/out/Haptic", + "path": "/user/hand/right/output/haptic" + } + ] + } + } +} \ No newline at end of file diff --git a/vr_actions/bindings_oculus.json b/vr_actions/bindings_oculus.json new file mode 100644 index 00000000..71a697b7 --- /dev/null +++ b/vr_actions/bindings_oculus.json @@ -0,0 +1,118 @@ +{ + "controller_type": "oculus_touch", + "description": "Oculus Touch\u63a7\u5236\u5668\u7ed1\u5b9a", + "name": "EG VR Editor - Oculus Touch", + "bindings": { + "/actions/default": { + "sources": [ + { + "inputs": { + "click": { + "output": "/actions/default/in/Trigger" + } + }, + "mode": "button", + "path": "/user/hand/left/input/trigger" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/Trigger" + } + }, + "mode": "button", + "path": "/user/hand/right/input/trigger" + }, + { + "inputs": { + "value": { + "output": "/actions/default/in/Squeeze" + } + }, + "mode": "trigger", + "path": "/user/hand/left/input/grip" + }, + { + "inputs": { + "value": { + "output": "/actions/default/in/Squeeze" + } + }, + "mode": "trigger", + "path": "/user/hand/right/input/grip" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/AButton" + } + }, + "mode": "button", + "path": "/user/hand/right/input/a" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/BButton" + } + }, + "mode": "button", + "path": "/user/hand/right/input/b" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Joystick" + }, + "click": { + "output": "/actions/default/in/TrackpadClick" + } + }, + "mode": "joystick", + "path": "/user/hand/left/input/thumbstick" + }, + { + "inputs": { + "position": { + "output": "/actions/default/in/Joystick" + }, + "click": { + "output": "/actions/default/in/TrackpadClick" + } + }, + "mode": "joystick", + "path": "/user/hand/right/input/thumbstick" + }, + { + "inputs": { + "click": { + "output": "/actions/default/in/Menu" + } + }, + "mode": "button", + "path": "/user/hand/left/input/menu" + } + ], + "poses": [ + { + "output": "/actions/default/in/Pose", + "path": "/user/hand/left/pose/raw" + }, + { + "output": "/actions/default/in/Pose", + "path": "/user/hand/right/pose/raw" + } + ], + "haptics": [ + { + "output": "/actions/default/out/Haptic", + "path": "/user/hand/left/output/haptic" + }, + { + "output": "/actions/default/out/Haptic", + "path": "/user/hand/right/output/haptic" + } + ] + } + } +} \ No newline at end of file