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

279 lines
9.6 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.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
简单的OpenXR测试脚本
在主程序基础上直接添加OpenXR相关代码进行测试
"""
import sys
import os
# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from main import MyWorld
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QLabel
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import QTimer
# Panda3D imports
from panda3d.core import Texture, GraphicsOutput, ATSNone, GraphicsPipe, Vec3
def setup_openxr_simulation(world):
"""在主程序基础上设置简单的OpenXR模拟"""
print("🔧 设置OpenXR模拟环境...")
# 获取渲染尺寸
render_width = 1280
render_height = 720
# 创建左右眼渲染缓冲区
from panda3d.core import WindowProperties, FrameBufferProperties, GraphicsPipe
# 创建窗口属性
winprops = WindowProperties()
winprops.setSize(render_width//2, render_height)
# 创建帧缓冲区属性
fbprops = FrameBufferProperties()
fbprops.setRgbColor(True)
fbprops.setRgbaBits(8, 8, 8, 8)
fbprops.setDepthBits(24)
# 设置渲染标志和GSG
flags = GraphicsPipe.BFRefuseWindow
gsg = world.win.getGsg()
left_eye_buffer = world.graphicsEngine.makeOutput(
world.pipe,
"left_eye",
-1000,
fbprops,
winprops,
flags,
gsg,
world.win
)
right_eye_buffer = world.graphicsEngine.makeOutput(
world.pipe,
"right_eye",
-1000,
fbprops,
winprops,
flags,
gsg,
world.win
)
if not left_eye_buffer or not right_eye_buffer:
print("❌ 无法创建眼部渲染缓冲区")
return None, None
# 创建用于显示的左右眼纹理,使用与主程序相同的方式
left_eye_texture = Texture("left_eye_texture")
right_eye_texture = Texture("right_eye_texture")
left_eye_texture.set_format(Texture.F_rgba8) # 使用主程序的设置方式
right_eye_texture.set_format(Texture.F_rgba8)
left_eye_texture.set_component_type(Texture.T_unsigned_byte)
right_eye_texture.set_component_type(Texture.T_unsigned_byte)
# 将纹理附加到渲染缓冲区,使用与主程序相同的方式
left_eye_buffer.add_render_texture(left_eye_texture, GraphicsOutput.RTM_copy_ram)
right_eye_buffer.add_render_texture(right_eye_texture, GraphicsOutput.RTM_copy_ram)
# 创建左右眼相机
left_eye_camera = world.makeCamera(left_eye_buffer)
right_eye_camera = world.makeCamera(right_eye_buffer)
# 设置相机参数,确保与主相机一致
left_eye_camera.node().get_lens().set_fov(world.camLens.get_fov())
right_eye_camera.node().get_lens().set_fov(world.camLens.get_fov())
left_eye_camera.node().get_lens().set_near(world.camLens.get_near())
right_eye_camera.node().get_lens().set_near(world.camLens.get_near())
left_eye_camera.node().get_lens().set_far(world.camLens.get_far())
right_eye_camera.node().get_lens().set_far(world.camLens.get_far())
# 设置相机位置(模拟瞳距)
left_eye_camera.setPos(world.cam.getPos() + Vec3(-0.03, 0, 0)) # 瞳距的一半
right_eye_camera.setPos(world.cam.getPos() + Vec3(0.03, 0, 0)) # 瞳距的一半
# 设置相机朝向,确保与主相机一致
left_eye_camera.setHpr(world.cam.getHpr())
right_eye_camera.setHpr(world.cam.getHpr())
# 设置相机渲染场景
left_eye_camera.node().setScene(world.render)
right_eye_camera.node().setScene(world.render)
# 获取渲染管线的最终输出纹理
def get_final_render_texture():
"""获取渲染管线的最终输出纹理"""
# 修复:正确获取最终渲染纹理的方法
if world.win:
# 直接从主窗口获取最终渲染纹理
return world.win.get_texture()
return None
# 等待并获取渲染结果
def wait_for_render_texture():
"""等待并获取有效的渲染纹理"""
timeout = 100 # 超时帧数
for i in range(timeout):
final_texture = get_final_render_texture()
if final_texture and final_texture.hasRamImage():
return final_texture
world.graphicsEngine.renderFrame()
return None
# 获取最终渲染纹理作为左右眼纹理的基础
final_texture = wait_for_render_texture()
if final_texture:
# 使用与主渲染管线相同的纹理参数
left_eye_texture = final_texture.makeCopy()
right_eye_texture = final_texture.makeCopy()
# 确保纹理数据可用
world.graphicsEngine.extractTextureData(left_eye_texture, world.win.getGsg())
world.graphicsEngine.extractTextureData(right_eye_texture, world.win.getGsg())
print("✅ 成功获取渲染管线的最终输出纹理")
else:
print("⚠️ 无法获取渲染管线的最终输出纹理,使用默认设置")
print("✅ OpenXR模拟环境设置完成")
return left_eye_texture, right_eye_texture
def main():
"""主函数"""
print("🚀 启动OpenXR简单测试...")
# 创建应用程序和世界实例
app = QApplication(sys.argv)
world = MyWorld()
# 加载一些测试模型
print("📦 加载测试场景...")
from panda3d.core import CardMaker
# 创建地面
cm = CardMaker("ground")
cm.setFrame(-5, 5, -5, 5)
ground = world.render.attachNewNode(cm.generate())
ground.setPos(0, 0, -1)
ground.setColor(0.5, 0.8, 0.5, 1.0)
ground.setHpr(0, -90, 0)
# 创建测试立方体
cube = world.loader.loadModel("models/environment")
if cube:
cube.reparentTo(world.render)
cube.setScale(0.5)
cube.setPos(0, 0, 0)
else:
# 如果没有环境模型,创建简单立方体
cm_cube = CardMaker("cube")
cm_cube.setFrame(-0.5, 0.5, -0.5, 0.5)
cube = world.render.attachNewNode(cm_cube.generate())
cube.setPos(0, 0, 0)
# 设置OpenXR模拟
left_tex, right_tex = setup_openxr_simulation(world)
if not left_tex or not right_tex:
print("❌ OpenXR模拟设置失败")
return
# 创建显示窗口
window = QMainWindow()
window.setWindowTitle("OpenXR Simple Test")
window.setGeometry(100, 100, 800, 300)
central_widget = QWidget()
layout = QHBoxLayout()
central_widget.setLayout(layout)
left_label = QLabel("Left Eye")
right_label = QLabel("Right Eye")
layout.addWidget(left_label)
layout.addWidget(right_label)
window.setCentralWidget(central_widget)
window.show()
def update_display():
"""更新显示"""
try:
# 让RenderPipeline进行渲染
world.taskMgr.step()
# 渲染几帧以确保纹理更新
for _ in range(5):
world.graphicsEngine.renderFrame()
# 更新左眼纹理
if left_tex:
# 检查纹理是否具有RAM图像
if not left_tex.hasRamImage():
# 如果没有RAM图像尝试提取
gsg = world.win.getGsg()
if gsg:
world.graphicsEngine.extractTextureData(left_tex, gsg)
# 现在检查是否有RAM图像和有效数据
if left_tex.hasRamImage():
data = left_tex.getRamImage().getData()
width = left_tex.getXSize()
height = left_tex.getYSize()
expected_len = width * height * 4
# 检查数据长度是否正确
if len(data) == expected_len:
# 使用与主程序相同的方式创建图像
img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
pixmap = QPixmap.fromImage(img)
left_label.setPixmap(pixmap.scaled(400, 300))
left_label.setText("")
# 更新右眼纹理
if right_tex:
# 检查纹理是否具有RAM图像
if not right_tex.hasRamImage():
# 如果没有RAM图像尝试提取
gsg = world.win.getGsg()
if gsg:
world.graphicsEngine.extractTextureData(right_tex, gsg)
# 现在检查是否有RAM图像和有效数据
if right_tex.hasRamImage():
data = right_tex.getRamImage().getData()
width = right_tex.getXSize()
height = right_tex.getYSize()
expected_len = width * height * 4
# 检查数据长度是否正确
if len(data) == expected_len:
# 使用与主程序相同的方式创建图像
img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
pixmap = QPixmap.fromImage(img)
right_label.setPixmap(pixmap.scaled(400, 300))
right_label.setText("")
except Exception as e:
print(f"纹理更新错误: {str(e)}")
# 定时更新显示
timer = QTimer()
timer.timeout.connect(update_display)
timer.start(33) # 约30 FPS
# 运行应用程序
print("✅ OpenXR简单测试运行中...")
sys.exit(app.exec_())
if __name__ == "__main__":
main()