Add comprehensive detailed design documents
This commit is contained in:
754
src-python/docs/details/overlay.md
Normal file
754
src-python/docs/details/overlay.md
Normal file
@@ -0,0 +1,754 @@
|
||||
# overlay - VRオーバーレイ統合システム
|
||||
|
||||
## 概要
|
||||
|
||||
VRChat向けのOpenVRオーバーレイシステムです。翻訳結果や字幕をVR空間内に表示する機能を提供し、HMD・コントローラー追跡、フェード効果、多言語フォント対応を統合的に管理します。
|
||||
|
||||
## 主要コンポーネント
|
||||
|
||||
### overlay.py - メインオーバーレイ管理
|
||||
- OpenVRオーバーレイの生成・配置・制御
|
||||
- HMD・左手・右手への追跡設定
|
||||
- フェードイン・フェードアウト効果
|
||||
|
||||
### overlay_image.py - 画像生成・描画
|
||||
- 多言語対応テキスト画像生成
|
||||
- メッセージログ・履歴表示
|
||||
- フォント・レイアウト管理
|
||||
|
||||
### overlay_utils.py - 数学的変換ユーティリティ
|
||||
- 3D座標変換行列計算
|
||||
- オイラー角・回転行列変換
|
||||
- 同次座標系変換
|
||||
|
||||
## クラス構造
|
||||
|
||||
### Overlay クラス (overlay.py)
|
||||
|
||||
```python
|
||||
class Overlay:
|
||||
def __init__(self, settings_dict: Dict[str, Dict[str, Any]]) -> None:
|
||||
self.system: Optional[Any] = None # OpenVRシステム
|
||||
self.overlay: Optional[Any] = None # オーバーレイインターface
|
||||
self.handle: Dict[str, Any] = {} # サイズ別ハンドル
|
||||
self.settings: Dict[str, Dict[str, Any]] # サイズ別設定
|
||||
self.lastUpdate: Dict[str, float] = {} # 最終更新時刻
|
||||
self.fadeRatio: Dict[str, float] = {} # フェード比率
|
||||
```
|
||||
|
||||
VRオーバーレイの総合管理クラス
|
||||
|
||||
#### 主要機能
|
||||
- OpenVRの初期化・管理
|
||||
- 複数サイズオーバーレイの同時管理
|
||||
- リアルタイムフェード効果処理
|
||||
- SteamVR接続状態監視
|
||||
|
||||
### OverlayImage クラス (overlay_image.py)
|
||||
|
||||
```python
|
||||
class OverlayImage:
|
||||
LANGUAGES = {
|
||||
"Default": "NotoSansJP-Regular.ttf",
|
||||
"Japanese": "NotoSansJP-Regular.ttf",
|
||||
"Korean": "NotoSansKR-Regular.ttf",
|
||||
"Chinese Simplified": "NotoSansSC-Regular.ttf",
|
||||
"Chinese Traditional": "NotoSansTC-Regular.ttf"
|
||||
}
|
||||
|
||||
def __init__(self, root_path: Optional[str] = None) -> None:
|
||||
self.message_log: List[dict] = []
|
||||
self.root_path: str
|
||||
```
|
||||
|
||||
テキスト画像生成・多言語フォント管理クラス
|
||||
|
||||
#### 主要機能
|
||||
- 多言語フォント自動選択
|
||||
- メッセージ履歴管理
|
||||
- 動的画像生成・合成
|
||||
- UI要素のサイズ計算
|
||||
|
||||
## 主要メソッド
|
||||
|
||||
### Overlay クラス
|
||||
|
||||
#### 初期化・制御
|
||||
|
||||
```python
|
||||
def startOverlay(self) -> None
|
||||
```
|
||||
|
||||
オーバーレイシステム開始
|
||||
|
||||
```python
|
||||
def shutdownOverlay(self) -> None
|
||||
```
|
||||
|
||||
オーバーレイシステム終了・リソース解放
|
||||
|
||||
```python
|
||||
def reStartOverlay(self) -> None
|
||||
```
|
||||
|
||||
オーバーレイシステム再起動
|
||||
|
||||
#### 表示制御
|
||||
|
||||
```python
|
||||
def showOverlay(self, image: Image, size: str) -> None
|
||||
```
|
||||
|
||||
画像をオーバーレイに表示
|
||||
|
||||
#### パラメータ
|
||||
- **image**: 表示するPIL画像
|
||||
- **size**: オーバーレイサイズ識別子
|
||||
|
||||
```python
|
||||
def setOpacity(self, opacity: float, size: str) -> None
|
||||
```
|
||||
|
||||
オーバーレイ透明度設定
|
||||
|
||||
#### パラメータ
|
||||
- **opacity**: 透明度(0.0-1.0)
|
||||
- **size**: 対象サイズ
|
||||
|
||||
```python
|
||||
def setTrackedDeviceRelative(self, tracker: str, size: str) -> None
|
||||
```
|
||||
|
||||
追跡デバイスへのオーバーレイ配置
|
||||
|
||||
#### パラメータ
|
||||
- **tracker**: 追跡デバイス("HMD", "LeftHand", "RightHand")
|
||||
- **size**: オーバーレイサイズ
|
||||
|
||||
### OverlayImage クラス
|
||||
|
||||
#### 画像生成
|
||||
|
||||
```python
|
||||
def createOverlayImage(self, message: str, language: str, ui_size: dict,
|
||||
ui_settings: dict, message_log_settings: dict) -> Image
|
||||
```
|
||||
|
||||
オーバーレイ用画像の生成
|
||||
|
||||
#### パラメータ
|
||||
- **message**: 表示メッセージ
|
||||
- **language**: 言語設定
|
||||
- **ui_size**: UIサイズ設定
|
||||
- **ui_settings**: UI表示設定
|
||||
- **message_log_settings**: ログ表示設定
|
||||
|
||||
#### 戻り値
|
||||
- **Image**: 生成されたPIL画像
|
||||
|
||||
#### 履歴管理
|
||||
|
||||
```python
|
||||
def addMessageLog(self, message: str, timestamp: datetime) -> None
|
||||
```
|
||||
|
||||
メッセージログに新規追加
|
||||
|
||||
#### パラメータ
|
||||
- **message**: 追加するメッセージ
|
||||
- **timestamp**: タイムスタンプ
|
||||
|
||||
```python
|
||||
def clearMessageLog(self) -> None
|
||||
```
|
||||
|
||||
メッセージログのクリア
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本的なオーバーレイ表示
|
||||
|
||||
```python
|
||||
from models.overlay.overlay import Overlay
|
||||
from models.overlay.overlay_image import OverlayImage
|
||||
from PIL import Image
|
||||
|
||||
# オーバーレイ設定
|
||||
settings = {
|
||||
"small": {
|
||||
"width": 0.3,
|
||||
"height": 0.1,
|
||||
"x_pos": 0.0,
|
||||
"y_pos": -0.2,
|
||||
"z_pos": 1.0,
|
||||
"opacity": 0.8,
|
||||
"display_duration": 3.0,
|
||||
"fadeout_duration": 1.0
|
||||
},
|
||||
"large": {
|
||||
"width": 0.5,
|
||||
"height": 0.2,
|
||||
"x_pos": 0.0,
|
||||
"y_pos": -0.3,
|
||||
"z_pos": 1.2,
|
||||
"opacity": 0.9,
|
||||
"display_duration": 5.0,
|
||||
"fadeout_duration": 1.5
|
||||
}
|
||||
}
|
||||
|
||||
# オーバーレイシステム初期化
|
||||
overlay_system = Overlay(settings)
|
||||
overlay_image = OverlayImage()
|
||||
|
||||
# システム開始
|
||||
overlay_system.startOverlay()
|
||||
|
||||
# 翻訳結果の表示
|
||||
translation_text = "Hello, world! / こんにちは、世界!"
|
||||
|
||||
# 画像生成設定
|
||||
ui_size = OverlayImage.getUiSizeSmallLog()
|
||||
ui_settings = {
|
||||
"font_size": 20,
|
||||
"text_color": (255, 255, 255, 255),
|
||||
"background_color": (0, 0, 0, 180)
|
||||
}
|
||||
message_log_settings = {
|
||||
"enabled": True,
|
||||
"max_lines": 5
|
||||
}
|
||||
|
||||
# 画像生成・表示
|
||||
overlay_img = overlay_image.createOverlayImage(
|
||||
message=translation_text,
|
||||
language="Japanese",
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings=message_log_settings
|
||||
)
|
||||
|
||||
# オーバーレイに表示
|
||||
overlay_system.showOverlay(overlay_img, "small")
|
||||
|
||||
# システム終了
|
||||
import time
|
||||
time.sleep(10)
|
||||
overlay_system.shutdownOverlay()
|
||||
```
|
||||
|
||||
### HMD・コントローラー追跡設定
|
||||
|
||||
```python
|
||||
# HMDに固定表示
|
||||
overlay_system.setTrackedDeviceRelative("HMD", "large")
|
||||
|
||||
# 左手コントローラーに追従
|
||||
overlay_system.setTrackedDeviceRelative("LeftHand", "small")
|
||||
|
||||
# 右手コントローラーに追従
|
||||
overlay_system.setTrackedDeviceRelative("RightHand", "small")
|
||||
|
||||
# 位置・回転の微調整(設定変更)
|
||||
overlay_system.settings["small"]["x_pos"] = 0.1
|
||||
overlay_system.settings["small"]["y_pos"] = -0.1
|
||||
overlay_system.settings["small"]["z_pos"] = 0.8
|
||||
overlay_system.settings["small"]["x_rotation"] = -30.0
|
||||
overlay_system.settings["small"]["y_rotation"] = 15.0
|
||||
|
||||
# 設定を適用
|
||||
overlay_system.setTrackedDeviceRelative("LeftHand", "small")
|
||||
```
|
||||
|
||||
### フェード効果制御
|
||||
|
||||
```python
|
||||
# フェード効果設定
|
||||
overlay_system.updateDisplayDuration(4.0, "large") # 4秒表示
|
||||
overlay_system.updateFadeoutDuration(2.0, "large") # 2秒でフェードアウト
|
||||
|
||||
# 即座に透明度変更
|
||||
overlay_system.setOpacity(0.5, "large") # 50%透明度
|
||||
|
||||
# フェード効果を無効にして固定表示
|
||||
overlay_system.settings["small"]["fadeout_duration"] = 0
|
||||
overlay_system.setOpacity(1.0, "small") # 完全不透明で固定
|
||||
```
|
||||
|
||||
### 多言語対応表示
|
||||
|
||||
```python
|
||||
# 日本語表示
|
||||
japanese_text = "これは日本語のテストです"
|
||||
jp_image = overlay_image.createOverlayImage(
|
||||
message=japanese_text,
|
||||
language="Japanese",
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings=message_log_settings
|
||||
)
|
||||
overlay_system.showOverlay(jp_image, "large")
|
||||
|
||||
# 韓国語表示
|
||||
korean_text = "이것은 한국어 테스트입니다"
|
||||
kr_image = overlay_image.createOverlayImage(
|
||||
message=korean_text,
|
||||
language="Korean",
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings=message_log_settings
|
||||
)
|
||||
overlay_system.showOverlay(kr_image, "small")
|
||||
|
||||
# 中国語(簡体字)表示
|
||||
chinese_text = "这是中文测试"
|
||||
cn_image = overlay_image.createOverlayImage(
|
||||
message=chinese_text,
|
||||
language="Chinese Simplified",
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings=message_log_settings
|
||||
)
|
||||
overlay_system.showOverlay(cn_image, "large")
|
||||
```
|
||||
|
||||
### メッセージログ機能
|
||||
|
||||
```python
|
||||
from datetime import datetime
|
||||
|
||||
# メッセージログの追加
|
||||
overlay_image.addMessageLog("最初のメッセージ", datetime.now())
|
||||
overlay_image.addMessageLog("翻訳結果: Hello -> こんにちは", datetime.now())
|
||||
overlay_image.addMessageLog("音声認識: こんにちは", datetime.now())
|
||||
|
||||
# ログ表示設定
|
||||
log_settings = {
|
||||
"enabled": True,
|
||||
"max_lines": 3, # 最大3行表示
|
||||
"show_timestamp": True, # タイムスタンプ表示
|
||||
"font_size": 16,
|
||||
"text_color": (200, 200, 200, 255)
|
||||
}
|
||||
|
||||
# ログ付きオーバーレイ画像生成
|
||||
logged_image = overlay_image.createOverlayImage(
|
||||
message="新しいメッセージ",
|
||||
language="Japanese",
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings=log_settings
|
||||
)
|
||||
|
||||
overlay_system.showOverlay(logged_image, "large")
|
||||
|
||||
# ログクリア
|
||||
overlay_image.clearMessageLog()
|
||||
```
|
||||
|
||||
## 座標系・変換システム
|
||||
|
||||
### 基本座標設定
|
||||
|
||||
```python
|
||||
# HMD基準座標(頭部固定表示)
|
||||
def getHMDBaseMatrix() -> np.ndarray:
|
||||
x_pos = 0.0 # 左右位置
|
||||
y_pos = -0.4 # 上下位置(下方向)
|
||||
z_pos = 1.0 # 前後位置(前方向)
|
||||
x_rotation = 0.0 # X軸回転
|
||||
y_rotation = 0.0 # Y軸回転
|
||||
z_rotation = 0.0 # Z軸回転
|
||||
|
||||
# 左手コントローラー基準座標
|
||||
def getLeftHandBaseMatrix() -> np.ndarray:
|
||||
x_pos = 0.3 # 右側にオフセット
|
||||
y_pos = 0.1 # 上方向にオフセット
|
||||
z_pos = -0.31 # 手前にオフセット
|
||||
x_rotation = -65.0 # 下向きに傾斜
|
||||
y_rotation = 165.0 # Y軸回転
|
||||
z_rotation = 115.0 # Z軸回転
|
||||
|
||||
# 右手コントローラー基準座標
|
||||
def getRightHandBaseMatrix() -> np.ndarray:
|
||||
x_pos = -0.3 # 左側にオフセット
|
||||
y_rotation = -165.0 # 左手と対称
|
||||
z_rotation = -115.0 # 左手と対称
|
||||
```
|
||||
|
||||
### 変換行列計算 (overlay_utils.py)
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from models.overlay.overlay_utils import *
|
||||
|
||||
# 移動変換
|
||||
translation = (0.1, -0.2, 0.5) # x, y, z移動
|
||||
translation_matrix = calcTranslationMatrix(translation)
|
||||
|
||||
# 回転変換(各軸独立)
|
||||
x_rotation_matrix = calcRotationMatrixX(30.0) # X軸30度回転
|
||||
y_rotation_matrix = calcRotationMatrixY(45.0) # Y軸45度回転
|
||||
z_rotation_matrix = calcRotationMatrixZ(60.0) # Z軸60度回転
|
||||
|
||||
# オイラー角から回転行列生成
|
||||
euler_angles = (30.0, 45.0, 60.0) # X, Y, Z軸回転角度
|
||||
rotation_matrix = euler_to_rotation_matrix(euler_angles)
|
||||
|
||||
# 基本行列への変換適用
|
||||
base_matrix = getHMDBaseMatrix()
|
||||
translation = (0.05, -0.1, 0.2)
|
||||
rotation = (10.0, -5.0, 0.0)
|
||||
transformed_matrix = transform_matrix(base_matrix, translation, rotation)
|
||||
|
||||
# 3x4行列を4x4同次座標に変換
|
||||
homogeneous_matrix = toHomogeneous(transformed_matrix)
|
||||
```
|
||||
|
||||
### カスタム配置設定
|
||||
|
||||
```python
|
||||
# カスタム位置でのオーバーレイ配置
|
||||
def createCustomOverlay(overlay_system, custom_pos, custom_rot, size):
|
||||
"""カスタム位置・回転でのオーバーレイ設定"""
|
||||
|
||||
# 設定を動的に変更
|
||||
overlay_system.settings[size]["x_pos"] = custom_pos[0]
|
||||
overlay_system.settings[size]["y_pos"] = custom_pos[1]
|
||||
overlay_system.settings[size]["z_pos"] = custom_pos[2]
|
||||
overlay_system.settings[size]["x_rotation"] = custom_rot[0]
|
||||
overlay_system.settings[size]["y_rotation"] = custom_rot[1]
|
||||
overlay_system.settings[size]["z_rotation"] = custom_rot[2]
|
||||
|
||||
# 追跡デバイス設定を再適用
|
||||
overlay_system.setTrackedDeviceRelative("HMD", size)
|
||||
|
||||
# 使用例:カスタム配置
|
||||
custom_position = (0.2, -0.3, 0.8) # やや右下前方
|
||||
custom_rotation = (-15.0, 10.0, 5.0) # 軽く傾斜
|
||||
createCustomOverlay(overlay_system, custom_position, custom_rotation, "large")
|
||||
```
|
||||
|
||||
## 高度な機能
|
||||
|
||||
### 動的サイズ・レイアウト管理
|
||||
|
||||
```python
|
||||
class AdaptiveOverlayManager:
|
||||
"""適応的オーバーレイ管理クラス"""
|
||||
|
||||
def __init__(self, base_overlay_system, base_overlay_image):
|
||||
self.overlay = base_overlay_system
|
||||
self.image_gen = base_overlay_image
|
||||
self.current_layout = "compact"
|
||||
|
||||
def adaptLayoutToContent(self, message, language):
|
||||
"""コンテンツに応じたレイアウト自動調整"""
|
||||
|
||||
# メッセージ長に応じてサイズ決定
|
||||
if len(message) < 50:
|
||||
layout = "compact"
|
||||
size_key = "small"
|
||||
elif len(message) < 150:
|
||||
layout = "standard"
|
||||
size_key = "medium"
|
||||
else:
|
||||
layout = "expanded"
|
||||
size_key = "large"
|
||||
|
||||
# 言語に応じたフォントサイズ調整
|
||||
if language in ["Chinese Simplified", "Chinese Traditional"]:
|
||||
font_scale = 1.1 # 中国語は少し大きめ
|
||||
elif language == "Korean":
|
||||
font_scale = 1.05 # 韓国語は微調整
|
||||
else:
|
||||
font_scale = 1.0 # 日本語・その他
|
||||
|
||||
# UI設定の動的生成
|
||||
ui_size = self.getAdaptiveUiSize(layout)
|
||||
ui_settings = {
|
||||
"font_size": int(18 * font_scale),
|
||||
"line_height": int(24 * font_scale),
|
||||
"text_color": (255, 255, 255, 255),
|
||||
"background_color": (0, 0, 0, 200),
|
||||
"border_width": 2,
|
||||
"border_color": (100, 150, 255, 255)
|
||||
}
|
||||
|
||||
return ui_size, ui_settings, size_key
|
||||
|
||||
def getAdaptiveUiSize(self, layout):
|
||||
"""レイアウトに応じたUIサイズ取得"""
|
||||
|
||||
layouts = {
|
||||
"compact": {
|
||||
"width": 400,
|
||||
"height": 100,
|
||||
"margin": 10,
|
||||
"padding": 8
|
||||
},
|
||||
"standard": {
|
||||
"width": 600,
|
||||
"height": 150,
|
||||
"margin": 15,
|
||||
"padding": 12
|
||||
},
|
||||
"expanded": {
|
||||
"width": 800,
|
||||
"height": 200,
|
||||
"margin": 20,
|
||||
"padding": 16
|
||||
}
|
||||
}
|
||||
|
||||
return layouts.get(layout, layouts["standard"])
|
||||
|
||||
# 使用例
|
||||
adaptive_manager = AdaptiveOverlayManager(overlay_system, overlay_image)
|
||||
|
||||
messages = [
|
||||
("Hello!", "English"),
|
||||
("これは中程度の長さのメッセージです。翻訳結果を表示します。", "Japanese"),
|
||||
("这是一个很长的消息,用来测试自适应布局功能。当消息内容很长时,系统会自动选择更大的显示区域,并调整字体大小以确保良好的可读性。", "Chinese Simplified")
|
||||
]
|
||||
|
||||
for message, language in messages:
|
||||
# 自動レイアウト調整
|
||||
ui_size, ui_settings, size_key = adaptive_manager.adaptLayoutToContent(message, language)
|
||||
|
||||
# 画像生成・表示
|
||||
adaptive_image = overlay_image.createOverlayImage(
|
||||
message=message,
|
||||
language=language,
|
||||
ui_size=ui_size,
|
||||
ui_settings=ui_settings,
|
||||
message_log_settings={"enabled": True, "max_lines": 3}
|
||||
)
|
||||
|
||||
overlay_system.showOverlay(adaptive_image, size_key)
|
||||
time.sleep(3)
|
||||
```
|
||||
|
||||
### パフォーマンス監視・最適化
|
||||
|
||||
```python
|
||||
class OverlayPerformanceMonitor:
|
||||
"""オーバーレイパフォーマンス監視クラス"""
|
||||
|
||||
def __init__(self, overlay_system):
|
||||
self.overlay = overlay_system
|
||||
self.frame_times = []
|
||||
self.update_counts = {}
|
||||
|
||||
def monitorFrameRate(self, duration=10.0):
|
||||
"""フレームレート監視"""
|
||||
|
||||
start_time = time.monotonic()
|
||||
frame_count = 0
|
||||
|
||||
while time.monotonic() - start_time < duration:
|
||||
frame_start = time.monotonic()
|
||||
|
||||
# フレーム処理(空の処理)
|
||||
time.sleep(1/90) # 90Hz目標
|
||||
|
||||
frame_end = time.monotonic()
|
||||
self.frame_times.append(frame_end - frame_start)
|
||||
frame_count += 1
|
||||
|
||||
# 統計計算
|
||||
avg_frame_time = sum(self.frame_times) / len(self.frame_times)
|
||||
avg_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0
|
||||
|
||||
print(f"平均フレーム時間: {avg_frame_time*1000:.2f}ms")
|
||||
print(f"平均FPS: {avg_fps:.1f}")
|
||||
print(f"総フレーム数: {frame_count}")
|
||||
|
||||
return avg_fps
|
||||
|
||||
def optimizeSettings(self, target_fps=60):
|
||||
"""パフォーマンス目標に基づく設定最適化"""
|
||||
|
||||
current_fps = self.monitorFrameRate(5.0)
|
||||
|
||||
if current_fps < target_fps * 0.8:
|
||||
print("パフォーマンス不足。設定を軽量化します...")
|
||||
|
||||
# フェード処理間隔を延長
|
||||
for size in self.overlay.settings:
|
||||
self.overlay.settings[size]["fadeout_duration"] *= 1.5
|
||||
|
||||
# 更新頻度を下げる
|
||||
# (mainloopの sleep_time 調整は overlay.py 内で実装)
|
||||
|
||||
elif current_fps > target_fps * 1.2:
|
||||
print("パフォーマンスに余裕があります。品質を向上します...")
|
||||
|
||||
# より滑らかなフェード
|
||||
for size in self.overlay.settings:
|
||||
self.overlay.settings[size]["fadeout_duration"] *= 0.8
|
||||
|
||||
# 使用例
|
||||
performance_monitor = OverlayPerformanceMonitor(overlay_system)
|
||||
performance_monitor.monitorFrameRate(10.0)
|
||||
performance_monitor.optimizeSettings(target_fps=60)
|
||||
```
|
||||
|
||||
## エラーハンドリング・復旧
|
||||
|
||||
### 堅牢な接続管理
|
||||
|
||||
```python
|
||||
class RobustOverlaySystem:
|
||||
"""堅牢性を高めたオーバーレイシステム"""
|
||||
|
||||
def __init__(self, settings_dict):
|
||||
self.base_overlay = Overlay(settings_dict)
|
||||
self.connection_retries = 3
|
||||
self.auto_reconnect = True
|
||||
|
||||
def safeStartOverlay(self, max_retries=None):
|
||||
"""安全なオーバーレイ開始(リトライ機構付き)"""
|
||||
|
||||
retries = max_retries or self.connection_retries
|
||||
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
# SteamVR接続確認
|
||||
if not self.base_overlay.checkSteamvrRunning():
|
||||
print("SteamVRが起動していません。待機中...")
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
# オーバーレイ開始
|
||||
self.base_overlay.startOverlay()
|
||||
|
||||
# 初期化完了まで待機
|
||||
timeout = 10.0
|
||||
start_time = time.monotonic()
|
||||
|
||||
while not self.base_overlay.initialized and time.monotonic() - start_time < timeout:
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.base_overlay.initialized:
|
||||
print("オーバーレイシステム開始完了")
|
||||
return True
|
||||
else:
|
||||
print(f"初期化タイムアウト(試行 {attempt + 1}/{retries})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"オーバーレイ開始エラー(試行 {attempt + 1}/{retries}): {e}")
|
||||
|
||||
# 既存システムのクリーンアップ
|
||||
try:
|
||||
self.base_overlay.shutdownOverlay()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if attempt < retries - 1:
|
||||
time.sleep(2 ** attempt) # 指数バックオフ
|
||||
|
||||
print("オーバーレイシステムの開始に失敗しました")
|
||||
return False
|
||||
|
||||
def monitorConnection(self):
|
||||
"""接続監視・自動復旧"""
|
||||
|
||||
while self.auto_reconnect:
|
||||
try:
|
||||
if self.base_overlay.initialized and not self.base_overlay.checkActive():
|
||||
print("OpenVR接続が切断されました。再接続を試行します...")
|
||||
|
||||
self.base_overlay.shutdownOverlay()
|
||||
time.sleep(2)
|
||||
|
||||
if self.safeStartOverlay():
|
||||
print("オーバーレイシステムが復旧しました")
|
||||
else:
|
||||
print("復旧に失敗しました")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"接続監視エラー: {e}")
|
||||
time.sleep(5)
|
||||
|
||||
# 使用例
|
||||
robust_overlay = RobustOverlaySystem(settings)
|
||||
|
||||
# 安全な開始
|
||||
if robust_overlay.safeStartOverlay():
|
||||
# 接続監視開始(別スレッド)
|
||||
import threading
|
||||
monitor_thread = threading.Thread(target=robust_overlay.monitorConnection, daemon=True)
|
||||
monitor_thread.start()
|
||||
|
||||
# 通常の操作
|
||||
overlay_img = overlay_image.createOverlayImage(...)
|
||||
robust_overlay.base_overlay.showOverlay(overlay_img, "small")
|
||||
```
|
||||
|
||||
## 依存関係・システム要件
|
||||
|
||||
### 必須依存関係
|
||||
- `openvr`: OpenVR Python バインディング
|
||||
- `numpy`: 数値計算・行列演算
|
||||
- `PIL (Pillow)`: 画像処理・生成
|
||||
- `psutil`: プロセス監視
|
||||
|
||||
### システム要件
|
||||
```python
|
||||
system_requirements = {
|
||||
"steamvr": "SteamVR環境必須",
|
||||
"openvr_runtime": "OpenVR Runtime",
|
||||
"vr_headset": "対応VRヘッドセット(Oculus, Vive, Index等)",
|
||||
"graphics": "VR対応GPU",
|
||||
"python": "Python 3.7以上"
|
||||
}
|
||||
|
||||
performance_requirements = {
|
||||
"cpu": "VR処理に十分なCPU性能",
|
||||
"memory": "追加メモリ使用量 ~100-500MB",
|
||||
"disk_space": "フォントファイル用容量 ~50MB"
|
||||
}
|
||||
```
|
||||
|
||||
### オプション依存関係
|
||||
- `utils.errorLogging`: エラーログ機能(フォールバック処理あり)
|
||||
|
||||
## 注意事項・制限
|
||||
|
||||
### VR環境制限
|
||||
- SteamVRが起動していない場合は動作不可
|
||||
- VRヘッドセットが接続されていない場合は制限あり
|
||||
- OpenVRドライバーの互換性に依存
|
||||
|
||||
### パフォーマンス制限
|
||||
- リアルタイム描画処理によるCPU・GPU負荷
|
||||
- フォントレンダリングによるメモリ使用量
|
||||
- 高解像度VRディスプレイでの描画負荷
|
||||
|
||||
### プラットフォーム制限
|
||||
```python
|
||||
platform_limitations = {
|
||||
"windows": "主要サポートプラットフォーム",
|
||||
"linux": "SteamVR Linux版での制限あり",
|
||||
"macos": "SteamVR macOS版サポート終了により制限",
|
||||
"mobile_vr": "OpenVR非対応のため利用不可"
|
||||
}
|
||||
```
|
||||
|
||||
## 関連モジュール
|
||||
|
||||
- `config.py`: オーバーレイ設定管理
|
||||
- `controller.py`: オーバーレイ制御インターフェース
|
||||
- `model.py`: オーバーレイ機能統合
|
||||
- `utils.py`: エラーログ・ユーティリティ
|
||||
|
||||
## 将来の改善点
|
||||
|
||||
- よりリッチなUI要素対応
|
||||
- アニメーション・エフェクト機能
|
||||
- カスタムフォント・テーマシステム
|
||||
- パフォーマンス監視・自動最適化
|
||||
- 他のVRプラットフォーム対応検討
|
||||
Reference in New Issue
Block a user