- 添加对有线连接的支持,特别是 Pico 4 的有线连接 - 改进 ALVR 服务器检测和连接逻辑 - 优化 VR 帧获取和处理流程 - 增加备用帧获取功能(主摄像机视图) - 修复 VR 眼部纹理相关问题 - 优化 VR 任务管理,确保正确渲染和提交帧
500 lines
17 KiB
Python
500 lines
17 KiB
Python
#!/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. 初始化VR:world.initializeVR()")
|
||
print(" 3. 启动ALVR:world.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() |