XGRIDSドキュメント
  • 简体中文
  • English
  • 繁體中文
  • 日本語
  • Deutsch
  • Español
  • Italiano
  • Français
  • Русский
  • Polski
  • Nederlands
  • 简体中文
  • English
  • 繁體中文
  • 日本語
  • Deutsch
  • Español
  • Italiano
  • Français
  • Русский
  • Polski
  • Nederlands
  • Lixel PortalCam シリーズ

    • PortalCam P1

      • 製品概要
      • デバイスの基本操作
      • LCC Scan App の使用
      • メンテナンスとお手入れ
      • FAQ
  • Lixel K シリーズ

    • Lixel K1

      • 製品概要
      • デバイスの基本操作
      • デバイスのアクティベーションと接続
      • デバイス収集
      • 絶対座標のポイントクラウドデータを取得する
      • マップフュージョン
      • 典型的なシーンにおける経路計画の推奨
      • 注意事項
      • FAQ
    • Lixel K2

      • 製品概要
      • デバイスの基本操作
      • デバイスのアクティベーションと接続
      • デバイス収集
      • 絶対座標のポイントクラウドデータを取得
      • マップフュージョン
      • 典型的なシーンにおける経路計画の推奨
      • 注意事項
      • FAQ
  • Lixel L シリーズ

    • Lixel L2 Pro

      • 製品概要
      • デバイスの基本操作
      • デバイスのアクティベーションと接続
      • デバイス収集
      • 絶対座標のポイントクラウドデータを取得する
      • 実時計測機能
      • 付録
      • FAQ
    • Lixel L3

      • 製品概要
      • デバイスの基本操作
      • デバイスのアクティベーションと接続
      • デバイス収集
      • 絶対座標点群データの取得
      • 付録
  • アクセサリー

    • Stick Light

      • 取り付けガイド
      • 基本操作
      • よくある質問
  • Lixel Studio

    • バージョンと著作権
    • インストールとアクティベーション
    • ソフトウェアインターフェース
    • ファイル操作
    • プロジェクト処理
    • ツール
    • 2D 作図
    • 業界応用
    • 設定
    • デバイス接続
    • よくある質問
  • Lixel CyberColor

    • LCC Studio

      • はじめに
      • バージョンと更新
      • ダウンロードとインストール
      • インターフェース概要とナビゲーション
      • 再構築前の準備
      • モデル再構築
      • 単一モデル再構築
      • 地図合成
      • 空地融合
      • 航空撮影再構築
      • マイモデル
      • その他の機能
      • 設定とアカウント
      • Converter
      • 動画再構築
      • よくある質問 / FAQ
    • LCC Scene Editor

      • バージョンと更新情報
      • アカウントとサインイン
      • 製品概要とホーム画面
      • エディター画面
      • ナビゲーションモード
      • ファイル
      • 設定
      • 編集
      • ウィンドウ
      • グローバルツールバー
      • アセットとプロパティ
      • 左ツールバー
      • ビューポイント
      • ポータル
      • スカイボックス
      • アノテーション
      • 測定
      • フライスルー
      • シーンレポート
      • 3D レイアウト
      • ミニマップ
      • プレビューモード(Viewer)
      • ヘルプ
      • よくある質問(FAQ)
      • スポーンポイント
    • LCC Model Editor

      • バージョンと更新
      • ユーザーガイド
      • 概要とインターフェース
      • ファイル操作
      • セレクター
      • モデルの編集
      • 測定
      • カラーグレーディング
      • アセット管理
      • 設定とヘルプ
      • よくある質問
    • Capture Guide

      • 概要
      • 撮影デバイス概要
      • 一般的な撮影の原則
      • 屋内シーンの撮影
      • 屋外シーンの撮影
      • 大規模撮影(マップフュージョン)
      • 空地マップフュージョン撮影
      • オブジェクト撮影
      • 人物撮影
      • ビデオ再構築撮影
      • HD Enhancement
      • 制御点(Lixel P1)
      • FAQ とトラブルシューティング
    • LCC Studio Linux

      • 製品概要説明
      • 基本アーキテクチャマニュアル
      • インストールと展開説明書
      • コンテナ起動パラメータ説明書
      • CodeMeter オフラインライセンス展開説明書
      • APIコマンドセット
      • 付録-開発者データマニュアル
      • 付録-エラーコード一覧
      • シングルノードマルチGPUクラスタ展開QuickStart
    • 活用テクニック

      • 複数の大規模 3DGS モデルの統合ワークフロー
    • バージョン履歴
  • プラグインと SDK

    • Unreal

      • 概要
      • クイックスタート - Windows
      • クイックスタート - Linux
      • クイックスタート - Quest3
      • エディションとライセンス
      • レンダリング
      • Tiled ラスタライズ(実験的機能)
      • 画面調節
      • 法線とライティング
      • シーン編集
      • パフォーマンスパラメーター
      • パフォーマンス最適化ガイド
      • サードパーティおよびエンジンプラグインとの連携
      • プロキシメッシュ
      • 読み込みアニメーション
      • コリジョン
      • ナビゲーションシステム対応
      • Single layer water 対応
      • ローカライズ
      • よくある質問
      • トラブルシューティング
      • ログと診断
      • お問い合わせ
      • ベストプラクティス

        • LixelStudio メッシュで 3DGS をリライティングする
      • API リファレンス

        • ALCCActorBase
        • ULCCComponentBase
        • ULCCComponent
        • ULCC2Component
        • SOG / SPZ / PLY Actors
        • ALCC2ProxyMesh
        • ALCCClippingVolume
        • ALCCSectionPlane
        • ALCCLoadVolume
        • ULCCUtilLibrary
        • Enums
        • Structs
      • 更新履歴

        • v3.4.0
        • v3.3.1
        • v3.0.0
        • v2.2.1
        • v1.0.0
        • v0.9.0
        • v0.8.0
        • v0.7.1
        • v0.6.1
        • v0.5.2
        • v0.4.1
        • v0.4.0
        • v0.3.0
        • v0.0.5
        • v0.0.4
        • v0.0.3
        • v0.0.2
        • v0.0.1
    • Unity

      • Unity SDK の概要
      • 技術的特徴
      • 開発環境の要件
      • PC クイックスタートガイド
      • プロジェクト設定の最適化ガイド
      • Pico 4 Ultra 開発ガイド
      • Pico 4 Ultra PC ストリーミングガイド
      • Quest 3 開発ガイド
      • Quest 3 PC ストリーミングガイド
      • OpenXR 開発ガイド
      • Pico 4 Ultra Business Streaming ガイド
      • 用語集
      • FAQ
      • お問い合わせ
      • 機能開発ガイド

        • 複数シーン混合レンダリング開発ガイド
        • 影の受光開発ガイド
        • リアルタイムライティング開発ガイド
        • マルチカメラレンダリング開発ガイド
        • 高解像度画像レンダリング開発ガイド
        • LCC / LCC2 データ形式互換性開発ガイド
        • 読み込みエフェクト開発ガイド
        • Mip レンダリングモード切り替え開発ガイド
        • エッジ・コーナースナップ開発ガイド
        • 投影デカール開発ガイド
        • ビデオ投影デカール開発ガイド
        • ハイライト開発ガイド
        • リアルタイムクリッピング開発ガイド
        • カラー調整開発ガイド
        • シーン Mesh データ取得開発ガイド
        • エディターモード開発ガイド
        • レンダリングパフォーマンスパラメータ設定ガイド
        • アプリケーションとデータの同梱パッケージ開発ガイド
        • コリジョンシステム開発ガイド
        • macOS 開発の権限問題ガイド
        • iOS デバイスのコンパイル・パッケージ化開発ガイド
      • API リファレンス

        • LCCManager
        • Renderer
        • データ型
      • 変更履歴

        • v2.3.0
        • v2.2.10
        • v2.2.0
        • v2.1.19
        • v2.0.14
    • Web

      • はじめに
      • レンダリング性能最適化ガイド
      • グラフィックス設定
      • よくある質問
      • API リファレンス

        • LCCRender::clearIndexDB
        • LCCRender::dispose
        • LCCRender::load
        • LCCRender::setCamera
        • LCCRender::unload
        • LCCRender::update
        • LCCObject::checkRenderNextFrame
        • LCCObject::clearRenderNextFrame
        • LCCObject::ecef2Prj
        • LCCObject::getBounds
        • LCCObject::getEnvInstancedMesh
        • LCCObject::getInstancedMesh
        • LCCObject::getLodInfos
        • LCCObject::getOriginPosition
        • LCCObject::getProjectionCoordinateSystemInfos
        • LCCObject::hasCollision
        • LCCObject::hasEnvironment
        • LCCObject::hasShcoef
        • LCCObject::intersectsCapsule
        • LCCObject::intersectsRayExt
        • LCCObject::intersectsRayFromOriginExt
        • LCCObject::intersectsSphere
        • LCCObject::lowerToBottom
        • LCCObject::prj2Ecef
        • LCCObject::raiseToTop
        • LCCObject::raycast
        • LCCObject::raycastFromOrigin
        • LCCObject::setAlpha
        • LCCObject::setClipBox
        • LCCObject::setClipPlane
        • LCCObject::setEndLod
        • LCCObject::setLodAutoLevelUp
        • LCCObject::setMaxDistance
        • LCCObject::setMaxNodeSplats
        • LCCObject::setMaxSplats
        • LCCObject::setOriginPosition
        • LCCObject::setPointsColor
        • LCCObject::setRenderState
        • LCCObject::setRotation
        • LCCObject::setScale
        • LCCObject::setSemantic
        • LCCObject::setSemanticColor
        • LCCObject::setSmooth
        • LCCObject::setStartLod
        • LCCObject::setTranslation
        • LCCObject::setVisible
        • LCCObject::togglePointsDisplayMode
        • LCCObject::useEnvironment
        • LCCObject::useShcoef
      • 更新履歴

        • v0.6.3
        • v0.6.2
        • v0.6.1
        • v0.6.0
        • v0.5.5
        • v0.5.4
        • v0.5.3
        • v0.5.2
        • v0.5.1
        • v0.5.0
        • v0.4.1
        • v0.4.0
        • v0.3.1
        • v0.3.0
        • v0.2.0

