🎃

PotalCamのLCCファイルをMeta Quest 3で参照する

に公開

LCCファイルとは

PortalCamを販売しているXGRIDS社が開発したオープンフォーマットのデータ形式です。
LODなどによりガウシアンスプラッティングの表示がQuest 3単体でも表示可能です。

LCCデータ構成フォーマットのホワイトペーパー
https://developer.xgrids.com/#/document?titleId=en-1762741644065

できること

PortalCamで撮影したLCCデータをQuest 3で見ることのできる簡単なビューワーを作成します。

仕様

ベースはクイックスタートガイド通りです。
そのままだと決まったLCCファイルを表示することはできるのですが、動的にファイルを変更することはできません。また、カメラの移動も自分で移動する範囲でしか動けません。
なので、

ベースはQuest3 開発クイックスタート
https://developer.xgrids.com/#/document?titleId=en-1737012953384)
に通りで以下を追加します。

  • Quest 3の特定のフォルダ内のLCCファイルを取得して表示する(1ファイルのみ)
  • Quest 3のコントローラーで移動ができるようにする

手順

1.ベースはQuest3 開発クイックスタートの通りにプロジェクトを作成します。

2.LCCRenderer.csを以下のように修正します

using LCCCore;
using UnityEngine;
using System.IO;
using System.Linq;

public class LCCRenderer : MonoBehaviour
{
    public LCCManager m_manager;
    private LCCCore.Renderer m_renderer;

    void Start()
    {
        // persistentDataPath 直下を対象に
        string searchPath = System.IO.Path.Combine(Application.persistentDataPath, "LCC");
        Debug.Log($"[LCCRenderer] Searching for .lcc files in: {searchPath}");

        // .lcc ファイルを検索
        string[] files = Directory.GetFiles(searchPath, "*.lcc", SearchOption.TopDirectoryOnly);

        if (files.Length == 0)
        {
            Debug.LogError($"[LCCRenderer] No .lcc files found in: {searchPath}");
            return;
        }

        // 最初に見つかったファイルを使う(複数ある場合は最初のもの)
        string path = files[0];
        Debug.Log($"[LCCRenderer] Loading file: {Path.GetFileName(path)}");

        // 念のため存在確認
        if (!File.Exists(path))
        {
            Debug.LogError($"[LCCRenderer] File not found: {path}");
            return;
        }

        // LCCレンダラー初期化・ロード
        m_renderer = m_manager.GetRender(this.transform);
        m_renderer.Load(path, PlatformType.Quest, onLoadCallback);
    }

    private void onLoadCallback()
    {
        Debug.Log("✅ LCC data loaded successfully!");
    }
}

以下フォルダにあるLCCファイルを探して表示します。
\内部共有ストレージ\Android\data[Package Name]\files\LCC

  1. ヒエラルキーの「XR Origin (VR)」に以下のスクリプトをアタッチします
  2. XRControllerLocomotion.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class XRControllerLocomotion : MonoBehaviour
{
    [Header("XR Rig / Camera")]
    public Transform rigRoot;
    public Transform head;

    [Header("Input Actions (assign if you have asset)")]
    public InputActionProperty leftStick;            // Left thumbstick (Vector2)
    public InputActionProperty rightStick;           // Right thumbstick (Vector2)
    public InputActionProperty rightPrimaryButton;   // Right A
    public InputActionProperty rightSecondaryButton; // Right B

    [Header("Speeds")]
    public float moveSpeed = 2.0f;
    public float verticalSpeed = 1.5f;
    public float rotateSpeedDeg = 120f;
    public float stickDeadzone = 0.1f;

    private InputAction _leftStickAuto, _rightStickAuto, _rightPrimaryAuto, _rightSecondaryAuto;

    void Awake()
    {
        if (leftStick.reference == null)
        {
            _leftStickAuto = new InputAction("LeftThumbstick", InputActionType.Value, "<XRController>{LeftHand}/thumbstick");
            _leftStickAuto.AddBinding("<XRController>{LeftHand}/primary2DAxis"); 
            leftStick = new InputActionProperty(_leftStickAuto);
        }

        if (rightStick.reference == null)
        {
            _rightStickAuto = new InputAction("RightThumbstick", InputActionType.Value, "<XRController>{RightHand}/thumbstick");
            _rightStickAuto.AddBinding("<XRController>{RightHand}/primary2DAxis"); 
            rightStick = new InputActionProperty(_rightStickAuto);
        }

        if (rightPrimaryButton.reference == null)
        {
            _rightPrimaryAuto = new InputAction("RightPrimaryButton", InputActionType.Button, "<XRController>{RightHand}/primaryButton");
            rightPrimaryButton = new InputActionProperty(_rightPrimaryAuto);
        }

        if (rightSecondaryButton.reference == null)
        {
            _rightSecondaryAuto = new InputAction("RightSecondaryButton", InputActionType.Button, "<XRController>{RightHand}/secondaryButton");
            rightSecondaryButton = new InputActionProperty(_rightSecondaryAuto);
        }
    }

    void OnEnable()
    {
        leftStick.action?.Enable();
        rightStick.action?.Enable();
        rightPrimaryButton.action?.Enable();
        rightSecondaryButton.action?.Enable();
    }

    void OnDisable()
    {
        leftStick.action?.Disable();
        rightStick.action?.Disable();
        rightPrimaryButton.action?.Disable();
        rightSecondaryButton.action?.Disable();
    }

    void Update()
    {
        if (rigRoot == null || head == null) return;

        Vector2 moveXY = rightStick.action.ReadValue<Vector2>();
        if (moveXY.sqrMagnitude > (stickDeadzone * stickDeadzone))
        {
            Vector3 fwd = head.forward; fwd.y = 0f; fwd.Normalize();
            Vector3 right = head.right; right.y = 0f; right.Normalize();
            Vector3 moveWorld = (fwd * moveXY.y + right * moveXY.x) * moveSpeed * Time.deltaTime;
            rigRoot.position += moveWorld;
        }

        float yawInput = leftStick.action.ReadValue<Vector2>().x;
        if (Mathf.Abs(yawInput) > stickDeadzone)
        {
            float yaw = yawInput * rotateSpeedDeg * Time.deltaTime;
            rigRoot.Rotate(0f, yaw, 0f, Space.World);
        }

        float v = 0f;
        if (rightSecondaryButton.action.IsPressed()) v += 1f;
        if (rightPrimaryButton.action.IsPressed()) v -= 1f;
        if (v != 0f) rigRoot.position += Vector3.up * (v * verticalSpeed * Time.deltaTime);
    }
}

5.XRControllerLocomotionを以下の設定をします。

6.操作は以下となります。
右コントローラーのサムスティックで前後左右
右コントローラーのA,Bで上下
左コントローラーのサムスティックで回転

7.ビルドしてAPKをQuest 3にインストールしてください。

確認

確認はサンプルデータの「[PortalCam]大きな鏡」で行っています。
https://developer.xgrids.com/#/download?page=sampledata

ホロラボのテックブログ

Discussion