forked from Rowland/EG
412 lines
15 KiB
Python
412 lines
15 KiB
Python
"""
|
||
VR控制面板
|
||
|
||
提供VR系统的GUI控制界面
|
||
包括VR启用/禁用、ALVR串流控制、性能监控等功能
|
||
"""
|
||
|
||
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
|
||
QPushButton, QLabel, QProgressBar, QSlider,
|
||
QSpinBox, QCheckBox, QComboBox, QTextEdit,
|
||
QGridLayout, QFrame, QSizePolicy)
|
||
from PyQt5.QtCore import Qt, QTimer, pyqtSignal
|
||
from PyQt5.QtGui import QFont, QColor, QPalette
|
||
|
||
|
||
class VRControlPanel(QWidget):
|
||
"""VR控制面板"""
|
||
|
||
# 信号定义
|
||
vr_enabled = pyqtSignal(bool)
|
||
alvr_streaming_changed = pyqtSignal(bool)
|
||
|
||
def __init__(self, world, parent=None):
|
||
super().__init__(parent)
|
||
self.world = world
|
||
self.setupUI()
|
||
self.connectSignals()
|
||
|
||
# 设置更新定时器
|
||
self.update_timer = QTimer()
|
||
self.update_timer.timeout.connect(self.updateStatus)
|
||
self.update_timer.start(1000) # 每秒更新一次
|
||
|
||
def setupUI(self):
|
||
"""设置界面"""
|
||
self.setWindowTitle("VR控制面板")
|
||
self.setMinimumSize(400, 600)
|
||
|
||
# 主布局
|
||
main_layout = QVBoxLayout(self)
|
||
|
||
# VR系统控制组
|
||
vr_control_group = self.createVRControlGroup()
|
||
main_layout.addWidget(vr_control_group)
|
||
|
||
# ALVR串流控制组
|
||
alvr_control_group = self.createALVRControlGroup()
|
||
main_layout.addWidget(alvr_control_group)
|
||
|
||
# 性能监控组
|
||
performance_group = self.createPerformanceGroup()
|
||
main_layout.addWidget(performance_group)
|
||
|
||
# 控制器状态组
|
||
controller_group = self.createControllerGroup()
|
||
main_layout.addWidget(controller_group)
|
||
|
||
# 日志输出组
|
||
log_group = self.createLogGroup()
|
||
main_layout.addWidget(log_group)
|
||
|
||
# 添加弹性空间
|
||
main_layout.addStretch()
|
||
|
||
def createVRControlGroup(self):
|
||
"""创建VR系统控制组"""
|
||
group = QGroupBox("VR系统控制")
|
||
layout = QVBoxLayout(group)
|
||
|
||
# 状态指示器
|
||
self.vr_status_label = QLabel("VR状态: 未启用")
|
||
self.vr_status_label.setStyleSheet("color: red; font-weight: bold;")
|
||
layout.addWidget(self.vr_status_label)
|
||
|
||
# 启用/禁用VR按钮
|
||
button_layout = QHBoxLayout()
|
||
self.enable_vr_button = QPushButton("启用VR")
|
||
self.enable_vr_button.clicked.connect(self.enableVR)
|
||
button_layout.addWidget(self.enable_vr_button)
|
||
|
||
self.disable_vr_button = QPushButton("禁用VR")
|
||
self.disable_vr_button.clicked.connect(self.disableVR)
|
||
self.disable_vr_button.setEnabled(False)
|
||
button_layout.addWidget(self.disable_vr_button)
|
||
|
||
layout.addLayout(button_layout)
|
||
|
||
# VR设备信息
|
||
self.vr_info_label = QLabel("VR设备: 未连接")
|
||
layout.addWidget(self.vr_info_label)
|
||
|
||
# VR选项
|
||
options_layout = QGridLayout()
|
||
|
||
# 控制器射线显示
|
||
self.show_rays_checkbox = QCheckBox("显示控制器射线")
|
||
self.show_rays_checkbox.stateChanged.connect(self.toggleControllerRays)
|
||
options_layout.addWidget(self.show_rays_checkbox, 0, 0)
|
||
|
||
# 手势识别
|
||
self.gesture_checkbox = QCheckBox("启用手势识别")
|
||
self.gesture_checkbox.stateChanged.connect(self.toggleGestureRecognition)
|
||
options_layout.addWidget(self.gesture_checkbox, 0, 1)
|
||
|
||
# VR交互
|
||
self.interaction_checkbox = QCheckBox("启用VR交互")
|
||
self.interaction_checkbox.setChecked(True)
|
||
self.interaction_checkbox.stateChanged.connect(self.toggleVRInteraction)
|
||
options_layout.addWidget(self.interaction_checkbox, 1, 0)
|
||
|
||
layout.addLayout(options_layout)
|
||
|
||
return group
|
||
|
||
def createALVRControlGroup(self):
|
||
"""创建ALVR串流控制组"""
|
||
group = QGroupBox("ALVR串流控制")
|
||
layout = QVBoxLayout(group)
|
||
|
||
# 连接状态
|
||
self.alvr_status_label = QLabel("ALVR状态: 未连接")
|
||
self.alvr_status_label.setStyleSheet("color: red; font-weight: bold;")
|
||
layout.addWidget(self.alvr_status_label)
|
||
|
||
# 串流控制按钮
|
||
button_layout = QHBoxLayout()
|
||
self.start_streaming_button = QPushButton("开始串流")
|
||
self.start_streaming_button.clicked.connect(self.startStreaming)
|
||
self.start_streaming_button.setEnabled(False)
|
||
button_layout.addWidget(self.start_streaming_button)
|
||
|
||
self.stop_streaming_button = QPushButton("停止串流")
|
||
self.stop_streaming_button.clicked.connect(self.stopStreaming)
|
||
self.stop_streaming_button.setEnabled(False)
|
||
button_layout.addWidget(self.stop_streaming_button)
|
||
|
||
layout.addLayout(button_layout)
|
||
|
||
# 串流质量设置
|
||
quality_layout = QGridLayout()
|
||
|
||
# 分辨率
|
||
quality_layout.addWidget(QLabel("分辨率宽度:"), 0, 0)
|
||
self.width_spinbox = QSpinBox()
|
||
self.width_spinbox.setRange(1920, 4096)
|
||
self.width_spinbox.setValue(2880)
|
||
self.width_spinbox.setSuffix(" px")
|
||
quality_layout.addWidget(self.width_spinbox, 0, 1)
|
||
|
||
quality_layout.addWidget(QLabel("分辨率高度:"), 1, 0)
|
||
self.height_spinbox = QSpinBox()
|
||
self.height_spinbox.setRange(1080, 2160)
|
||
self.height_spinbox.setValue(1700)
|
||
self.height_spinbox.setSuffix(" px")
|
||
quality_layout.addWidget(self.height_spinbox, 1, 1)
|
||
|
||
# 帧率
|
||
quality_layout.addWidget(QLabel("帧率:"), 2, 0)
|
||
self.fps_spinbox = QSpinBox()
|
||
self.fps_spinbox.setRange(60, 120)
|
||
self.fps_spinbox.setValue(72)
|
||
self.fps_spinbox.setSuffix(" fps")
|
||
quality_layout.addWidget(self.fps_spinbox, 2, 1)
|
||
|
||
# 比特率
|
||
quality_layout.addWidget(QLabel("比特率:"), 3, 0)
|
||
self.bitrate_spinbox = QSpinBox()
|
||
self.bitrate_spinbox.setRange(50, 500)
|
||
self.bitrate_spinbox.setValue(150)
|
||
self.bitrate_spinbox.setSuffix(" Mbps")
|
||
quality_layout.addWidget(self.bitrate_spinbox, 3, 1)
|
||
|
||
layout.addLayout(quality_layout)
|
||
|
||
# 应用设置按钮
|
||
self.apply_quality_button = QPushButton("应用质量设置")
|
||
self.apply_quality_button.clicked.connect(self.applyQualitySettings)
|
||
layout.addWidget(self.apply_quality_button)
|
||
|
||
return group
|
||
|
||
def createPerformanceGroup(self):
|
||
"""创建性能监控组"""
|
||
group = QGroupBox("性能监控")
|
||
layout = QGridLayout(group)
|
||
|
||
# FPS显示
|
||
layout.addWidget(QLabel("渲染FPS:"), 0, 0)
|
||
self.fps_label = QLabel("0")
|
||
self.fps_label.setStyleSheet("font-weight: bold; color: blue;")
|
||
layout.addWidget(self.fps_label, 0, 1)
|
||
|
||
# 串流FPS
|
||
layout.addWidget(QLabel("串流FPS:"), 1, 0)
|
||
self.stream_fps_label = QLabel("0")
|
||
self.stream_fps_label.setStyleSheet("font-weight: bold; color: green;")
|
||
layout.addWidget(self.stream_fps_label, 1, 1)
|
||
|
||
# 延迟
|
||
layout.addWidget(QLabel("延迟:"), 2, 0)
|
||
self.latency_label = QLabel("0 ms")
|
||
self.latency_label.setStyleSheet("font-weight: bold; color: orange;")
|
||
layout.addWidget(self.latency_label, 2, 1)
|
||
|
||
# 性能进度条
|
||
layout.addWidget(QLabel("CPU使用率:"), 3, 0)
|
||
self.cpu_progress = QProgressBar()
|
||
self.cpu_progress.setRange(0, 100)
|
||
layout.addWidget(self.cpu_progress, 3, 1)
|
||
|
||
layout.addWidget(QLabel("GPU使用率:"), 4, 0)
|
||
self.gpu_progress = QProgressBar()
|
||
self.gpu_progress.setRange(0, 100)
|
||
layout.addWidget(self.gpu_progress, 4, 1)
|
||
|
||
return group
|
||
|
||
def createControllerGroup(self):
|
||
"""创建控制器状态组"""
|
||
group = QGroupBox("控制器状态")
|
||
layout = QVBoxLayout(group)
|
||
|
||
# 控制器列表
|
||
self.controller_list = QTextEdit()
|
||
self.controller_list.setMaximumHeight(100)
|
||
self.controller_list.setReadOnly(True)
|
||
layout.addWidget(self.controller_list)
|
||
|
||
# 触觉反馈测试
|
||
haptic_layout = QHBoxLayout()
|
||
haptic_layout.addWidget(QLabel("触觉反馈测试:"))
|
||
|
||
self.haptic_button = QPushButton("发送震动")
|
||
self.haptic_button.clicked.connect(self.sendHapticFeedback)
|
||
haptic_layout.addWidget(self.haptic_button)
|
||
|
||
layout.addLayout(haptic_layout)
|
||
|
||
return group
|
||
|
||
def createLogGroup(self):
|
||
"""创建日志输出组"""
|
||
group = QGroupBox("系统日志")
|
||
layout = QVBoxLayout(group)
|
||
|
||
self.log_text = QTextEdit()
|
||
self.log_text.setMaximumHeight(150)
|
||
self.log_text.setReadOnly(True)
|
||
layout.addWidget(self.log_text)
|
||
|
||
# 清空日志按钮
|
||
clear_button = QPushButton("清空日志")
|
||
clear_button.clicked.connect(self.clearLog)
|
||
layout.addWidget(clear_button)
|
||
|
||
return group
|
||
|
||
def connectSignals(self):
|
||
"""连接信号"""
|
||
# 连接值变化信号
|
||
self.width_spinbox.valueChanged.connect(self.onQualityChanged)
|
||
self.height_spinbox.valueChanged.connect(self.onQualityChanged)
|
||
self.fps_spinbox.valueChanged.connect(self.onQualityChanged)
|
||
self.bitrate_spinbox.valueChanged.connect(self.onQualityChanged)
|
||
|
||
def enableVR(self):
|
||
"""启用VR"""
|
||
self.addLog("正在启用VR模式...")
|
||
if self.world.enableVRMode():
|
||
self.addLog("✓ VR模式已启用")
|
||
self.vr_enabled.emit(True)
|
||
else:
|
||
self.addLog("✗ VR模式启用失败")
|
||
|
||
def disableVR(self):
|
||
"""禁用VR"""
|
||
self.addLog("正在禁用VR模式...")
|
||
self.world.disableVRMode()
|
||
self.addLog("✓ VR模式已禁用")
|
||
self.vr_enabled.emit(False)
|
||
|
||
def startStreaming(self):
|
||
"""开始串流"""
|
||
self.addLog("正在开始ALVR串流...")
|
||
if self.world.startALVRStreaming():
|
||
self.addLog("✓ ALVR串流已开始")
|
||
self.alvr_streaming_changed.emit(True)
|
||
else:
|
||
self.addLog("✗ ALVR串流开始失败")
|
||
|
||
def stopStreaming(self):
|
||
"""停止串流"""
|
||
self.addLog("正在停止ALVR串流...")
|
||
self.world.stopALVRStreaming()
|
||
self.addLog("✓ ALVR串流已停止")
|
||
self.alvr_streaming_changed.emit(False)
|
||
|
||
def toggleControllerRays(self, checked):
|
||
"""切换控制器射线显示"""
|
||
self.world.showControllerRays(checked)
|
||
self.addLog(f"控制器射线: {'显示' if checked else '隐藏'}")
|
||
|
||
def toggleGestureRecognition(self, checked):
|
||
"""切换手势识别"""
|
||
self.world.setVRGestureEnabled(checked)
|
||
self.addLog(f"手势识别: {'启用' if checked else '禁用'}")
|
||
|
||
def toggleVRInteraction(self, checked):
|
||
"""切换VR交互"""
|
||
self.world.setVRInteractionEnabled(checked)
|
||
self.addLog(f"VR交互: {'启用' if checked else '禁用'}")
|
||
|
||
def applyQualitySettings(self):
|
||
"""应用质量设置"""
|
||
width = self.width_spinbox.value()
|
||
height = self.height_spinbox.value()
|
||
fps = self.fps_spinbox.value()
|
||
bitrate = self.bitrate_spinbox.value()
|
||
|
||
self.world.setALVRStreamQuality(width, height, fps, bitrate)
|
||
self.addLog(f"串流质量已设置: {width}x{height} @ {fps}fps, {bitrate}Mbps")
|
||
|
||
def sendHapticFeedback(self):
|
||
"""发送触觉反馈"""
|
||
controllers = self.world.getAllControllers()
|
||
if controllers:
|
||
controller_id = controllers[0] # 使用第一个控制器
|
||
self.world.sendHapticFeedback(controller_id, 0.5, 0.8)
|
||
self.addLog(f"已发送触觉反馈到控制器 {controller_id}")
|
||
else:
|
||
self.addLog("没有可用的控制器")
|
||
|
||
def onQualityChanged(self):
|
||
"""质量设置变化"""
|
||
# 可以在这里实现实时质量调整
|
||
pass
|
||
|
||
def updateStatus(self):
|
||
"""更新状态显示"""
|
||
# 更新VR状态
|
||
vr_status = self.world.getVRStatus()
|
||
|
||
# VR系统状态
|
||
if vr_status['vr_enabled']:
|
||
self.vr_status_label.setText("VR状态: 已启用")
|
||
self.vr_status_label.setStyleSheet("color: green; font-weight: bold;")
|
||
self.enable_vr_button.setEnabled(False)
|
||
self.disable_vr_button.setEnabled(True)
|
||
|
||
# 更新VR设备信息
|
||
vr_info = vr_status['vr_info']
|
||
if vr_info:
|
||
device_info = f"VR设备: {vr_info.get('hmd_manufacturer', 'Unknown')} {vr_info.get('hmd_model', 'Unknown')}"
|
||
self.vr_info_label.setText(device_info)
|
||
else:
|
||
self.vr_status_label.setText("VR状态: 未启用")
|
||
self.vr_status_label.setStyleSheet("color: red; font-weight: bold;")
|
||
self.enable_vr_button.setEnabled(True)
|
||
self.disable_vr_button.setEnabled(False)
|
||
self.vr_info_label.setText("VR设备: 未连接")
|
||
|
||
# ALVR状态
|
||
if vr_status['alvr_connected']:
|
||
self.alvr_status_label.setText("ALVR状态: 已连接")
|
||
self.alvr_status_label.setStyleSheet("color: green; font-weight: bold;")
|
||
self.start_streaming_button.setEnabled(not vr_status['alvr_streaming'])
|
||
self.stop_streaming_button.setEnabled(vr_status['alvr_streaming'])
|
||
else:
|
||
self.alvr_status_label.setText("ALVR状态: 未连接")
|
||
self.alvr_status_label.setStyleSheet("color: red; font-weight: bold;")
|
||
self.start_streaming_button.setEnabled(False)
|
||
self.stop_streaming_button.setEnabled(False)
|
||
|
||
# 性能统计
|
||
streaming_status = vr_status['streaming_status']
|
||
if streaming_status:
|
||
self.stream_fps_label.setText(str(streaming_status.get('fps', 0)))
|
||
self.latency_label.setText(f"{streaming_status.get('latency', 0)} ms")
|
||
|
||
# 控制器状态
|
||
controllers = vr_status['controllers']
|
||
if controllers:
|
||
controller_text = f"已连接 {len(controllers)} 个控制器:\n"
|
||
for i, controller_id in enumerate(controllers):
|
||
controller_text += f"控制器 {i+1}: ID {controller_id}\n"
|
||
self.controller_list.setText(controller_text)
|
||
else:
|
||
self.controller_list.setText("没有连接的控制器")
|
||
|
||
def addLog(self, message):
|
||
"""添加日志"""
|
||
import datetime
|
||
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
||
log_message = f"[{timestamp}] {message}"
|
||
self.log_text.append(log_message)
|
||
print(log_message) # 同时输出到控制台
|
||
|
||
def clearLog(self):
|
||
"""清空日志"""
|
||
self.log_text.clear()
|
||
|
||
def closeEvent(self, event):
|
||
"""关闭事件"""
|
||
# 停止更新定时器
|
||
if hasattr(self, 'update_timer'):
|
||
self.update_timer.stop()
|
||
|
||
# 如果VR启用,先禁用
|
||
if self.world.isVREnabled():
|
||
self.disableVR()
|
||
|
||
event.accept() |