Skip to content

LKG Bridge 不要レンダリング

概要

Looking Glass ディスプレイは通常 Looking Glass Bridge というデスクトップアプリ経由でキャリブレーションやレンダリングを行います。しかし iPad では Bridge が動作しません。本調査では、Bridge を介さずにレンチキュラーレンダリングを独自実装するために必要な技術情報をまとめています。

レンチキュラーレンダリングの原理

Looking Glass はレンチキュラーレンズを使った裸眼立体視ディスプレイです。画面上の各サブピクセル(R/G/B)に、見る角度に応じた異なるビュー(視点)の画像情報を割り当てます。

表示パイプライン

多視点画像(Quilt)
    ↓ サブピクセルインターリービング
レンチキュラー画像(画面に表示される最終画像)
    ↓ レンチキュラーレンズ
裸眼立体視(見る角度で異なる画像が見える)

レンチキュラーシェーダーのアルゴリズム

  1. 各画面ピクセルの UV 座標から、R/G/B サブピクセルそれぞれが見るべき「ビューインデックス」を計算
  2. view = (screen_uv.x + screen_uv.y * tilt) * pitch - center(各サブピクセルで subp 分ずらす)
  3. ビューインデックスからキルトテクスチャ内のタイル座標を計算
  4. R, G, B を別々のビューからサンプリング(サブピクセルインターリービング

キャリブレーション JSON(visual.json)

ファイルの場所

Looking Glass デバイス本体のストレージ内に保存されています:

LKG-XXXXXX/LKG_calibration/visual.json
  • iPad/iPhone: USB-C 接続 → ファイルアプリで直接アクセス
  • PC: USB 接続 → ストレージとしてマウント → コピー

フィールド一覧

json
{
  "configVersion": "string",
  "serial": "string",
  "pitch":    { "value": 45.0 },
  "slope":    { "value": -5.0 },
  "center":   { "value": -0.5 },
  "fringe":   { "value": 0 },
  "viewCone": { "value": 40 },
  "invView":  { "value": 1 },
  "verticalAngle": { "value": 0.0 },
  "DPI":      { "value": 338.0 },
  "screenW":  { "value": 3840 },
  "screenH":  { "value": 2160 },
  "flipImageX": { "value": 0.0 },
  "flipImageY": { "value": 0.0 },
  "flipSubp":   { "value": 0.0 },
  "CellPatternMode": { "value": 0 },
  "subpixelCells": [
    {
      "ROffsetX": 0.0, "ROffsetY": 0.0,
      "GOffsetX": 0.0, "GOffsetY": 0.0,
      "BOffsetX": 0.0, "BOffsetY": 0.0
    }
  ]
}

シェーダーユニフォームへの変換式

生のキャリブレーション値からシェーダーで使う値への変換が必要です:

// pitch の変換
screenInches = screenW / DPI
pitch_shader = pitch_raw * screenInches * cos(atan(1.0 / slope))

// tilt の変換
tilt = screenH / (screenW * slope) * (flipImageX >= 0.5 ? -1 : 1)

// subpixel の変換
subp = 1.0 / (3 * screenW) * pitch_shader

TypeScript版(WebXR ライブラリより):

typescript
get pitch() {
  return (calibration.pitch.value * calibration.screenW.value / calibration.DPI.value)
    * Math.cos(Math.atan(1.0 / calibration.slope.value))
}

get tilt() {
  return (calibration.screenH.value / (calibration.screenW.value * calibration.slope.value))
    * (calibration.flipImageX.value ? -1 : 1)
}

get subp() {
  return (1 / (calibration.screenW.value * 3)) * (calibration.flipImageX.value ? -1 : 1)
}

AI補完

pitch / slope / center の意味:

  • pitch: レンチキュラーレンズのピッチ(1つのレンズの幅に対応するピクセル数)。デバイスのDPIとレンズの物理寸法から決まります。
  • slope: レンチキュラーレンズの傾斜角。レンズが画面の垂直軸から微小角度傾いているため、この補正が必要です。
  • center: レンズとサブピクセルの位相オフセット。個体ごとにわずかに異なる製造上のズレを補正します。

これらの値はデバイスごとに異なり、正確な立体視のために個体別キャリブレーションが必要です。

Unity Plugin のレンチキュラーシェーダー

シェーダーユニフォーム

Lenticular.shaderAssets/Looking Glass Plugin/Shaders/)で使用される主要ユニフォーム:

変数名説明
p_pitch処理済みピッチ値
p_slope処理済みスロープ値
centerセンターオフセット
screenW, screenH画面解像度
rotated回転フラグ
subpixelCellsサブピクセルセル配列(OLEDデバイス用)

ビュー計算の核心ロジック

glsl
// 各画面ピクセルのUV座標からビューインデックスを計算
n_views = uv.x + uv.y * p_slope

// サブピクセルごとに異なるビューをサンプリング
views[0] = screen_uv.x + subp * 0.0;  // R
views[1] = screen_uv.x + subp * 1.0;  // G
views[2] = screen_uv.x + subp * 2.0;  // B

