forked from Rowland/EG
vr画面抖动修复
This commit is contained in:
parent
11cbefc905
commit
86b38bcfb3
@ -60,7 +60,8 @@ class VRManager(DirectObject):
|
||||
self.hmd_pose = Mat4.identMat()
|
||||
self.controller_poses = {}
|
||||
self.tracked_device_poses = []
|
||||
self.poses = None # OpenVR姿态数组
|
||||
self.poses = None # OpenVR渲染姿态数组
|
||||
self.game_poses = None # OpenVR游戏逻辑姿态数组
|
||||
|
||||
# VR渲染参数
|
||||
self.eye_width = 1080
|
||||
@ -95,6 +96,13 @@ class VRManager(DirectObject):
|
||||
# 帧同步标记 - 修复ATW闪烁
|
||||
self._poses_updated_this_frame = False
|
||||
|
||||
# 姿态缓存 - 修复时序不匹配
|
||||
self._cached_render_poses = None # 用于渲染的缓存姿态
|
||||
self._first_frame = True # 首帧标记
|
||||
|
||||
# ATW控制选项 - 备选方案
|
||||
self.disable_async_reprojection = False # 是否禁用异步重投影
|
||||
|
||||
# VR手柄控制器
|
||||
self.left_controller = None
|
||||
self.right_controller = None
|
||||
@ -168,10 +176,11 @@ class VRManager(DirectObject):
|
||||
self.eye_width, self.eye_height = self.vr_system.getRecommendedRenderTargetSize()
|
||||
print(f"✓ VR渲染目标尺寸: {self.eye_width}x{self.eye_height}")
|
||||
|
||||
# 创建OpenVR姿态数组
|
||||
# 创建OpenVR姿态数组 - 分离渲染和游戏姿态
|
||||
poses_t = openvr.TrackedDevicePose_t * openvr.k_unMaxTrackedDeviceCount
|
||||
self.poses = poses_t()
|
||||
print("✓ VR姿态数组已创建")
|
||||
self.poses = poses_t() # 渲染姿态(预测的)
|
||||
self.game_poses = poses_t() # 游戏逻辑姿态(当前的)
|
||||
print("✓ VR渲染和游戏姿态数组已创建")
|
||||
|
||||
# 创建VR渲染缓冲区
|
||||
if not self._create_vr_buffers():
|
||||
@ -194,6 +203,10 @@ class VRManager(DirectObject):
|
||||
if not self.interaction_manager.initialize():
|
||||
print("⚠️ VR交互系统初始化失败,但VR系统将继续运行")
|
||||
|
||||
# 可选:禁用异步重投影(备选方案)
|
||||
if self.disable_async_reprojection:
|
||||
self._disable_async_reprojection()
|
||||
|
||||
# 启动VR更新任务
|
||||
self._start_vr_task()
|
||||
|
||||
@ -466,14 +479,14 @@ class VRManager(DirectObject):
|
||||
self.pose_failures += 1
|
||||
|
||||
def _wait_get_poses_immediate(self):
|
||||
"""立即获取VR姿态 - 修复ATW闪烁的关键方法"""
|
||||
"""立即获取VR姿态 - 修复ATW闪烁的关键方法(双姿态版本)"""
|
||||
try:
|
||||
if not self.vr_compositor or not self.poses:
|
||||
if not self.vr_compositor or not self.poses or not self.game_poses:
|
||||
return
|
||||
|
||||
# 使用0预测时间来避免双重预测,立即获取当前姿态
|
||||
# 这是修复ATW闪烁的关键:在渲染前立即获取,避免时序错误
|
||||
result = self.vr_compositor.waitGetPoses(self.poses, None)
|
||||
# 关键修复:传递渲染姿态和游戏姿态数组
|
||||
# 渲染姿态用于绘制,游戏姿态用于逻辑,避免ATW过度补偿
|
||||
result = self.vr_compositor.waitGetPoses(self.poses, self.game_poses)
|
||||
|
||||
# 检查姿态数据的有效性
|
||||
valid_poses = 0
|
||||
@ -498,9 +511,10 @@ class VRManager(DirectObject):
|
||||
valid_poses += 1
|
||||
|
||||
# 调试信息 - 仅在第一次成功时输出
|
||||
if not hasattr(self, '_immediate_mode_logged') and valid_poses > 0:
|
||||
print(f"✅ 立即姿态获取模式启用 - 有效姿态数: {valid_poses}")
|
||||
self._immediate_mode_logged = True
|
||||
if not hasattr(self, '_dual_pose_mode_logged') and valid_poses > 0:
|
||||
print(f"✅ 双姿态立即获取模式启用 - 有效姿态数: {valid_poses}")
|
||||
print(" 渲染姿态用于绘制,游戏姿态用于逻辑,防止ATW过度补偿")
|
||||
self._dual_pose_mode_logged = True
|
||||
|
||||
except Exception as e:
|
||||
# 限制错误输出频率
|
||||
@ -513,6 +527,33 @@ class VRManager(DirectObject):
|
||||
|
||||
self.pose_failures += 1
|
||||
|
||||
def _cache_poses_for_next_frame(self):
|
||||
"""缓存当前姿态供下一帧渲染使用 - 修复时序不匹配"""
|
||||
try:
|
||||
if not self.poses or len(self.poses) == 0:
|
||||
return
|
||||
|
||||
# 如果是第一帧,直接使用当前姿态
|
||||
if self._first_frame:
|
||||
self._cached_render_poses = self.poses
|
||||
self._first_frame = False
|
||||
print("✓ 首帧姿态缓存已设置")
|
||||
return
|
||||
|
||||
# 复制当前渲染姿态到缓存
|
||||
# 下一帧将使用这些姿态进行渲染
|
||||
poses_t = openvr.TrackedDevicePose_t * openvr.k_unMaxTrackedDeviceCount
|
||||
cached_poses = poses_t()
|
||||
|
||||
# 复制姿态数据
|
||||
for i in range(len(self.poses)):
|
||||
cached_poses[i] = self.poses[i]
|
||||
|
||||
self._cached_render_poses = cached_poses
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ 姿态缓存失败: {e}")
|
||||
|
||||
def _reset_frame_flag(self, task):
|
||||
"""重置帧标记 - 确保下一帧可以更新姿态"""
|
||||
self._poses_updated_this_frame = False
|
||||
@ -667,6 +708,37 @@ class VRManager(DirectObject):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _update_camera_poses_with_cache(self):
|
||||
"""使用缓存姿态更新相机 - 符合OpenVR时序假设"""
|
||||
try:
|
||||
# 使用缓存的姿态,符合OpenVR的时序假设
|
||||
# OpenVR假设你用上一次WaitGetPoses的姿态渲染当前提交的帧
|
||||
|
||||
if not self._cached_render_poses:
|
||||
# 如果没有缓存姿态,回退到当前姿态(首帧情况)
|
||||
print("⚠️ 没有缓存姿态,使用当前姿态")
|
||||
return self._update_camera_poses()
|
||||
|
||||
# 从缓存姿态数组中获取HMD姿态
|
||||
if len(self._cached_render_poses) > 0:
|
||||
hmd_pose = self._cached_render_poses[openvr.k_unTrackedDeviceIndex_Hmd]
|
||||
if hmd_pose.bPoseIsValid:
|
||||
self.update_hmd(hmd_pose)
|
||||
|
||||
# 调试信息 - 验证缓存姿态使用
|
||||
if not hasattr(self, '_cached_pose_logged'):
|
||||
print("✅ 使用缓存姿态更新相机 - 符合OpenVR时序假设")
|
||||
self._cached_pose_logged = True
|
||||
else:
|
||||
print("⚠️ 缓存的HMD姿态数据无效")
|
||||
|
||||
except Exception as e:
|
||||
print(f"使用缓存姿态更新相机失败: {e}")
|
||||
# 回退到正常更新方式
|
||||
self._update_camera_poses()
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _submit_frames_to_vr(self):
|
||||
"""将渲染帧提交给VR系统"""
|
||||
try:
|
||||
@ -897,7 +969,10 @@ class VRManager(DirectObject):
|
||||
# 在渲染开始前立即获取最新姿态,避免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()
|
||||
# 缓存当前姿态供下一帧使用,符合OpenVR时序假设
|
||||
self._cache_poses_for_next_frame()
|
||||
# 使用缓存的姿态更新相机(上一帧的姿态)
|
||||
self._update_camera_poses_with_cache()
|
||||
self._poses_updated_this_frame = True
|
||||
# 在帧结束时重置标记
|
||||
self.world.taskMgr.doMethodLater(0.001, self._reset_frame_flag, "reset_frame_flag")
|
||||
@ -920,7 +995,10 @@ class VRManager(DirectObject):
|
||||
# 由于左右眼都会调用回调,确保每帧只调用一次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()
|
||||
# 缓存当前姿态供下一帧使用,符合OpenVR时序假设
|
||||
self._cache_poses_for_next_frame()
|
||||
# 使用缓存的姿态更新相机(上一帧的姿态)
|
||||
self._update_camera_poses_with_cache()
|
||||
self._poses_updated_this_frame = True
|
||||
# 在帧结束时重置标记
|
||||
self.world.taskMgr.doMethodLater(0.001, self._reset_frame_flag, "reset_frame_flag")
|
||||
@ -1355,4 +1433,35 @@ class VRManager(DirectObject):
|
||||
Args:
|
||||
object_node: 要标记的对象节点
|
||||
"""
|
||||
self.interaction_manager._add_collision_to_object(object_node)
|
||||
self.interaction_manager._add_collision_to_object(object_node)
|
||||
|
||||
def _disable_async_reprojection(self):
|
||||
"""禁用异步重投影 - 备选修复方案"""
|
||||
try:
|
||||
# 尝试通过OpenVR设置禁用异步重投影
|
||||
if hasattr(openvr, 'VRSettings'):
|
||||
settings = openvr.VRSettings()
|
||||
if settings:
|
||||
# 禁用异步重投影
|
||||
error = settings.setBool("steamvr", "enableAsyncReprojection", False)
|
||||
if error == openvr.VRSettingsError_None:
|
||||
print("✅ 异步重投影已禁用")
|
||||
else:
|
||||
print(f"⚠️ 禁用异步重投影失败: 设置错误 {error}")
|
||||
else:
|
||||
print("⚠️ 无法获取VR设置接口")
|
||||
else:
|
||||
print("⚠️ OpenVR设置接口不可用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ 禁用异步重投影失败: {e}")
|
||||
|
||||
def enable_async_reprojection_disable(self):
|
||||
"""启用异步重投影禁用选项 - 用户可调用的方法"""
|
||||
self.disable_async_reprojection = True
|
||||
print("📝 异步重投影禁用选项已启用,将在下次VR初始化时生效")
|
||||
|
||||
def disable_async_reprojection_disable(self):
|
||||
"""禁用异步重投影禁用选项 - 恢复默认行为"""
|
||||
self.disable_async_reprojection = False
|
||||
print("📝 异步重投影禁用选项已关闭,将使用默认ATW行为")
|
||||
@ -1 +0,0 @@
|
||||
Subproject commit 3f9567897552df6c10078bc124795101cf478f91
|
||||
Loading…
Reference in New Issue
Block a user