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

480 lines
18 KiB
Python
Executable File
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
import time
# 添加项目根目录到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
import numpy as np
def test_openxr_basic_display(world):
"""测试基本OpenXR显示功能"""
print("=== OpenXR基本显示测试 ===")
# 加载一些模型来展示
print("📦 加载演示场景...")
try:
# 创建一些简单的几何体作为演示
from panda3d.core import CardMaker, Vec4
# 创建地面
cm = CardMaker("ground")
cm.setFrame(-10, 10, -10, 10)
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)
# 创建一些立方体
for i in range(5):
for j in range(5):
cube = world.loader.loadModel("models/environment")
if not cube:
# 如果没有environment模型创建简单的立方体
cm_cube = CardMaker(f"cube_{i}_{j}")
cm_cube.setFrame(-0.5, 0.5, -0.5, 0.5)
cube = world.render.attachNewNode(cm_cube.generate())
cube.setPos(i * 2 - 4, j * 2 - 4, 0)
cube.setScale(0.5)
cube.setColor(i/5.0, j/5.0, 1.0, 1.0)
print("✓ 演示场景加载完成")
except Exception as e:
print(f"场景加载错误: {str(e)}")
# 初始化OpenXR系统
print("\n🥽 初始化OpenXR显示系统...")
openxr_success = world.initializeOpenXR()
if openxr_success:
print("✓ OpenXR系统初始化成功")
openxr_info = world.getOpenXRInfo()
print(f"\n📊 OpenXR显示信息:")
print(f" - 模式: {openxr_info['mode']}")
print(f" - 渲染尺寸: {openxr_info['render_size']}")
print(f" - 模拟模式: {openxr_info['simulation_mode']}")
print(f" - 有线连接: {openxr_info['wired_connection']}")
if openxr_info['simulation_mode']:
print("\n💡 模拟模式说明:")
print(" - 左右眼视图将并排显示在主窗口")
print(" - 可以看到立体渲染效果")
print(" - 头部会有轻微的模拟摆动")
else:
print("\n💡 真实OpenXR模式:")
print(" - 画面将渲染到VR头盔")
print(" - 支持真实的头部追踪")
print(" - 控制器交互可用")
# 创建显示窗口
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
# 创建主窗口显示OpenXR渲染结果
window = QMainWindow()
window.setWindowTitle("OpenXR Stereo Rendering Preview")
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():
if hasattr(world.openxr_manager, 'left_eye_texture') and world.openxr_manager.left_eye_texture:
# 获取左眼纹理数据
tex = world.openxr_manager.left_eye_texture
try:
if tex.get_x_size() > 0 and tex.get_y_size() > 0:
# 添加对纹理数据有效性的检查
if tex.might_have_ram_image():
# 使用正确的API将纹理数据复制到QImage
data = tex.get_ram_image().get_data()
if data:
img = QImage(data, tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
left_label.setPixmap(pixmap.scaled(400, 300))
left_label.setText("") # 清除文字,只显示图像
else:
left_label.setText("Left Eye (No Data)")
else:
left_label.setText("Left Eye (No RAM Image)")
else:
left_label.setText("Left Eye (Invalid Size)")
except Exception as e:
print(f"左眼纹理更新错误: {str(e)}")
left_label.setText("Left Eye (Error)")
else:
left_label.setText("Left Eye (No Texture)")
if hasattr(world.openxr_manager, 'right_eye_texture') and world.openxr_manager.right_eye_texture:
# 获取右眼纹理数据
tex = world.openxr_manager.right_eye_texture
try:
if tex.get_x_size() > 0 and tex.get_y_size() > 0:
# 添加对纹理数据有效性的检查
if tex.might_have_ram_image():
# 使用正确的API将纹理数据复制到QImage
data = tex.get_ram_image().get_data()
if data:
img = QImage(data, tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
right_label.setPixmap(pixmap.scaled(400, 300))
right_label.setText("") # 清除文字,只显示图像
else:
right_label.setText("Right Eye (No Data)")
else:
right_label.setText("Right Eye (No RAM Image)")
else:
right_label.setText("Right Eye (Invalid Size)")
except Exception as e:
print(f"右眼纹理更新错误: {str(e)}")
right_label.setText("Right Eye (Error)")
else:
right_label.setText("Right Eye (No Texture)")
timer = QTimer()
timer.timeout.connect(update_display)
timer.start(33) # 约30 FPS
# 运行几秒钟以展示效果
print(f"\n🎮 OpenXR显示测试运行中... (10秒)")
print(" 观察主窗口中的立体渲染效果")
start_time = time.time()
while time.time() - start_time < 10:
# 处理Panda3D事件
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
# 处理Qt事件
try:
app.processEvents()
except Exception as e:
print(f"Qt事件处理错误: {str(e)}")
# 添加短暂延迟以避免过度占用CPU
time.sleep(0.016) # ~60 FPS
print("✓ OpenXR显示测试完成")
else:
print("✗ OpenXR系统初始化失败")
return False
# 关闭OpenXR系统
world.shutdownOpenXR()
print("\n✓ OpenXR系统已关闭")
return True
def test_openxr_streaming(world):
"""测试OpenXR串流功能"""
print("=== OpenXR串流测试 ===")
# 初始化OpenXR系统
print("初始化OpenXR系统...")
if not world.initializeOpenXR():
print("✗ OpenXR系统初始化失败")
return False
# 启动输入处理
print("启动OpenXR输入处理...")
if not world.startOpenXRInput():
print("⚠ OpenXR输入处理启动失败")
# 初始化串流
print("初始化OpenXR串流...")
if world.initializeOpenXRStreaming():
print("✓ OpenXR串流初始化成功")
# 开始串流
print("开始OpenXR串流...")
if world.startOpenXRStreaming():
print("✓ OpenXR串流已开始")
# 创建显示窗口
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
# 创建主窗口显示OpenXR渲染结果
window = QMainWindow()
window.setWindowTitle("OpenXR Streaming Preview")
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:
# 更新左眼纹理
if hasattr(world.openxr_manager, 'left_eye_texture') and world.openxr_manager.left_eye_texture:
tex = world.openxr_manager.left_eye_texture
# 检查纹理尺寸和数据有效性
if tex.get_x_size() > 0 and tex.get_y_size() > 0 and tex.might_have_ram_image():
ram_image = tex.get_ram_image()
if ram_image and ram_image.get_data():
# 使用正确的数据访问方法
img = QImage(ram_image.get_data(), tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
left_label.setPixmap(pixmap.scaled(400, 300))
left_label.setText("") # 清除文字,只显示图像
# 更新右眼纹理
if hasattr(world.openxr_manager, 'right_eye_texture') and world.openxr_manager.right_eye_texture:
tex = world.openxr_manager.right_eye_texture
# 检查纹理尺寸和数据有效性
if tex.get_x_size() > 0 and tex.get_y_size() > 0 and tex.might_have_ram_image():
ram_image = tex.get_ram_image()
if ram_image and ram_image.get_data():
# 使用正确的数据访问方法
img = QImage(ram_image.get_data(), tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
right_label.setPixmap(pixmap.scaled(400, 300))
right_label.setText("") # 清除文字,只显示图像
except Exception as e:
print(f"纹理更新错误: {str(e)}")
# 清除可能已损坏的纹理引用
if hasattr(world.openxr_manager, 'left_eye_texture'):
world.openxr_manager.left_eye_texture = None
if hasattr(world.openxr_manager, 'right_eye_texture'):
world.openxr_manager.right_eye_texture = None
timer = QTimer()
timer.timeout.connect(update_display)
timer.start(33) # 约30 FPS
# 运行几秒钟
print("OpenXR串流运行中... (5秒)")
start_time = time.time()
while time.time() - start_time < 5:
# 处理Panda3D事件
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
# 处理Qt事件
try:
app.processEvents()
except Exception as e:
print(f"Qt事件处理错误: {str(e)}")
time.sleep(0.016) # ~60 FPS
# 停止串流
world.stopOpenXRStreaming()
print("✓ OpenXR串流已停止")
else:
print("✗ OpenXR串流启动失败")
else:
print("✗ OpenXR串流初始化失败")
# 关闭系统
world.shutdownOpenXRStreaming()
world.stopOpenXRInput()
world.shutdownOpenXR()
print("✓ OpenXR串流测试完成")
return True
def test_openxr_full(world):
"""测试完整OpenXR功能"""
print("=== 完整OpenXR功能测试 ===")
# 初始化OpenXR系统
print("初始化OpenXR系统...")
if not world.initializeOpenXR():
print("✗ OpenXR系统初始化失败")
return False
# 创建显示窗口
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
# 创建主窗口显示OpenXR渲染结果
window = QMainWindow()
window.setWindowTitle("OpenXR Full Functionality Preview")
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:
# 更新左眼纹理
if hasattr(world.openxr_manager, 'left_eye_texture') and world.openxr_manager.left_eye_texture:
tex = world.openxr_manager.left_eye_texture
# 检查纹理尺寸和数据有效性
if tex.get_x_size() > 0 and tex.get_y_size() > 0 and tex.might_have_ram_image():
ram_image = tex.get_ram_image()
if ram_image and ram_image.get_data():
# 使用正确的数据访问方法
img = QImage(ram_image.get_data(), tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
left_label.setPixmap(pixmap.scaled(400, 300))
left_label.setText("") # 清除文字,只显示图像
# 更新右眼纹理
if hasattr(world.openxr_manager, 'right_eye_texture') and world.openxr_manager.right_eye_texture:
tex = world.openxr_manager.right_eye_texture
# 检查纹理尺寸和数据有效性
if tex.get_x_size() > 0 and tex.get_y_size() > 0 and tex.might_have_ram_image():
ram_image = tex.get_ram_image()
if ram_image and ram_image.get_data():
# 使用正确的数据访问方法
img = QImage(ram_image.get_data(), tex.get_x_size(), tex.get_y_size(), QImage.Format_RGBA8888)
pixmap = QPixmap.fromImage(img)
right_label.setPixmap(pixmap.scaled(400, 300))
right_label.setText("") # 清除文字,只显示图像
except Exception as e:
print(f"纹理更新错误: {str(e)}")
# 清除可能已损坏的纹理引用
if hasattr(world.openxr_manager, 'left_eye_texture'):
world.openxr_manager.left_eye_texture = None
if hasattr(world.openxr_manager, 'right_eye_texture'):
world.openxr_manager.right_eye_texture = None
timer = QTimer()
timer.timeout.connect(update_display)
timer.start(33) # 约30 FPS
# 一键启用OpenXR模式
print("启用OpenXR模式...")
if world.enableOpenXRMode():
print("✓ OpenXR模式已启用")
# 启动输入处理
print("启动OpenXR输入处理...")
if not world.startOpenXRInput():
print("⚠ OpenXR输入处理启动失败")
# 获取状态
openxr_info = world.getOpenXRInfo()
print(f"\n📊 OpenXR状态:")
print(f" - 启用: {openxr_info['enabled']}")
print(f" - 模式: {openxr_info['mode']}")
print(f" - 模拟模式: {openxr_info['simulation_mode']}")
print(f" - 渲染尺寸: {openxr_info['render_size']}")
print(f" - 有线连接: {openxr_info['wired_connection']}")
# 获取状态
status = world.getOpenXRStatus()
print(f"\n📊 OpenXR状态:")
print(f" - 启用: {status['openxr_enabled']}")
print(f" - 连接: {status['openxr_connected']}")
print(f" - 串流: {status['openxr_streaming']}")
print(f" - 控制器: {len(status['controllers'])}")
if status['streaming_status']:
streaming_status = status['streaming_status']
print(f"\n📡 串流状态:")
print(f" - FPS: {streaming_status['fps']}")
print(f" - 分辨率: {streaming_status['resolution']}")
print(f" - 延迟: {streaming_status['latency']}ms")
# 运行一段时间
print(f"\n🎮 OpenXR完整功能运行中... (15秒)")
start_time = time.time()
while time.time() - start_time < 15:
# 处理Panda3D事件
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
# 处理Qt事件
try:
app.processEvents()
except Exception as e:
print(f"Qt事件处理错误: {str(e)}")
time.sleep(0.016) # ~60 FPS
# 禁用OpenXR模式
world.shutdownOpenXR()
print("✓ OpenXR模式已禁用")
else:
print("✗ OpenXR模式启用失败")
return False
# 关闭系统
world.stopOpenXRInput()
world.shutdownOpenXR()
print("✓ 完整OpenXR功能测试完成")
return True
if __name__ == "__main__":
print("OpenXR功能测试")
print("===============")
# 创建世界实例(只创建一次)
world = MyWorld()
# 运行测试
print("1. 基本显示测试")
test_openxr_basic_display(world)
print("\n" + "="*50 + "\n")
print("2. 串流功能测试")
test_openxr_streaming(world)
print("\n" + "="*50 + "\n")
print("3. 完整功能测试")
test_openxr_full(world)
print("\n" + "="*50)
print("所有测试完成!")