EG/vr_display_demo.py
Rowland bb56813e44 feat(core): 优化 ALVR 串流功能并添加对 Pico 4 的支持
- 添加对有线连接的支持,特别是 Pico 4 的有线连接
- 改进 ALVR 服务器检测和连接逻辑
- 优化 VR 帧获取和处理流程
- 增加备用帧获取功能(主摄像机视图)
- 修复 VR 眼部纹理相关问题
- 优化 VR 任务管理,确保正确渲染和提交帧
2025-07-29 10:17:13 +08:00

500 lines
17 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 python3
# -*- coding: utf-8 -*-
"""
VR显示功能演示脚本
演示引擎画面在VR中的显示效果包括ALVR串流
"""
import sys
import os
import time
from main import MyWorld
def demo_vr_basic_display():
"""演示基本VR显示功能"""
print("=== VR基本显示演示 ===")
# 创建世界实例
world = MyWorld()
# 加载一些模型来展示
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("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)}")
# 初始化VR系统
print("\n🥽 初始化VR显示系统...")
vr_success = world.initializeVR()
if vr_success:
print("✓ VR系统初始化成功")
vr_info = world.getVRInfo()
print(f"\n📊 VR显示信息:")
print(f" - 模式: {vr_info['mode']}")
print(f" - 渲染尺寸: {vr_info['render_size']}")
print(f" - 模拟模式: {vr_info['simulation_mode']}")
if vr_info['simulation_mode']:
print("\n💡 模拟模式说明:")
print(" - 左右眼视图将并排显示在主窗口")
print(" - 可以看到立体渲染效果")
print(" - 头部会有轻微的模拟摆动")
else:
print("\n💡 真实VR模式:")
print(" - 画面将渲染到VR头盔")
print(" - 支持真实的头部追踪")
print(" - 控制器交互可用")
# 运行几秒钟以展示效果
print(f"\n🎮 VR显示演示运行中... (10秒)")
print(" 观察主窗口中的立体渲染效果")
start_time = time.time()
while time.time() - start_time < 10:
# 处理Panda3D事件
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
time.sleep(0.016) # ~60 FPS
print("✓ VR显示演示完成")
else:
print("✗ VR系统初始化失败")
return False
# 关闭VR系统
world.shutdownVR()
print("\n✓ VR系统已关闭")
return True
def demo_alvr_streaming():
"""演示ALVR串流功能"""
print("=== ALVR串流显示演示 ===")
# 创建世界实例
world = MyWorld()
# 首先初始化VR系统
print("🥽 初始化VR系统...")
if not world.initializeVR():
print("✗ VR系统初始化失败")
return False
# 检查是否为直连模式SteamVR已运行
if world.alvr_streamer._is_steamvr_active():
print("💡 检测到SteamVR正在运行将使用直连模式")
print(" 在直连模式下画面将直接通过SteamVR传输到头显")
print(" 无需通过ALVR服务器进行额外的串流处理")
# 初始化ALVR串流
print("\n📡 初始化ALVR串流...")
print("💡 检测到VR设备已连接正在尝试连接ALVR服务器...")
alvr_success = world.initializeALVR()
if alvr_success:
print("✓ ALVR串流初始化成功")
# 设置串流质量
print("\n🎥 配置串流质量...")
quality_set = world.setALVRStreamQuality(2880, 1700, 72, 150)
if quality_set:
print(" ✓ 串流质量: 2880x1700@72fps, 150Mbps")
# 获取串流状态
status = world.getALVRStreamingStatus()
print(f"\n📊 ALVR串流状态:")
print(f" - 连接状态: {status['connected']}")
print(f" - 串流状态: {status['streaming']}")
print(f" - 分辨率: {status['resolution']}")
print(f" - 帧率: {status['fps']}")
print(f" - 码率: {status['bitrate']}Mbps")
# 开始串流
print(f"\n🚀 开始ALVR串流...")
if world.startALVRStreaming():
print("✓ ALVR串流已开始")
print(f"\n💡 ALVR串流说明:")
print(" - 引擎画面正在串流到VR头盔")
print(" - 支持Quest 2/3/Pico 4等VR设备")
print(" - 确保ALVR客户端在头盔中运行")
print(" - 检查网络连接质量")
# 运行串流演示
print(f"\n📡 ALVR串流演示运行中... (15秒)")
start_time = time.time()
while time.time() - start_time < 15:
# 更新串流状态
current_status = world.getALVRStreamingStatus()
if time.time() - start_time > 5: # 5秒后显示状态更新
print(f" 当前FPS: {current_status['fps']}, 延迟: {current_status['latency']}ms")
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
time.sleep(0.016)
# 停止串流
print("\n🛑 停止ALVR串流...")
world.stopALVRStreaming()
print("✓ ALVR串流已停止")
else:
print("⚠ ALVR串流启动失败")
print(" 可能原因:")
print(" - ALVR服务器未运行")
print(" - VR客户端未连接")
print(" - 网络连接问题")
print(" - 防火墙阻止连接")
else:
print("⚠ ALVR串流初始化失败")
print("💡 这可能是因为:")
print(" 1. ALVR服务器未运行")
print(" 2. SteamVR正在使用独占模式")
print(" 3. 端口冲突")
print("\n🔧 Pico 4有线连接设置建议:")
print(" 1. 确保ALVR服务器正在运行")
print(" 2. 检查任务管理器中是否有alvr_server进程")
print(" 3. 尝试重启ALVR服务器")
print(" 4. 确认防火墙允许ALVR通信")
print(" 5. 检查ALVR服务器端口设置")
print(" 6. 如果SteamVR正在运行尝试先关闭它")
print("\n💡 直连模式说明:")
print(" 如果您使用的是有线连接如Pico 4通过USB-C连接")
print(" 并且SteamVR已经可以正常显示画面您可能不需要ALVR串流")
print(" SteamVR会直接处理渲染并将画面传输到头显")
# 关闭系统
world.shutdownALVR()
world.shutdownVR()
print("\n✓ 所有系统已关闭")
return True
def demo_vr_interaction():
"""演示VR交互功能"""
print("=== VR交互显示演示 ===")
# 创建世界实例
world = MyWorld()
# 初始化VR系统
print("🥽 初始化VR系统...")
if not world.initializeVR():
print("✗ VR系统初始化失败")
return False
# 启动VR输入处理
print("\n🎮 启动VR输入处理...")
if world.startVRInput():
print("✓ VR输入处理已启动")
# 显示控制器射线
world.showControllerRays(True)
print("✓ 控制器射线已启用")
# 启用VR交互
world.setVRInteractionEnabled(True)
world.setVRGestureEnabled(True)
print("✓ VR交互和手势识别已启用")
# 获取控制器状态
print(f"\n🎮 控制器状态:")
controllers = world.getAllControllers()
for i, controller in enumerate(controllers):
if controller:
state = world.getControllerState(i)
print(f" 控制器 {i}: 可用")
if state:
print(f" - 连接: {state.get('connected', False)}")
print(f" - 扳机: {state.get('trigger', 0):.2f}")
print(f" - 握把: {state.get('grip', 0):.2f}")
# 运行交互演示
print(f"\n🤏 VR交互演示运行中... (10秒)")
print(" - 控制器射线可见")
print(" - 扳机:抓取物体")
print(" - 握把:切换交互模式")
print(" - 触摸板:导航控制")
start_time = time.time()
while time.time() - start_time < 10:
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
time.sleep(0.016)
# 停止VR输入
world.stopVRInput()
print("✓ VR输入处理已停止")
else:
print("⚠ VR输入处理启动失败")
# 关闭VR系统
world.shutdownVR()
print("\n✓ VR系统已关闭")
return True
def demo_comprehensive_vr():
"""综合VR显示演示"""
print("=== 综合VR显示演示 ===")
# 创建世界实例
world = MyWorld()
# 创建丰富的演示场景
print("🎨 创建VR演示场景...")
try:
from panda3d.core import CardMaker, Vec4, AmbientLight, DirectionalLight
# 添加光照
ambient_light = AmbientLight('ambient')
ambient_light.setColor(Vec4(0.3, 0.3, 0.3, 1))
ambient_light_np = world.render.attachNewNode(ambient_light)
world.render.setLight(ambient_light_np)
directional_light = DirectionalLight('directional')
directional_light.setColor(Vec4(0.8, 0.8, 0.8, 1))
directional_light.setDirection(Vec4(-1, -1, -1, 0))
directional_light_np = world.render.attachNewNode(directional_light)
world.render.setLight(directional_light_np)
# 创建地面网格
for i in range(-5, 6):
for j in range(-5, 6):
cm = CardMaker(f"grid_{i}_{j}")
cm.setFrame(-0.4, 0.4, -0.4, 0.4)
grid = world.render.attachNewNode(cm.generate())
grid.setPos(i * 1.0, j * 1.0, -1)
grid.setHpr(0, -90, 0)
# 棋盘格颜色
if (i + j) % 2 == 0:
grid.setColor(0.8, 0.8, 0.8, 1.0)
else:
grid.setColor(0.6, 0.6, 0.6, 1.0)
# 创建一些彩色立方体
for i in range(8):
cm = CardMaker(f"cube_{i}")
cm.setFrame(-0.3, 0.3, -0.3, 0.3)
cube = world.render.attachNewNode(cm.generate())
import math
angle = i * math.pi * 2 / 8
radius = 3
cube.setPos(math.cos(angle) * radius, math.sin(angle) * radius, 0.5)
cube.setHpr(i * 45, 0, 0)
cube.setScale(1, 1, 2)
# 彩虹颜色
hue = i / 8.0
r = abs(math.sin(hue * math.pi * 2))
g = abs(math.sin((hue + 0.33) * math.pi * 2))
b = abs(math.sin((hue + 0.66) * math.pi * 2))
cube.setColor(r, g, b, 1.0)
print("✓ VR演示场景创建完成")
except Exception as e:
print(f"场景创建错误: {str(e)}")
# 完整的VR系统演示
print("\n🥽 启动完整VR系统...")
# 1. 初始化VR
if not world.initializeVR():
print("✗ VR系统初始化失败")
return False
print("✓ VR显示系统已启动")
# 2. 启动VR输入
if world.startVRInput():
world.showControllerRays(True)
world.setVRInteractionEnabled(True)
print("✓ VR交互系统已启动")
# 3. 尝试启动ALVR串流
if world.initializeALVR():
world.setALVRStreamQuality(2880, 1700, 72, 100)
if world.startALVRStreaming():
print("✓ ALVR串流已启动")
else:
print("⚠ ALVR串流启动失败")
else:
print("⚠ ALVR初始化失败正常如果没有ALVR服务器")
# 运行综合演示
print(f"\n🎬 综合VR显示演示运行中... (20秒)")
print("💡 功能说明:")
print(" - 立体渲染显示")
print(" - 头部追踪(模拟或真实)")
print(" - 控制器可视化")
print(" - ALVR无线串流")
print(" - VR交互功能")
start_time = time.time()
frame_count = 0
while time.time() - start_time < 20:
# 处理引擎更新
if hasattr(world, 'taskMgr'):
world.taskMgr.step()
frame_count += 1
# 每5秒显示一次状态
elapsed = time.time() - start_time
if frame_count % 300 == 0: # 约每5秒
fps = frame_count / elapsed
print(f" 运行状态: {elapsed:.1f}s, FPS: {fps:.1f}")
# 显示VR状态
vr_info = world.getVRInfo()
print(f" VR模式: {vr_info['mode']}, 分辨率: {vr_info['render_size']}")
if world.isALVRStreaming():
alvr_status = world.getALVRStreamingStatus()
print(f" ALVR: FPS {alvr_status['fps']}, 延迟 {alvr_status['latency']}ms")
time.sleep(0.016) # ~60 FPS
print("✓ 综合VR演示完成")
# 关闭所有系统
world.stopVRInput()
world.stopALVRStreaming()
world.shutdownALVR()
world.shutdownVR()
print("\n✓ 所有VR系统已关闭")
return True
def print_vr_display_guide():
"""打印VR显示指南"""
print("📋 VR显示功能指南")
print("=" * 50)
print("\n🎯 功能概述:")
print(" - 立体渲染:为左右眼生成不同视角的画面")
print(" - 头部追踪:根据头部运动调整视角")
print(" - ALVR串流无线串流到Quest等VR设备")
print(" - 控制器交互支持VR控制器输入")
print("\n🔧 使用方法:")
print(" 1. 运行引擎python3 main.py")
print(" 2. 初始化VRworld.initializeVR()")
print(" 3. 启动ALVRworld.initializeALVR()")
print(" 4. 开始串流world.startALVRStreaming()")
print("\n📱 ALVR设置步骤:")
print(" 1. 下载ALVR服务器到PC")
print(" 2. 在Quest中安装ALVR客户端")
print(" 3. 确保PC和Quest在同一WiFi网络")
print(" 4. 启动ALVR服务器")
print(" 5. 在Quest中连接到PC")
print(" 6. 运行引擎VR演示")
print("\n🎮 VR模式说明:")
print(" 模拟模式:")
print(" - 无需VR硬件")
print(" - 立体视图显示在主窗口")
print(" - 模拟头部和控制器追踪")
print(" - 适合开发和调试")
print(" ")
print(" 真实VR模式:")
print(" - 需要VR头盔和SteamVR")
print(" - 真实的立体渲染和追踪")
print(" - 支持控制器交互")
print(" - 完整的VR体验")
print("\n🛠 故障排除:")
print(" - VR初始化失败 → 自动切换到模拟模式")
print(" - ALVR连接失败 → 检查网络和服务器")
print(" - 画面不显示 → 检查VR头盔和SteamVR")
print(" - 延迟过高 → 降低串流质量或使用有线连接")
def main():
"""主函数"""
print("🎮 VR显示功能演示")
print("=" * 50)
print("请选择演示类型:")
print("1. 基本VR显示演示")
print("2. ALVR串流演示")
print("3. VR交互演示")
print("4. 综合VR演示")
print("5. VR显示功能指南")
try:
choice = input("请输入选择 (1-5): ")
if choice == "1":
success = demo_vr_basic_display()
elif choice == "2":
success = demo_alvr_streaming()
elif choice == "3":
success = demo_vr_interaction()
elif choice == "4":
success = demo_comprehensive_vr()
elif choice == "5":
print_vr_display_guide()
return
else:
print("无效的选择")
return
print("\n" + "=" * 50)
if success:
print("✓ VR显示演示成功完成")
print("🎉 引擎画面VR显示功能正常工作")
else:
print("✗ VR显示演示遇到问题")
print("💡 请检查VR系统设置和连接")
except KeyboardInterrupt:
print("\n用户中断演示")
except Exception as e:
print(f"演示过程中发生错误: {str(e)}")
if __name__ == "__main__":
main()