1
0
forked from Rowland/EG

vr画面抖动修复

This commit is contained in:
Rowland 2025-09-16 10:43:07 +08:00
parent ded28e0097
commit 11cbefc905
2 changed files with 107 additions and 27 deletions

View File

@ -92,6 +92,9 @@ class VRManager(DirectObject):
# VR提交策略 - 基于参考实现
self.submit_together = True # 是否在right_cb中同时提交左右眼
# 帧同步标记 - 修复ATW闪烁
self._poses_updated_this_frame = False
# VR手柄控制器
self.left_controller = None
self.right_controller = None
@ -389,20 +392,16 @@ class VRManager(DirectObject):
self.last_fps_time = current_time
# 优化的VR更新顺序
# 1. 立即调用 waitGetPoses 获取最新的姿态数据
# 这确保我们使用最新数据而不是上一帧的数据
self._wait_get_poses()
# 注意WaitGetPoses现在在渲染回调中调用避免ATW双重预测
# 这里仅更新非关键的跟踪设备和交互系统
# 2. 更新相机位置(使用刚获取的最新姿态数据)
self._update_camera_poses()
# 3. 更新手柄和其他跟踪设备
# 1. 更新手柄和其他跟踪设备
self.update_tracked_devices()
# 4. 更新VR动作状态
# 2. 更新VR动作状态
self.action_manager.update_actions()
# 5. 更新VR交互系统
# 3. 更新VR交互系统
self.interaction_manager.update()
# 注意:纹理提交现在通过渲染回调自动处理
@ -466,6 +465,59 @@ class VRManager(DirectObject):
# 记录姿态失败次数
self.pose_failures += 1
def _wait_get_poses_immediate(self):
"""立即获取VR姿态 - 修复ATW闪烁的关键方法"""
try:
if not self.vr_compositor or not self.poses:
return
# 使用0预测时间来避免双重预测立即获取当前姿态
# 这是修复ATW闪烁的关键在渲染前立即获取避免时序错误
result = self.vr_compositor.waitGetPoses(self.poses, None)
# 检查姿态数据的有效性
valid_poses = 0
# 更新HMD姿态设备0通常是头显
if len(self.poses) > 0 and self.poses[0].bPoseIsValid:
valid_poses += 1
else:
# 如果HMD姿态无效不要频繁输出错误信息
if not hasattr(self, '_hmd_invalid_warning_shown'):
print("⚠️ HMD姿态数据无效立即模式")
self._hmd_invalid_warning_shown = True
# 更新控制器姿态
self.controller_poses.clear()
for device_id in range(1, min(len(self.poses), openvr.k_unMaxTrackedDeviceCount)):
if self.poses[device_id].bPoseIsValid:
device_class = self.vr_system.getTrackedDeviceClass(device_id)
if device_class == openvr.TrackedDeviceClass_Controller:
controller_matrix = self.poses[device_id].mDeviceToAbsoluteTracking
self.controller_poses[device_id] = self._convert_openvr_matrix_to_panda(controller_matrix)
valid_poses += 1
# 调试信息 - 仅在第一次成功时输出
if not hasattr(self, '_immediate_mode_logged') and valid_poses > 0:
print(f"✅ 立即姿态获取模式启用 - 有效姿态数: {valid_poses}")
self._immediate_mode_logged = True
except Exception as e:
# 限制错误输出频率
if not hasattr(self, '_last_immediate_error_frame'):
self._last_immediate_error_frame = 0
if self.frame_count - self._last_immediate_error_frame > 300: # 每5秒最多输出一次错误
print(f"立即姿态获取失败: {e}")
self._last_immediate_error_frame = self.frame_count
self.pose_failures += 1
def _reset_frame_flag(self, task):
"""重置帧标记 - 确保下一帧可以更新姿态"""
self._poses_updated_this_frame = False
return task.done
def _update_tracking_data(self):
"""更新VR追踪数据"""
try:
@ -840,26 +892,53 @@ class VRManager(DirectObject):
print("========================")
def left_cb(self, cbdata):
"""左眼渲染回调 - 基于参考实现"""
# 执行实际的渲染工作
cbdata.upcall()
# 根据提交策略决定是否立即提交
if not self.submit_together:
# 分别提交模式:左眼渲染完成后立即提交
self.submit_texture(openvr.Eye_Left, self.vr_left_texture)
"""左眼渲染回调 - 修复ATW闪烁问题"""
try:
# 在渲染开始前立即获取最新姿态避免ATW双重预测
if not hasattr(self, '_poses_updated_this_frame') or not self._poses_updated_this_frame:
self._wait_get_poses_immediate()
self._update_camera_poses()
self._poses_updated_this_frame = True
# 在帧结束时重置标记
self.world.taskMgr.doMethodLater(0.001, self._reset_frame_flag, "reset_frame_flag")
# 执行实际的渲染工作
cbdata.upcall()
# 根据提交策略决定是否立即提交
if not self.submit_together:
# 分别提交模式:左眼渲染完成后立即提交
self.submit_texture(openvr.Eye_Left, self.vr_left_texture)
except Exception as e:
print(f"左眼渲染回调错误: {e}")
def right_cb(self, cbdata):
"""右眼渲染回调 - 基于参考实现"""
# 执行实际的渲染工作
cbdata.upcall()
# 根据提交策略决定提交方式
if self.submit_together:
# 同时提交模式:右眼渲染完成后同时提交左右眼
self.submit_texture(openvr.Eye_Left, self.vr_left_texture)
self.submit_texture(openvr.Eye_Right, self.vr_right_texture)
else:
# 分别提交模式:只提交右眼
self.submit_texture(openvr.Eye_Right, self.vr_right_texture)
"""右眼渲染回调 - 修复ATW闪烁问题"""
try:
# 在渲染开始前立即获取最新姿态避免ATW双重预测
# 由于左右眼都会调用回调确保每帧只调用一次WaitGetPoses
if not hasattr(self, '_poses_updated_this_frame') or not self._poses_updated_this_frame:
self._wait_get_poses_immediate()
self._update_camera_poses()
self._poses_updated_this_frame = True
# 在帧结束时重置标记
self.world.taskMgr.doMethodLater(0.001, self._reset_frame_flag, "reset_frame_flag")
# 执行实际的渲染工作
cbdata.upcall()
# 根据提交策略决定提交方式
if self.submit_together:
# 同时提交模式:右眼渲染完成后同时提交左右眼
self.submit_texture(openvr.Eye_Left, self.vr_left_texture)
self.submit_texture(openvr.Eye_Right, self.vr_right_texture)
else:
# 分别提交模式:只提交右眼
self.submit_texture(openvr.Eye_Right, self.vr_right_texture)
except Exception as e:
print(f"右眼渲染回调错误: {e}")
def submit_texture(self, eye, texture):
"""提交纹理到VR - 基于参考实现,增强调试信息"""

@ -0,0 +1 @@
Subproject commit 3f9567897552df6c10078bc124795101cf478f91