ビデオ投影デカール開発ガイド

機能概要

ビデオ投影デカールは 投影デカール の拡張です。投影する内容が静的な画像ではなく ビデオ になります。アプローチは、Unity 内蔵の VideoPlayer でビデオをデコードし、各フレームをデカールテクスチャに動的に更新することで、スライドプロジェクターのようにビデオを 3DGS 点群サーフェスへ投影します。

デカール自体が ワールド空間に固定された透視投影 であるため、ビデオフレームはプロジェクターの姿勢に応じて点群サーフェスに「貼り付け」られます。プロジェクターフラスタム内の点は現在のビデオフレームで着色され、フラスタム外の点は影響を受けません。

注:

通常のデカールと同様、ビデオデカールは PC / Mac(URP パイプライン) でのみ有効です。モバイルや VR プラットフォームで関連インターフェースを呼び出しても SDK は無視し、警告を出力します。

このガイドでは「ビデオ」に関連する増分部分のみを説明します。シーンのセットアップ(Main Camera / LCCManager / LCCRenderer / Projector)、URP Renderer への Decal Depth Feature の追加、オクルージョンカリングの調整、デカール API の詳細など基本事項は、先に 投影デカール開発ガイド をお読みください。

実装原理

SDK のデカールインターフェース SetDecalTexture(Texture2D tex) は Texture2D のみを受け付けますが、実行時にこのテクスチャを動的に更新することに対応しています。Unity の VideoPlayer のデコード出力は RenderTexture(GPU 上)です。したがって、データパイプライン全体は次のようになります。

