PotalCamのLCCファイルをMeta Quest 3で参照する
LCCファイルとは
PortalCamを販売しているXGRIDS社が開発したオープンフォーマットのデータ形式です。
LODなどによりガウシアンスプラッティングの表示がQuest 3単体でも表示可能です。
LCCデータ構成フォーマットのホワイトペーパー
できること
PortalCamで撮影したLCCデータをQuest 3で見ることのできる簡単なビューワーを作成します。

仕様
ベースはクイックスタートガイド通りです。
そのままだと決まったLCCファイルを表示することはできるのですが、動的にファイルを変更することはできません。また、カメラの移動も自分で移動する範囲でしか動けません。
なので、
ベースはQuest3 開発クイックスタート に通りで以下を追加します。
- 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

- ヒエラルキーの「XR Origin (VR)」に以下のスクリプトをアタッチします
- 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]大きな鏡」で行っています。
株式会社ホロラボの技術に関するブログ集です。 ホロラボは「フィジカルとデジタルをつなげ、新たな世界を創造する」をミッションに、XRや空間コンピューティングを軸にした価値を提供する企業です。 お問い合わせは👉のURLよりお願いします! hololab.co.jp/#contact
Discussion