EG/core/openxr_manager.py
Rowland 72819341ef docs(README): 添加项目README文档
- 创建详细的README文档,介绍项目功能、架构、使用方法等
- 新增.pyc文件和目录,用于缓存编译后的Python代码
- 添加.lingma规则文件,用于代码格式检查
- 删除ALVR串流处理器代码,准备替换为OpenXR输入处理器
- 新增OpenXR输入处理器代码,处理VR控制器输入
2025-07-29 17:46:08 +08:00

342 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
OpenXR管理器
负责OpenXR系统初始化、追踪和渲染
支持有线VR串流功能
"""
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
from panda3d.core import *
from panda3d.core import Mat4, PerspectiveLens, CardMaker
# 修复taskMgr导入错误应该从TaskManagerGlobal导入而不是ShowBaseGlobal
from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
import sys
class OpenXRManager(DirectObject):
"""OpenXR管理器 - 处理OpenXR系统初始化、追踪和渲染"""
def __init__(self, world):
super().__init__()
self.world = world
self.openxr_enabled = False
self.xr_instance = None
self.xr_system = None
self.xr_session = None
# 渲染配置
self.render_width = 1920
self.render_height = 1080
# 有线连接设置
self.wired_connection = True
self.connection_ip = "127.0.0.1"
self.connection_port = 9943
# 模拟模式设置(用于开发测试)
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.left_eye_texture = None
self.right_eye_texture = None
self.eye_textures = {}
# 控制器相关
self.controller_nodes = {}
self.controller_poses = {}
print("✓ OpenXR管理器初始化完成")
def initialize_openxr(self, force_simulation=False):
"""初始化OpenXR系统"""
try:
# 检查是否强制使用模拟模式
if force_simulation:
print("🔧 强制启用OpenXR模拟模式")
return self._init_simulation_mode()
# 检查OpenXR支持
if not self._check_openxr_support():
print("⚠ OpenXR支持不可用切换到模拟模式")
return self._init_simulation_mode()
# 尝试初始化OpenXR
if not self._init_openxr_native():
print("⚠ OpenXR初始化失败切换到模拟模式")
print("提示: 请确保OpenXR运行时已安装且VR头盔已连接")
return self._init_simulation_mode()
# 真实OpenXR模式初始化成功
print("✓ 真实OpenXR模式初始化成功")
return self._init_real_openxr_mode()
except Exception as e:
print(f"OpenXR初始化错误: {str(e)}")
print("⚠ 切换到模拟模式")
return self._init_simulation_mode()
def _check_openxr_support(self):
"""检查OpenXR支持"""
try:
# TODO: 实际检查OpenXR运行时支持
# 这里暂时返回False以使用模拟模式进行开发
return False
except:
return False
def _init_openxr_native(self):
"""初始化原生OpenXR"""
# TODO: 实现OpenXR初始化逻辑
print(" OpenXR原生初始化占位符")
return False
def _init_real_openxr_mode(self):
"""初始化真实OpenXR模式"""
self.openxr_enabled = True
self.simulation_mode = False
# TODO: 实现实际的OpenXR设置
# 1. 创建OpenXR实例
# 2. 获取系统信息
# 3. 创建会话
# 4. 设置渲染目标
# 5. 初始化控制器
return True
def _init_simulation_mode(self):
"""初始化模拟模式"""
self.openxr_enabled = True
self.simulation_mode = True
# 设置模拟渲染尺寸
self.render_width = self.simulation_data['render_size'][0]
self.render_height = self.simulation_data['render_size'][1]
# 初始化模拟立体渲染
self._setup_simulation_rendering()
print(" OpenXR模拟模式已启用")
print(f" 渲染尺寸: {self.render_width}x{self.render_height}")
print(" 头部追踪: 模拟摆动")
print(" 控制器: 模拟位置")
return True
def _setup_simulation_rendering(self):
"""设置模拟渲染"""
print("🔧 OpenXR模拟模式: 开始设置渲染")
# 创建左右眼渲染缓冲区
self.left_eye_buffer = self._create_eye_buffer("left_eye", self.render_width//2, self.render_height)
self.right_eye_buffer = self._create_eye_buffer("right_eye", self.render_width//2, self.render_height)
print(f" 创建眼部缓冲区: 左眼={self.left_eye_buffer is not None}, 右眼={self.right_eye_buffer is not None}")
# 创建左右眼相机
self.left_eye_camera = self._create_eye_camera("left_eye_camera", (-0.03, 0, 0)) # 瞳距的一半
self.right_eye_camera = self._create_eye_camera("right_eye_camera", (0.03, 0, 0)) # 瞳距的一半)
print(f" 创建眼部相机: 左眼={self.left_eye_camera is not None}, 右眼={self.right_eye_camera is not None}")
# 创建用于显示的左右眼纹理,格式与主程序保持一致
self.left_eye_texture = Texture("left_eye_texture")
self.right_eye_texture = Texture("right_eye_texture")
self.left_eye_texture.setFormat(Texture.F_rgba8)
self.right_eye_texture.setFormat(Texture.F_rgba8)
self.left_eye_texture.setComponentType(Texture.T_unsigned_byte)
self.right_eye_texture.setComponentType(Texture.T_unsigned_byte)
print(f" 创建眼部纹理: 左眼={self.left_eye_texture is not None}, 右眼={self.right_eye_texture is not None}")
print(" 设置纹理格式为F_rgba8和T_unsigned_byte")
# 设置自动纹理缩放为None
self.left_eye_texture.setAutoTextureScale(ATSNone)
self.right_eye_texture.setAutoTextureScale(ATSNone)
print(" 设置自动纹理缩放为ATSNone")
# 将纹理附加到渲染缓冲区使用RTMCopyRam模式确保数据能被复制到RAM
left_result = self.left_eye_buffer.addRenderTexture(self.left_eye_texture, GraphicsOutput.RTMCopyRam)
right_result = self.right_eye_buffer.addRenderTexture(self.right_eye_texture, GraphicsOutput.RTMCopyRam)
print(f" 添加渲染纹理结果: 左眼={left_result}, 右眼={right_result}")
# 设置相机渲染目标
if self.left_eye_buffer and self.left_eye_camera:
self.left_eye_camera.node().setScene(self.world.render)
print(" 设置左眼相机渲染场景")
if self.right_eye_buffer and self.right_eye_camera:
self.right_eye_camera.node().setScene(self.world.render)
print(" 设置右眼相机渲染场景")
self.eye_textures['left'] = self.left_eye_texture
self.eye_textures['right'] = self.right_eye_texture
print(" 初始化完成,开始渲染帧")
# 强制渲染多帧以便初始化纹理数据
# 参考主程序的实现方式,渲染足够多的帧以确保数据填充
for i in range(5): # 渲染5帧以确保纹理数据被正确填充
self.world.graphicsEngine.renderFrame()
print(f" 渲染第{i+1}")
# 提取纹理数据到RAM
gsg = self.world.win.getGsg()
print(f" 获取GSG: {gsg is not None}")
if gsg:
self.world.graphicsEngine.extractTextureData(self.left_eye_texture, gsg)
self.world.graphicsEngine.extractTextureData(self.right_eye_texture, gsg)
print(" 提取纹理数据到RAM")
# 检查纹理数据是否成功提取
left_has_ram = self.left_eye_texture.hasRamImage()
right_has_ram = self.right_eye_texture.hasRamImage()
print(f" 纹理RAM图像检查: 左眼={left_has_ram}, 右眼={right_has_ram}")
if left_has_ram:
left_data_size = len(self.left_eye_texture.getRamImage().getData())
print(f" 左眼纹理数据大小: {left_data_size} 字节")
if right_has_ram:
right_data_size = len(self.right_eye_texture.getRamImage().getData())
print(f" 右眼纹理数据大小: {right_data_size} 字节")
def get_left_eye_texture(self):
"""获取左眼纹理用于显示"""
return self.left_eye_texture
def get_right_eye_texture(self):
"""获取右眼纹理用于显示"""
return self.right_eye_texture
def _create_eye_buffer(self, name, width, height):
"""创建眼部渲染缓冲区"""
# 创建帧缓冲区属性
fb_prop = FrameBufferProperties()
fb_prop.setRgbColor(True)
fb_prop.setRgbaBits(8, 8, 8, 8)
fb_prop.setDepthBits(24)
# 创建窗口属性
win_prop = WindowProperties()
win_prop.setSize(width, height)
# 创建缓冲区
buffer = self.world.graphicsEngine.makeOutput(
self.world.pipe,
name,
-1000, # 低优先级
fb_prop,
win_prop,
GraphicsPipe.BFRefuseWindow
)
return buffer
def _create_eye_camera(self, name, position_offset):
"""创建眼部相机"""
# 创建相机节点
camera_node = Camera(name)
lens = PerspectiveLens()
lens.setFov(100) # VR镜头视野
lens.setNear(0.1)
lens.setFar(1000.0)
camera_node.setLens(lens)
# 创建相机节点路径
camera_np = self.world.render.attachNewNode(camera_node)
camera_np.setPos(*position_offset)
return camera_np
def shutdown_openxr(self):
"""关闭OpenXR系统"""
if not self.openxr_enabled:
return True
try:
# 清理渲染缓冲区
if self.left_eye_buffer:
self.world.graphicsEngine.removeWindow(self.left_eye_buffer)
self.left_eye_buffer = None
if self.right_eye_buffer:
self.world.graphicsEngine.removeWindow(self.right_eye_buffer)
self.right_eye_buffer = None
# 清理相机
if self.left_eye_camera:
self.left_eye_camera.removeNode()
self.left_eye_camera = None
if self.right_eye_camera:
self.right_eye_camera.removeNode()
self.right_eye_camera = None
# 重置状态
self.openxr_enabled = False
self.xr_instance = None
self.xr_system = None
self.xr_session = None
print("✓ OpenXR系统已关闭")
return True
except Exception as e:
print(f"OpenXR关闭错误: {str(e)}")
return False
def is_openxr_enabled(self):
"""检查OpenXR是否启用"""
return self.openxr_enabled
def get_openxr_info(self):
"""获取OpenXR系统信息"""
return {
"enabled": self.openxr_enabled,
"mode": "simulation" if self.simulation_mode else "real",
"render_size": (self.render_width, self.render_height),
"simulation_mode": self.simulation_mode,
"wired_connection": self.wired_connection
}
def update_simulation_data(self, data_type, data):
"""更新模拟数据"""
if data_type in self.simulation_data:
self.simulation_data[data_type] = data
return True
return False
def get_simulation_data(self, data_type=None):
"""获取模拟数据"""
if data_type:
return self.simulation_data.get(data_type, None)
return self.simulation_data
def enable_simulation_mode(self):
"""启用模拟模式"""
if not self.simulation_mode:
self.shutdown_openxr()
self.simulation_mode = True
self.initialize_openxr(force_simulation=True)