VideoPlayer がデコード → RenderTexture(GPU)→ Texture2D にコピー → SetDecalTexture(フレームテクスチャ) → 点群に投影

重要な点は 2 つあり、これが本ガイドで強調する 2 つの「アライメント」です。

  1. 空間的アライメント:点群に投影されるビデオフレームの位置・サイズ・向きは、プロジェクターパラメータ(姿勢、FOV、Aspect、Near/Far)で決まります。ビデオとシーンの空間的アライメント を参照してください。
  2. 時間的アライメント:ビデオフレームレートはシーンレンダリングフレームレートよりはるかに低いことが多いため(シーンは数百 FPS で動作することもあります)、レンダリングフレームごとにテクスチャをコピーしてプッシュすることはできません。VideoPlayer.frame を使って新しいデコードフレームが出現したかどうかを検出し、新しいフレームが届いたときだけ更新します。ビデオフレームレートとレンダリングフレームレートのアライメント を参照してください。
ビデオ投影デカールのデータパイプライン図

ビデオ投影デカールのデータパイプライン:VideoPlayer → RenderTexture → Texture2D → SetDecalTexture

前提条件

ビデオデカールは通常のデカールと同じ前提条件を共有します。開始前に以下を確認してください。

  1. シーンに Main Camera、LCCManager、LCCRenderer、Projector がセットアップ済みであること(投影デカール開発ガイド · 手順 1 を参照)。
  2. 現在 URP パイプラインを使用していること。オクルージョンカリングが必要な場合は、URP Renderer Asset に Decal Depth Feature が登録されていること。
  3. Console にエラーが報告され、効果が表示されない場合は、Render Graph 互換モードを無効にします(投影デカール開発ガイド の FAQ セクションを参照)。
  4. ビデオアセットを用意します。プロジェクト内の VideoClip アセットでも、ディスク / ネットワーク上のビデオファイル URL(例:file:///D:/sample.mp4)でも構いません。

手順 1:スクリプトを書く

VideoStreaming.cs という名前の新しい C# スクリプトを作成します。通常の Decal.cs の骨組みを基に、「静的なデカールテクスチャ」を「実行時に VideoPlayer を作成してビデオをデコードし、デコードしたフレームに応じて Update() でデカールテクスチャを更新する」に置き換えています。プロジェクトへそのままコピーできます。

using LCCCore;
using UnityEngine;
using UnityEngine.Video;

public class VideoStreaming : MonoBehaviour
{
    [Header("必須")]
    [Tooltip("シーン内の LCCManager インスタンス")]
    public LCCManager m_manager;
    [Tooltip("有効な LCC シーンパス")]
    public string m_filePath;

    [Header("ビデオソース(デコードしたフレームをデカールとして投影)")]
    [Tooltip("投影するビデオクリップ。下記の URL より優先されます")]
    public VideoClip m_videoClip;
    [Tooltip("ビデオファイルパス / URL。クリップが割り当てられていない場合に使用(例:file:///D:/xxx.mp4)")]
    public string m_videoUrl;
    [Tooltip("ループ再生")]
    public bool m_videoLoop = true;

    [Header("プロジェクター(+Z 方向に投影)")]
    [Tooltip("プロジェクターの姿勢。空の場合はこのオブジェクトの Transform を使用")]
    public Transform m_projector;
    [Range(1f, 179f)] public float m_fov = 60f;
    [Tooltip("投影アスペクト比。<=0 の場合はビデオのアスペクト比を自動使用")]
    public float m_aspect = 0f;
    public float m_near = 0.1f;
    public float m_far = 100f;

    [Header("デカールの外観")]
    [Range(0f, 1f)] public float m_opacity = 1.0f;
    [Range(0f, 0.5f)][Tooltip("エッジフェード幅(UV 比)。0 = ハードエッジ")]
    public float m_edgeFade = 0.1f;
    [Tooltip("毎フレーム投影を更新し、実行時にプロジェクターのドラッグやパラメータ調整が可能に")]
    public bool m_updateEveryFrame = true;

    [Header("オクルージョンカリング(PC/Mac のみ)")]
    [Tooltip("オンの場合、前面ジオメトリの背後にある背面/遮蔽点はデカールで着色されなくなります(スライドプロジェクター効果)。オフの場合は X 線です")]
    public bool m_occlusion = false;
    [Range(0f, 1f)][Tooltip("不透明度閾値:この値以上の不透明度を持つ Splat のみが深度マップに寄与し、浮遊/霧状の点を除去します。0 = すべて参加")]
    public float m_occlusionCutoff = 0f;
    [Range(0f, 0.5f)][Tooltip("相対深度許容値。小さすぎる -> 近傍サーフェスの自己オクルージョン、大きすぎる -> X 線着色の漏れ。デフォルト 0.05")]
    public float m_occlusionBias = 0.05f;
    [Range(0, 16)][Tooltip("正方形フットプリント半径の上限(px)。X 線の透過漏れを除去する主なノブ。0 = 単一テクセル、デフォルト 2")]
    public int m_occlusionFootprint = 2;
    [Tooltip("深度マップ解像度(px、2 のべき乗 256〜4096)。かすめ角の穴を埋めるには下げます。デフォルト 1024")]
    public int m_occlusionResolution = 1024;

    // -- 実行時状態 --
    private bool m_loaded;
    private bool m_lastOcclusion;
    private float m_lastCutoff = float.NaN;
    private float m_lastBias = float.NaN;
    private int m_lastFootprint = -1;
    private int m_lastResolution = -1;

    // -- ビデオ状態 --
    private VideoPlayer m_videoPlayer;
    private RenderTexture m_videoRT;   // VideoPlayer がビデオをここにデコード(GPU)
    private Texture2D m_frameTex;      // 現在のフレームをここにコピーし、デカールへ渡す
    private bool m_videoReady;
    private long m_lastVideoFrame = -1; // デカールへプッシュ済みの最後のフレームインデックス

    void Start()
    {
        if (m_manager == null || string.IsNullOrEmpty(m_filePath))
        {
            Debug.LogError("[VideoStreaming] m_manager または m_filePath が割り当てられていません。");
            enabled = false;
            return;
        }

        // 1) レンダーパイプラインを PC 単一シーンのエディターモードに初期化
        m_manager.SetPlatformType(PlatformType.PC);
        m_manager.SwitchRenderPass(ActiveRenderMode.SingleRender);
        m_manager.SetEditorMode(true);

        // 2) シーン読み込みと並行してビデオのデコードを開始
        SetupVideo();

        // 3) 点群シーンを読み込み、完了後にデカールを有効化(デカールはグローバル状態。シーン準備完了後に設定するのが最も安全)
        var renderer = m_manager.GetRender(this.transform);
        Debug.Log($"[VideoStreaming] 読み込みを開始: {m_filePath}");
        renderer.Load(m_filePath,
            _ => { /* 進捗コールバック。この例では未使用 */ },
            OnSceneLoaded);
    }

    /// <summary>実行時に VideoPlayer を作成し、クリップ/URL の準備を開始します。</summary>
    private void SetupVideo()
    {
        m_videoPlayer = gameObject.AddComponent<VideoPlayer>();
        m_videoPlayer.playOnAwake = false;
        m_videoPlayer.isLooping = m_videoLoop;
        m_videoPlayer.renderMode = VideoRenderMode.RenderTexture;
        m_videoPlayer.audioOutputMode = VideoAudioOutputMode.None; // デモ:音声なし

        if (m_videoClip != null)
        {
            m_videoPlayer.source = VideoSource.VideoClip;
            m_videoPlayer.clip = m_videoClip;
        }
        else
        {
            m_videoPlayer.source = VideoSource.Url;
            m_videoPlayer.url = m_videoUrl;
        }

        // 解像度が判明したらフレームバッファを割り当て、再生を開始します。
        m_videoPlayer.prepareCompleted += OnVideoPrepared;
        m_videoPlayer.Prepare();
    }

    private void OnVideoPrepared(VideoPlayer vp)
    {
        int w = (int)vp.width;
        int h = (int)vp.height;

        m_videoRT = new RenderTexture(w, h, 0, RenderTextureFormat.ARGB32);
        m_videoRT.Create();
        vp.targetTexture = m_videoRT;

        m_frameTex = new Texture2D(w, h, TextureFormat.RGBA32, false);

        m_videoReady = true;
        vp.Play();
        Debug.Log($"[VideoStreaming] ビデオ準備完了: {w}x{h}、再生中。");
    }

    private void OnSceneLoaded()
    {
        Debug.Log("[VideoStreaming] 読み込み完了、デカール投影を有効化します。");

        // -- 基本投影: 5 つの API --
        // テクスチャ内容は Update() でデコードしたフレームが駆動します。ここでは現在利用可能なフレームを先にプッシュします。
        if (m_frameTex != null) m_manager.SetDecalTexture(m_frameTex);
        m_manager.SetDecalOpacity(m_opacity);        // 全体の不透明度
        m_manager.SetDecalEdgeFade(m_edgeFade);      // エッジフェード
        ApplyProjection();                           // プロジェクターの姿勢(内部的に SetDecalProjection を呼び出す)
        m_manager.SetDecalEnabled(true);             // デカールを有効化(_DECAL キーワード)

        // -- オクルージョンカリング: 2 つの API -- ApplyProjection の後でなければならない(深度マップには有効なプロジェクター VP 行列が必要)
        m_manager.SetDecalOcclusionSettings(BuildOcclusionSettings());
        m_manager.SetDecalOcclusion(m_occlusion);
        CacheOcclusionState();

        m_loaded = true;
    }

    void Update()
    {
        if (!m_loaded) return;

        // --- ビデオフレーム更新。レンダリング FPS とはデカップリング ---
        // VideoPlayer.frame はビデオ自身の再生レートでのみ増加します。シーンが数百 FPS でレンダリングされても、
        // 隣接する 2 つのビデオフレームの間ではインデックスは変わらないため、実際に新しいデコードフレームが出現したときだけ
        // そのフレームをコピーしてデカールテクスチャを再度プッシュします。
        if (m_videoReady && m_videoPlayer.frame != m_lastVideoFrame)
        {
            m_lastVideoFrame = m_videoPlayer.frame;

            // GPU 上の RenderTexture を、デカール API が受け付ける Texture2D にコピーします。
            // これはビデオフレームレートでのみ実行されるため、読み戻しコストは許容範囲です。
            RenderTexture prev = RenderTexture.active;
            RenderTexture.active = m_videoRT;
            m_frameTex.ReadPixels(new Rect(0, 0, m_videoRT.width, m_videoRT.height), 0, 0, false);
            m_frameTex.Apply(false);
            RenderTexture.active = prev;

            m_manager.SetDecalTexture(m_frameTex);
        }

        // 実行時にオクルージョンを切り替え
        if (m_occlusion != m_lastOcclusion)
        {
            m_manager.SetDecalOcclusion(m_occlusion);
            m_lastOcclusion = m_occlusion;
        }

        // オクルージョン品質パラメータが変更されたら -> 構造体を一度プッシュ
        if (!Mathf.Approximately(m_occlusionCutoff, m_lastCutoff) ||
            !Mathf.Approximately(m_occlusionBias, m_lastBias) ||
            m_occlusionFootprint != m_lastFootprint ||
            m_occlusionResolution != m_lastResolution)
        {
            m_manager.SetDecalOcclusionSettings(BuildOcclusionSettings());
            CacheOcclusionState();
        }

        // 便利なランタイム調整のため毎フレームプロジェクター / 外観を更新
        if (!m_updateEveryFrame) return;
        m_manager.SetDecalOpacity(m_opacity);
        m_manager.SetDecalEdgeFade(m_edgeFade);
        ApplyProjection();
    }

    /// <summary>現在のプロジェクター姿勢と透視パラメータから投影行列を構築します。</summary>
    private void ApplyProjection()
    {
        Transform p = m_projector != null ? m_projector : this.transform;
        float aspect = m_aspect > 0f
            ? m_aspect
            : (m_videoRT != null ? (float)m_videoRT.width / m_videoRT.height : 1920.0f / 1080.0f);
        m_manager.SetDecalProjection(p.position, p.rotation, m_fov, aspect, m_near, m_far);
    }

    /// <summary>4 つのオクルージョンパラメータを構造体にまとめます。</summary>
    private DecalOcclusionSettings BuildOcclusionSettings()
    {
        return new DecalOcclusionSettings
        {
            opacityCutoff  = m_occlusionCutoff,
            depthBias      = m_occlusionBias,
            footprintMaxPx = m_occlusionFootprint,
            resolution     = m_occlusionResolution,
        };
    }

    private void CacheOcclusionState()
    {
        m_lastOcclusion  = m_occlusion;
        m_lastCutoff     = m_occlusionCutoff;
        m_lastBias       = m_occlusionBias;
        m_lastFootprint  = m_occlusionFootprint;
        m_lastResolution = m_occlusionResolution;
    }

    private void OnDestroy()
    {
        if (m_videoPlayer != null) m_videoPlayer.prepareCompleted -= OnVideoPrepared;
        if (m_videoRT != null)
        {
            m_videoRT.Release();
            Destroy(m_videoRT);
        }
        if (m_frameTex != null) Destroy(m_frameTex);
    }

    // -- 便利なデバッグエントリポイント(Inspector 右クリック) --
    [ContextMenu("デカール オン")]  private void DecalOn()  { m_manager?.SetDecalEnabled(true); }
    [ContextMenu("デカール オフ")] private void DecalOff() { m_manager?.SetDecalEnabled(false); }
    [ContextMenu("オクルージョン オン")]  private void OcclusionOn()  { m_occlusion = true;  m_manager?.SetDecalOcclusion(true);  m_lastOcclusion = true; }
    [ContextMenu("オクルージョン オフ")] private void OcclusionOff() { m_occlusion = false; m_manager?.SetDecalOcclusion(false); m_lastOcclusion = false; }
}

注:

  • ビデオとシーンの読み込みは並行実行:Start() で先に SetupVideo() を呼び出して VideoPlayer.Prepare() を開始し、その後に点群シーンの Load を開始します。両者は互いにブロックしません。
  • フレームバッファはビデオ準備完了後にのみ割り当て:RenderTexture と Texture2D のサイズはビデオの実際の解像度(vp.width / vp.height)から取得するため、prepareCompleted コールバック OnVideoPrepared で作成します。
  • デカールはシーン読み込み完了後にのみ有効化:通常のデカールと同様、SetDecalTexture / SetDecalEnabled は OnSceneLoaded コールバックに配置します。その時点でビデオが未準備の場合、m_frameTex は null で最初のテクスチャ設定はスキップされます。Update() で最初のフレームが届いたときに埋められます。

手順 2:スクリプトをアタッチしてプロパティを設定する

  1. VideoStreaming.cs スクリプトを Hierarchy ウィンドウの LCCRenderer GameObject にアタッチします。
  2. Inspector ウィンドウで LCCManager GameObject をスクリプトの Manager プロパティへドラッグします。
  3. Projector GameObject をスクリプトの Projector プロパティへドラッグします。
  4. File Path プロパティに LCC シーンファイルパスを入力します。
  5. ビデオソースを指定します。次のいずれかを選択します。
    • プロジェクトから VideoClip アセットを Video Clip プロパティへドラッグする。または
    • Video Url プロパティにビデオファイルパスを入力する(例:file:///D:/sample.mp4)。
    • 両方に入力した場合は Video Clip が優先されます。
  6. その他のプロパティは必要に応じて調整できます。各意味は以下の表のとおりです。
VideoStreaming スクリプトの Inspector プロパティ設定

VideoStreaming スクリプトの Inspector プロパティ設定

フィールド意味デフォルト値
Managerシーン内の LCCManager インスタンス必須
File Path有効な LCC シーンパス必須
Video Clip投影するビデオアセット。Video Url より優先空
Video Urlビデオファイルパス / URL。クリップ未指定時に使用空
Video Loopループ再生するかどうかチェック
Projectorプロジェクターの姿勢。+Z が投影方向。空の場合はこのオブジェクトの Transform を使用空
Fovプロジェクターの透視視野角60
Aspect投影アスペクト比。0 以下の場合はビデオのアスペクト比から自動計算0(自動)
Near / Farプロジェクターフラスタムの近 / 遠クリッピングプレーン0.1 / 100
Opacityデカール全体の不透明度1
Edge Fadeエッジフェード幅(UV 比)。0 はハードエッジ0.1
Update Every Frame毎フレームプロジェクター / 外観を更新。ランタイム調整に便利チェック
Occlusionオクルージョンカリングを有効にするかどうかオフ
Occlusion Cutoff / Bias / Footprint / Resolutionオクルージョンカリング品質パラメータ。投影デカール開発ガイド を参照0 / 0.05 / 2 / 1024

手順 3:実行して効果を確認する

Unity で Play をクリックします。Prepare 完了後にビデオが再生を開始します。シーン読み込み完了後にデカールが自動的にオンになり、ビデオフレームがフレームごとに 3DGS サーフェスへ投影されます。Update Every Frame にチェックが入っている場合、Scene ビューでプロジェクターを直接ドラッグすると、点群サーフェス上のビデオフレームがリアルタイムに動くのが確認できます。

実行後にビデオフレームが 3DGS サーフェスへ投影された様子

実行後にビデオフレームが 3DGS サーフェスへ投影された様子

ビデオとシーンの空間的アライメント

「空間的アライメント」とは、ビデオフレームを 希望する位置・向き・サイズで点群へ正確に投影 することです。ビデオフレームの位置は完全にプロジェクター(SetDecalProjection)で決まり、ビデオ内容とは無関係です。アライメントに影響するパラメータは以下のとおりです。

パラメータ由来アライメントへの影響
プロジェクターの 位置(Projector.position)Projector の Transformフラスタム頂点のワールド座標、つまりビデオを「どこから」投影するかを決定します。平行移動すると、フレームが点群に落ちる位置がずれます。
プロジェクターの 向き(Projector.rotation)Projector の Transform+Z が投影方向です。回転させると投影方向が変わり、フレームがサーフェス上で移動 / 傾きます。
Fov(垂直視野角)スクリプトフィールド m_fovフラスタムの開き角を決定し、点群上のフレームの サイズ に直接影響します。FOV が大きいほどフレームは大きく、小さいほど集約されます。範囲 [1, 179]。
Aspect(アスペクト比)スクリプトフィールド m_aspectフレームの横縦比を決定します。0 にするとビデオの解像度アスペクト比が自動使用されます(m_videoRT.width / height)。ビデオが引き伸ばされないようにする推奨方法です。手動値が間違っているとフレームが引き伸ばされます。
Near / Far(近 / 遠クリッピングプレーン)スクリプトフィールド m_near / m_far投影方向に沿ったフラスタムの有効深度区間を決定します。[near, far] 内の点のみが着色されます。Far が小さすぎると遠くの点群が切れ、Near が大きすぎると近くの点群が漏れます。対象点群の深度範囲をカバーする必要があります。

一般的なアライメント手順:

  1. まず Aspect を 0(自動)のままにしてフレームの歪みを防ぎ、位置とサイズの調整に集中します。
  2. Projector の位置と向きをドラッグして、フレームを対象領域の中心に合わせます(リアルタイムプレビューには Update Every Frame をチェック)。
  3. Fov を調整してフレームのカバーサイズを制御します。
  4. Near / Far 区間が対象点群の深度を完全にカバーしていることを確認し、クリッピングプレーンでフレームが切れないようにします。
  5. 特定の比率を強制する必要がある場合(例:16:9 ビデオを正方形領域に投影)は、Aspect を手動で設定します。

ヒント:

ビデオの フレーム比率 は Aspect で制御され、ビデオの 解像度 は明瞭度と読み戻しコストにのみ影響し、点群へ投影される物理サイズには影響しません。サイズは Fov と投影距離の組み合わせで決まります。

ビデオフレームが点群のどこにどの大きさで落ちるかに対するプロジェクターパラメータの影響

プロジェクターの姿勢 / Fov / Aspect / Near-Far が、ビデオフレームの落ちる位置と大きさに与える影響

ビデオフレームレートとレンダリングフレームレートのアライメント

これはビデオデカールで最も重要な部分です。ビデオフレームレート(例:25/30 FPS)は通常、シーンレンダリングフレームレート(3DGS シーンは数百 FPS で動作することも)よりはるかに低いです。 レンダリングフレームごとに「読み戻し + SetDecalTexture」を行うと、次の 2 つの問題があります。

  • 冗長な作業:同じビデオフレームが繰り返しコピー・プッシュされ、純粋な無駄になります。
  • パフォーマンス低下:ReadPixels は GPU→CPU の読み戻しで、コストが無視できません。高いレンダリングフレームレートで毎フレーム実行すると、顕著なフレームドロップを引き起こします。

デカップリング戦略:VideoPlayer.frame を拍子として使う

VideoPlayer.frame は現在の デコード済みフレームインデックス で、ビデオ自身の再生レートでのみ増加します。レンダリングフレームレートがどれほど高くても、このインデックスは 2 つのビデオフレームの間で変わりません。これに基づき、「インデックスが変化したとき」だけテクスチャを更新します。

if (m_videoReady && m_videoPlayer.frame != m_lastVideoFrame)
{
    m_lastVideoFrame = m_videoPlayer.frame;

    // 新しいデコードフレームが届いたときだけ一度読み戻してデカールをプッシュ
    RenderTexture prev = RenderTexture.active;
    RenderTexture.active = m_videoRT;
    m_frameTex.ReadPixels(new Rect(0, 0, m_videoRT.width, m_videoRT.height), 0, 0, false);
    m_frameTex.Apply(false);
    RenderTexture.active = prev;

    m_manager.SetDecalTexture(m_frameTex);
}

これにより:

  • シーンが 300 FPS、ビデオが 30 FPS でレンダリングされる場合、300 フレームのうち約 30 フレームだけが実際に読み戻しとプッシュを行い、残りのフレームは if で直接スキップされます。
  • 拍子はプレイヤー自身が制御 します。ビデオフレームレートに合わせる手書きタイマーは不要で、レンダリングフレームレートの変動によるフレームの欠落や重複もありません。
  • ビデオの速度、ループ、一時停止はすべて VideoPlayer が内部で管理し、frame インデックスはそれらを忠実に反映します。スクリプトに追加の同期は不要です。

なぜ毎フレームタイマーを使わないのか?

Time.deltaTime を手動で累積してビデオフレーム間隔を近似するには、レンダリングフレームレートのジッターとビデオの速度変更 / フレームスキップの両方を処理する必要があり、プレイヤーの実際の内部デコード進捗から簡単にずれます。VideoPlayer.frame を直接読むことで、プレイヤーを唯一の情報源にできます。最もシンプルで堅牢です。

Update Every Frame について:

スクリプトの m_updateEveryFrame は、プロジェクター姿勢 / 不透明度 / フェード を毎フレーム更新するかどうかを制御するもので、ビデオフレーム更新とは別の話です。ビデオフレーム更新は常に VideoPlayer.frame の拍子に従い、このスイッチの影響を受けません。

パフォーマンスとフォーマットに関する注意

  • 読み戻しコストは解像度に比例します。 ReadPixels + Apply は GPU→CPU→GPU の往復です。解像度が高いほど遅くなります。この例はシンプルさと十分なデモのために使用しています。ビデオ解像度が非常に高い場合や性能に敏感な場合は、純粋な GPU コピー Graphics.CopyTexture(m_videoRT, m_frameTex) に切り替えられますが、ソースとターゲットのフォーマットが一致している必要があります(RenderTextureFormat.ARGB32 は TextureFormat.RGBA32 に対応)。また、一部のプラットフォームでは CopyTexture が制限されます。
  • SetDecalTexture は Texture2D のみ受け付けます。 これこそが RenderTexture を Texture2D に読み戻す必要がある理由です。VideoPlayer の RenderTexture をデカールインターフェースへ直接渡すことはできません。
  • フレームバッファを再利用し、毎フレーム new しない。 この例では m_frameTex はビデオ準備完了時に一度だけ作成し、以降は毎フレーム同じ Texture2D を再利用して、頻繁な割り当て / GC を防ぎます。
  • リソースを適時に解放する。 OnDestroy で RenderTexture と Texture2D を Release() / Destroy し、prepareCompleted を解除してリークを防ぎます。
  • 音声は接続していません。 この例では audioOutputMode を None に設定し、映像のみを実演しています。音声が必要な場合は AudioSource モードに変更し、AudioSource をアタッチします。

通常デカールとの違いのまとめ

観点通常デカール(Decal.cs)ビデオデカール(VideoStreaming.cs)
デカール内容静的な Texture2Dビデオをフレーム単位でデコードした Texture2D
テクスチャソースInspector で画像をドラッグVideoPlayer デコード → RenderTexture → 読み戻し
テクスチャ更新タイミング一度だけ設定VideoPlayer.frame の拍子でフレームごとに更新
追加コンポーネントなし実行時に AddComponent<VideoPlayer>()
Aspect の自動値画像のアスペクト比ビデオのアスペクト比
その他(プロジェクター / オクルージョン / API)まったく同じまったく同じ

関連する主要 API

SDK 側では、ビデオデカールは SetDecalTexture の 動的更新 能力を追加で使用するだけで、その他のデカール API は通常デカールとまったく同じです。投影デカール開発ガイド · デカール関連 API を参照してください。

SetDecalTexture(動的更新)

// 戻り値: void
public void SetDecalTexture(Texture2D tex)

デカールテクスチャを設定します。RGB はカラー、A はデカール自身のマスクです。このメソッドは 実行時に繰り返し呼び出すことに対応 しています。新しい Texture2D を渡すたびに現在のデカール内容が即座に置き換えられます。これこそがフレーム単位ビデオ投影の基礎です。Update() で新しいデコードフレームが出現するたびに一度呼び出します。

パラメータ型説明
texTexture2Dデカールテクスチャ。実行時に繰り返し置き換え可能

その他の関連する Unity 内蔵型(VideoPlayer / RenderTexture / Texture2D)は標準の Unity API です。使い方は Unity 公式ドキュメントを参照してください。