ビデオ投影デカール開発ガイド
機能概要
ビデオ投影デカールは 投影デカール の拡張です。投影する内容が静的な画像ではなく ビデオ になります。アプローチは、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 つの「アライメント」です。
- 空間的アライメント:点群に投影されるビデオフレームの位置・サイズ・向きは、プロジェクターパラメータ(姿勢、FOV、Aspect、Near/Far)で決まります。ビデオとシーンの空間的アライメント を参照してください。
- 時間的アライメント:ビデオフレームレートはシーンレンダリングフレームレートよりはるかに低いことが多いため(シーンは数百 FPS で動作することもあります)、レンダリングフレームごとにテクスチャをコピーしてプッシュすることはできません。
VideoPlayer.frameを使って新しいデコードフレームが出現したかどうかを検出し、新しいフレームが届いたときだけ更新します。ビデオフレームレートとレンダリングフレームレートのアライメント を参照してください。

ビデオ投影デカールのデータパイプライン:VideoPlayer → RenderTexture → Texture2D → SetDecalTexture
前提条件
ビデオデカールは通常のデカールと同じ前提条件を共有します。開始前に以下を確認してください。
- シーンに Main Camera、LCCManager、LCCRenderer、Projector がセットアップ済みであること(投影デカール開発ガイド · 手順 1 を参照)。
- 現在 URP パイプラインを使用していること。オクルージョンカリングが必要な場合は、URP Renderer Asset に Decal Depth Feature が登録されていること。
- Console にエラーが報告され、効果が表示されない場合は、Render Graph 互換モードを無効にします(投影デカール開発ガイド の FAQ セクションを参照)。
- ビデオアセットを用意します。プロジェクト内の
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:スクリプトをアタッチしてプロパティを設定する
VideoStreaming.csスクリプトを Hierarchy ウィンドウの LCCRenderer GameObject にアタッチします。- Inspector ウィンドウで LCCManager GameObject をスクリプトの Manager プロパティへドラッグします。
- Projector GameObject をスクリプトの Projector プロパティへドラッグします。
- File Path プロパティに LCC シーンファイルパスを入力します。
- ビデオソースを指定します。次のいずれかを選択します。
- プロジェクトから VideoClip アセットを Video Clip プロパティへドラッグする。または
- Video Url プロパティにビデオファイルパスを入力する(例:
file:///D:/sample.mp4)。 - 両方に入力した場合は Video Clip が優先されます。
- その他のプロパティは必要に応じて調整できます。各意味は以下の表のとおりです。

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 サーフェスへ投影された様子
ビデオとシーンの空間的アライメント
「空間的アライメント」とは、ビデオフレームを 希望する位置・向き・サイズで点群へ正確に投影 することです。ビデオフレームの位置は完全にプロジェクター(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 が大きすぎると近くの点群が漏れます。対象点群の深度範囲をカバーする必要があります。 |
一般的なアライメント手順:
- まず Aspect を 0(自動)のままにしてフレームの歪みを防ぎ、位置とサイズの調整に集中します。
- Projector の位置と向きをドラッグして、フレームを対象領域の中心に合わせます(リアルタイムプレビューには Update Every Frame をチェック)。
- Fov を調整してフレームのカバーサイズを制御します。
- Near / Far 区間が対象点群の深度を完全にカバーしていることを確認し、クリッピングプレーンでフレームが切れないようにします。
- 特定の比率を強制する必要がある場合(例: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() で新しいデコードフレームが出現するたびに一度呼び出します。
| パラメータ | 型 | 説明 |
|---|---|---|
tex | Texture2D | デカールテクスチャ。実行時に繰り返し置き換え可能 |
その他の関連する Unity 内蔵型(VideoPlayer / RenderTexture / Texture2D)は標準の Unity API です。使い方は Unity 公式ドキュメントを参照してください。