views[0] += screen_uv.y * slope;
views[1] += screen_uv.y * slope;
views[2] += screen_uv.y * slope;

views *= vec3(pitch);
views -= vec3(center);
views = vec3(1.0) - fract(views);

GLSL レンチキュラーシェーダー(簡易版)

mpv プレーヤー等で使える最小限のGLSLシェーダーです:

glsl
const float tilt = -0.12039111681976107;
const float pitch = 370.66407267416486;
const float center = 0.13695651292800903 + tilt*pitch;
const float subp = 1.0 / (3*2560) * pitch;
const vec2 tiles = vec2(5,9);

vec2 quilt_map(vec2 pos, float a) {
    vec2 tile = vec2(tiles.x-1,0), dir=vec2(-1,1);
    a = fract(a)*tiles.y;
    tile.y += dir.y*floor(a);
    a = fract(a)*tiles.x;
    tile.x += dir.x*floor(a);
    return (tile+pos)/tiles;
}

vec4 hook() {
    vec4 res;
    float a;
    a = (HOOKED_pos.x + HOOKED_pos.y*tilt)*pitch - center;
    res.x = HOOKED_tex(quilt_map(HOOKED_pos, a)).x;
    res.y = HOOKED_tex(quilt_map(HOOKED_pos, a+subp)).y;
    res.z = HOOKED_tex(quilt_map(HOOKED_pos, a+2*subp)).z;
    res.w = 1.0;
    return res;
}

モデル別キルト設定

モデルシリアルプレフィックスキルト解像度列×行総ビュー数
Looking Glass 8.9"LKG-2K4096×40965×945
Looking Glass 15.6"LKG-4K4096×40965×945
PortraitLKG-P3360×33608×648
16" Gen2LKG-A4096×40965×945
32" Gen2LKG-B8192×81925×945
65"LKG-D8192×81928×972
GoLKG-E4092×409211×666
16" Spatial OLED (Portrait)LKG-H5995×600011×666
16" Spatial OLED (Landscape)LKG-J5999×59997×749
32" Spatial Display (Portrait)LKG-K8184×818411×666
32" Spatial Display (Landscape)LKG-L8190×81907×749

Bridge 通信プロトコル(参考)

通常の Bridge 経由のフローです(iPad では使えません)。

HTTP API

  • デフォルトポート: HTTP 33334, WebSocket 9724
  • エンドポイント: http://localhost:33334/{endpoint}
  • 主要メソッド:
    • enter_orchestration: セッション開始
    • available_output_devices: ディスプレイ一覧取得(キャリブレーション含む)
    • update_devices: デバイス情報更新

キャリブレーション取得フロー

  1. BridgeConnectionHTTP.Connect() で WebSocket 接続
  2. TryEnterOrchestration() でセッション開始
  3. UpdateDevicesAsync()available_output_devices を呼び出し
  4. レスポンスから Display オブジェクトを解析
  5. Display.calibrationCalibration.Parse() でパース

Bridge なしでの代替手段

方法説明iPad対応
USB ストレージから直接読み取りUSB-C接続 → ファイルアプリで visual.json にアクセス
手動キャリブレーションテストパターンを表示しながら tilt/pitch/center を手動調整
Looking Glass Studio for iOS公式iOSアプリが visual.json を直接読み込み

iPad での制限事項:

  • iPad ではネイティブの Looking Glass Bridge が動作しない
  • USB-C 経由で visual.json を取得する方法が主要
  • Go デバイスの場合、ファームウェア v1.0.59 以上が必要

重要なファイルパス(Unity Plugin 4.0-alpha)

シェーダー

  • Assets/Looking Glass Plugin/Shaders/Lenticular.shader
  • Assets/Looking Glass Plugin/Shaders/QuiltCopy.shader
  • Packages/com.unity.render-pipelines.core/ShaderLibrary/LookingGlass/LookingGlassSettings.hlsl

C# スクリプト

  • Assets/Looking Glass Plugin/Scripts/CalibrationLoader.cs
  • Assets/Looking Glass Plugin/Scripts/BridgeInterface.cs
  • Packages/com.unity.render-pipelines.core/Runtime/Looking Glass/MultiviewData.cs
  • Assets/Looking Glass Plugin/Plugins/LKG-Toolkit/Toolkit-API/Device/Calibration.cs
  • Assets/Looking Glass Plugin/Plugins/LKG-Toolkit/Toolkit-API/Bridge/BridgeConnectionHTTP.cs

オープンソース実装(参考)

プロジェクトライセンス内容
looking-glass-webxr(公式)Apache-2.0WebXR Polyfill
holoplaycore.js(公式)独自Bridge通信 + Shader生成
lonetech/LookingGlass-mpv用GLSLシェーダー
surf-visualization/looking-glassBSDPython実装(キャリブレーション含む)

関連記事


Author: 山本颯一郎 | Source: 0226LKGBridgeを介さないレンダリングの独自実装について AI Enhanced: Claude — 2026-03-06