Özelliklere Genel Bakış
Video projeksiyonlu decal, Projeksiyonlu Decal özelliğinin bir uzantısıdır: yansıtılan içerik artık statik bir görsel değil, bir videodur. Yaklaşım, videoyu Unity'nin yerleşik VideoPlayer bileşeniyle çözmek ve her karede decal dokusunu dinamik olarak güncellemektir. Böylece video, bir slayt projektörü gibi 3DGS nokta bulutu yüzeyine yansıtılır.
Decal, dünya uzayında sabit bir perspektif projeksiyon olduğundan, video karesi projektörün konumuna göre nokta bulutu yüzeyine "yapıştırılır". Projektörün görüş piramidi içindeki noktalar geçerli video karesiyle renklendirilir; piramidin dışındaki noktalar etkilenmez.
Not:
Normal decal gibi, video decal da yalnızca PC / Mac'te (URP işlem hattı) etkilidir. Mobil veya VR platformlarında ilgili arayüzlerin çağrılması SDK tarafından yok sayılır ve bir uyarı yazdırılır.
Bu kılavuz yalnızca "video" ile ilgili ek kısımları açıklar. Sahne kurulumu (Main Camera / LCCManager / LCCRenderer / Projector), URP Renderer'a Decal Depth Feature eklenmesi, oklüzyon kırpma ayarları ve ayrıntılı decal API'leri gibi temel konular için önce Projeksiyonlu Decal Geliştirme Kılavuzu'nu okuyun.
Uygulama Prensibi
SDK'nın decal arayüzü SetDecalTexture(Texture2D tex) yalnızca Texture2D kabul eder, ancak bu dokunun çalışma zamanında dinamik olarak güncellenmesini destekler. Unity VideoPlayer bileşeninin çözme çıktısı ise (GPU üzerinde) bir RenderTexture nesnesidir. Bu nedenle tüm veri hattı şöyledir:
VideoPlayer decodes → RenderTexture (GPU) → copy to Texture2D → SetDecalTexture(frame texture) → project onto the point cloud
İki temel nokta vardır; bu kılavuzun vurguladığı iki "hizalama" da bunlardır:
- Uzamsal hizalama: nokta bulutuna yansıtılan video karesinin konumu, boyutu ve yönelimi projektör parametreleriyle (konum, FOV, Aspect, Near/Far) belirlenir; bkz. Video ve Sahnenin Uzamsal Hizalanması.
- Zaman hizalaması: video kare hızı, sahne görüntüleme kare hızından çoğu zaman çok daha düşüktür (sahne yüzlerce FPS ile çalışabilir). Bu nedenle dokuyu her görüntüleme karesinde kopyalayıp göndermemelisiniz. Yeni bir çözülmüş karenin oluşup oluşmadığını anlamak için
VideoPlayer.framedeğerini kullanın ve yalnızca yeni kare geldiğinde güncelleyin; bkz. Video Kare Hızı ile Görüntüleme Kare Hızının Hizalanması.

Video projeksiyonlu decal veri hattı: VideoPlayer → RenderTexture → Texture2D → SetDecalTexture
Ön Koşullar
Video decal, normal decal ile aynı ön koşulları paylaşır. Başlamadan önce aşağıdakileri kontrol edin:
- Sahnede Main Camera, LCCManager, LCCRenderer ve Projector zaten kurulmuştur (bkz. Projeksiyon Decal Geliştirme Kılavuzu · Adım 1).
- Şu anda URP işlem hattı kullanılmaktadır. Oklüzyon kırpması gerekiyorsa Decal Depth Feature, URP Renderer Asset içine kaydedilmiştir.
- Console hata bildirir ve hiçbir efekt görünmezse Render Graph compatibility mode seçeneğini devre dışı bırakın (bkz. Projeksiyon Decal Geliştirme Kılavuzu Sık Sorulan Sorular bölümü).
- Bir video varlığı hazırlayın: Bu, proje içindeki bir
VideoClipvarlığı veya diskteki / ağdaki bir video dosyası URL'si olabilir (ör.file:///D:/sample.mp4).
Adım 1: Betiği Yazın
VideoStreaming.cs adlı yeni bir C# betiği oluşturun. Normal Decal.cs iskeletini temel alan bu betik, "statik decal dokusu" yerine "çalışma zamanında videoyu çözmek için bir VideoPlayer oluşturur ve Update() içinde decal dokusunu çözülen karelere göre günceller". Doğrudan projenize kopyalayabilirsiniz.
using LCCCore;
using UnityEngine;
using UnityEngine.Video;
public class VideoStreaming : MonoBehaviour
{
[Header("Required")]
[Tooltip("The LCCManager instance in the scene")]
public LCCManager m_manager;
[Tooltip("A valid LCC scene path")]
public string m_filePath;
[Header("Video source (decoded frames are projected as the decal)")]
[Tooltip("Video clip to project. Takes priority over the URL below")]
public VideoClip m_videoClip;
[Tooltip("Video file path / URL, used when no clip is assigned (e.g. file:///D:/xxx.mp4)")]
public string m_videoUrl;
[Tooltip("Loop playback")]
public bool m_videoLoop = true;
[Header("Projector (projects along +Z)")]
[Tooltip("Projector pose. Leave empty to use this object's transform")]
public Transform m_projector;
[Range(1f, 179f)] public float m_fov = 60f;
[Tooltip("Projection aspect ratio; <=0 uses the video's aspect ratio automatically")]
public float m_aspect = 0f;
public float m_near = 0.1f;
public float m_far = 100f;
[Header("Decal appearance")]
[Range(0f, 1f)] public float m_opacity = 1.0f;
[Range(0f, 0.5f)][Tooltip("Edge fade width (UV ratio). 0 = hard edge")]
public float m_edgeFade = 0.1f;
[Tooltip("Refresh projection every frame, so you can drag the projector / tweak params at runtime")]
public bool m_updateEveryFrame = true;
[Header("Occlusion culling (PC/Mac only)")]
[Tooltip("When on, back-facing/occluded points behind front geometry are no longer colored by the decal (slide-projector effect); when off it is X-ray")]
public bool m_occlusion = false;
[Range(0f, 1f)][Tooltip("Opacity threshold: only splats with opacity >= this value contribute to the depth map, filtering out floaters/foggy points. 0 = all participate")]
public float m_occlusionCutoff = 0f;
[Range(0f, 0.5f)][Tooltip("Relative depth tolerance. Too small -> near-surface self-occlusion; too large -> leaked X-ray coloring. Default 0.05")]
public float m_occlusionBias = 0.05f;
[Range(0, 16)][Tooltip("Square footprint radius cap (px), the main knob for removing X-ray bleed-through. 0 = single texel, default 2")]
public int m_occlusionFootprint = 2;
[Tooltip("Depth map resolution (px, power of two 256~4096). Lower it to fill grazing-angle holes. Default 1024")]
public int m_occlusionResolution = 1024;
// -- Runtime state --
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;
// -- Video state --
private VideoPlayer m_videoPlayer;
private RenderTexture m_videoRT; // VideoPlayer decodes the video here (GPU)
private Texture2D m_frameTex; // the current frame is copied here and fed to the decal
private bool m_videoReady;
private long m_lastVideoFrame = -1; // the last frame index pushed to the decal
void Start()
{
if (m_manager == null || string.IsNullOrEmpty(m_filePath))
{
Debug.LogError("[VideoStreaming] m_manager or m_filePath is not assigned.");
enabled = false;
return;
}
// 1) Initialize the render pipeline to PC single-scene editor mode
m_manager.SetPlatformType(PlatformType.PC);
m_manager.SwitchRenderPass(ActiveRenderMode.SingleRender);
m_manager.SetEditorMode(true);
// 2) Start decoding the video in parallel with scene loading
SetupVideo();
// 3) Load the point cloud scene, then enable the decal (decal is a global state; it is safest to set it after the scene is ready)
var renderer = m_manager.GetRender(this.transform);
Debug.Log($"[VideoStreaming] Start loading: {m_filePath}");
renderer.Load(m_filePath,
_ => { /* progress callback, unused in this example */ },
OnSceneLoaded);
}
/// <summary>Create the VideoPlayer at runtime and start preparing the clip/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; // demo: no audio
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;
}
// Allocate the frame buffer once the resolution is known, then start playback.
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] Video prepared: {w}x{h}, playing.");
}
private void OnSceneLoaded()
{
Debug.Log("[VideoStreaming] Load complete, enabling decal projection.");
// -- Base projection: 5 APIs --
// Texture content is driven by decoded frames in Update(); here we push the current available frame first.
if (m_frameTex != null) m_manager.SetDecalTexture(m_frameTex);
m_manager.SetDecalOpacity(m_opacity); // overall opacity
m_manager.SetDecalEdgeFade(m_edgeFade); // edge fade
ApplyProjection(); // projector pose (internally calls SetDecalProjection)
m_manager.SetDecalEnabled(true); // enable decal (_DECAL keyword)
// -- Occlusion culling: 2 APIs -- must be after ApplyProjection (the depth map needs a valid projector VP matrix)
m_manager.SetDecalOcclusionSettings(BuildOcclusionSettings());
m_manager.SetDecalOcclusion(m_occlusion);
CacheOcclusionState();
m_loaded = true;
}
void Update()
{
if (!m_loaded) return;
// --- Video frame update, decoupled from render FPS ---
// VideoPlayer.frame only increments at the video's own playback rate. Even if the scene renders at hundreds of FPS,
// the index stays the same between two adjacent video frames, so only when a new decoded frame actually appears
// do we copy that frame and push the decal texture again.
if (m_videoReady && m_videoPlayer.frame != m_lastVideoFrame)
{
m_lastVideoFrame = m_videoPlayer.frame;
// Copy the RenderTexture on the GPU to the Texture2D accepted by the decal API.
// This only runs at the video frame rate, so the readback cost is manageable.
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);
}
// toggle occlusion at runtime
if (m_occlusion != m_lastOcclusion)
{
m_manager.SetDecalOcclusion(m_occlusion);
m_lastOcclusion = m_occlusion;
}
// if any occlusion quality parameter changed -> push the struct once
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();
}
// refresh projector / appearance every frame for convenient runtime tuning
if (!m_updateEveryFrame) return;
m_manager.SetDecalOpacity(m_opacity);
m_manager.SetDecalEdgeFade(m_edgeFade);
ApplyProjection();
}
/// <summary>Build the projection matrix from the current projector pose and perspective parameters.</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>Collect the 4 occlusion parameters into a struct.</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);
}
// -- Convenient debug entry points (Inspector right-click) --
[ContextMenu("Decal On")] private void DecalOn() { m_manager?.SetDecalEnabled(true); }
[ContextMenu("Decal Off")] private void DecalOff() { m_manager?.SetDecalEnabled(false); }
[ContextMenu("Occlusion On")] private void OcclusionOn() { m_occlusion = true; m_manager?.SetDecalOcclusion(true); m_lastOcclusion = true; }
[ContextMenu("Occlusion Off")] private void OcclusionOff() { m_occlusion = false; m_manager?.SetDecalOcclusion(false); m_lastOcclusion = false; }
}
Not:
- Video ve sahne yüklemesi paralel çalışır:
Start()içinde önceSetupVideo()çağrılarakVideoPlayer.Prepare()başlatılır, ardından nokta bulutu sahnesininLoadişlemi başlatılır. İkisi birbirini engellemez.- Kare arabelleği yalnızca video hazır olduktan sonra ayrılır:
RenderTextureveTexture2Dboyutları videonun gerçek çözünürlüğünden (vp.width/vp.height) alınır. Bu nedenleprepareCompletedgeri çağrısı olanOnVideoPreparediçinde oluşturulurlar.- Decal yalnızca sahne yüklemesi bittikten sonra etkinleştirilir: Normal decal ile aynı şekilde,
SetDecalTexture/SetDecalEnabledçağrılarıOnSceneLoadedgeri çağrısına yerleştirilir. Bu noktada video hazır değilsem_frameTexnull olur ve ilk doku atama işlemi atlanır. Doku, ilk kareUpdate()içinde geldiğinde doldurulur.
Adım 2: Betiği Ekleyin ve Özellikleri Yapılandırın
VideoStreaming.csbetiğini Hierarchy penceresindeki LCCRenderer GameObject'ine ekleyin.- Inspector penceresinde LCCManager GameObject'ini betiğin Manager özelliğine sürükleyin.
- Projector GameObject'ini betiğin Projector özelliğine sürükleyin.
- LCC sahne dosyasının yolunu File Path özelliğine girin.
Video kaynağını belirtin; iki seçenekten birini kullanın:
- Projedeki bir VideoClip varlığını Video Clip özelliğine sürükleyin veya
- Video dosyasının yolunu Video Url özelliğine girin (ör.
file:///D:/sample.mp4). - İkisi de doldurulursa Video Clip önceliklidir.
- Diğer özellikler ihtiyaca göre ayarlanabilir; anlamları aşağıdaki tabloda verilmiştir.

VideoStreaming betiğinin Inspector özellik ayarları
| Alan | Anlamı | Varsayılan değer |
|---|---|---|
| Manager | Sahnedeki LCCManager örneği | Gerekli |
| File Path | Geçerli bir LCC sahne yolu | Gerekli |
| Video Clip | Yansıtılacak video varlığı; Video Url'den daha yüksek önceliğe sahiptir | Boş |
| Video Url | Video dosya yolu / URL'si; klip belirtilmediğinde kullanılır | Boş |
| Video Loop | Oynatmanın döngüde olup olmayacağı | İşaretli |
| Projector | Projektör konumu ve yönü; +Z projeksiyon yönüdür. Boş bırakılırsa bu nesnenin Transform bileşeni kullanılır | Boş |
| Fov | Projektörün perspektif görüş alanı | 60 |
| Aspect | İzdüşüm en-boy oranı; 0 veya daha küçük olduğunda videonun en-boy oranından otomatik hesaplanır | 0 (otomatik) |
| Near / Far | Projektör frustum'unun yakın / uzak kırpma düzlemleri | 0.1 / 100 |
| Opaklık | Decal'in genel opaklığı | 1 |
| Edge Fade | Kenar solma genişliği (UV oranı); 0 sert kenar demektir | 0.1 |
| Update Every Frame | Projektörü / görünümü her karede yeniler; çalışma zamanında ayar yapmayı kolaylaştırır | İşaretli |
| Occlusion | Örtme ayıklamasının etkinleştirilip etkinleştirilmeyeceği | Kapalı |
| Occlusion Cutoff / Bias / Footprint / Resolution | Oklüzyon kırpması kalite parametreleri; bkz. Projeksiyon Decal Geliştirme Kılavuzu | 0 / 0.05 / 2 / 1024 |
Adım 3: Çalıştırın ve Efekti Gözlemleyin
Unity'de Play düğmesine tıklayın. Video, Prepare tamamlandıktan sonra oynatılmaya başlar. Sahne yüklemesi bittiğinde decal otomatik olarak açılır ve video kareleri 3DGS yüzeyine kare kare yansıtılır. Update Every Frame işaretliyse projektörü Scene görünümünde doğrudan sürükleyebilir ve video karesinin nokta bulutu yüzeyinde gerçek zamanlı olarak hareket ettiğini görebilirsiniz.

Çalıştırma sonrasında 3DGS yüzeyine yansıtılan video kareleri
Video ile Sahnenin Uzamsal Hizalanması
"Uzamsal hizalama", video karesinin nokta bulutuna istediğiniz konumda, yönde ve boyutta doğru şekilde yansıtılmasını sağlamak anlamına gelir. Video karesinin konumunu tamamen projektör (SetDecalProjection) belirler; video içeriğinden bağımsızdır. Hizalamayı etkileyen parametreler aşağıdadır:
| Parametre | Source | Hizalamaya etkisi |
|---|---|---|
| Projektör konumu (Projector.position) | Projector'ın Transform bileşeni | Kesik piramidin tepe noktasının dünya koordinatını, yani videonun "nereden" yansıtıldığını belirler. Konumu kaydırmak, karenin nokta bulutu üzerinde düştüğü yeri değiştirir. |
| Projektör yönü (Projector.rotation) | Projector'ın Transform bileşeni | +Z, projeksiyon yönüdür. Projektörü döndürmek projeksiyon yönünü değiştirir; kare de yüzeyde buna göre kayar / eğilir. |
| Fov (dikey görüş alanı) | Betik alanı m_fov | Kesik piramidin açılma açısını belirler ve karenin nokta bulutu üzerindeki boyutunu doğrudan etkiler: FOV büyüdükçe kare büyür, küçüldükçe kare daha yoğunlaşır. Aralık: [1, 179]. |
| Aspect (en-boy oranı) | Betik alanı m_aspect | Karenin yatay/dikey oranını belirler. 0 olarak ayarlandığında videonun çözünürlük en-boy oranı otomatik olarak kullanılır (m_videoRT.width / height). Videonun gerilmesini önlemek için önerilen yöntem budur. Elle girilen yanlış bir değer karenin gerilmesine neden olur. |
| Near / Far (yakın / uzak kırpma düzlemleri) | Betik alanları m_near / m_far | Kesik piramidin projeksiyon yönü boyunca etkin derinlik aralığını belirler. Yalnızca [near, far] aralığındaki noktalar renklendirilir. Far değeri çok küçükse uzaktaki nokta bulutları kırpılır, Near değeri çok büyükse yakındakiler gözden kaçar. Değerler, hedef nokta bulutunun derinlik aralığını kapsamalıdır. |
Genel hizalama adımları:
- Önce kare bozulmasını önlemek için Aspect değerini 0 (otomatik) olarak bırakın ve konum ile boyutu ayarlamaya odaklanın.
- Kareyi hedef alanın merkezine yerleştirmek için Projector konumunu ve yönünü sürükleyin (gerçek zamanlı önizleme için Update Every Frame seçeneğini işaretleyin).
- Karenin kapsama boyutunu kontrol etmek için Fov değerini ayarlayın.
- Karenin kırpma düzlemleri tarafından kesilmemesi için Near / Far aralığının hedef nokta bulutunun derinliğini tamamen kapsadığını doğrulayın.
- Belirli bir oranı zorlamanız gerekiyorsa (ör. 16:9 bir videoyu kare bir alana yansıtmak), Aspect değerini elle ayarlayın.
İpucu:
Videonun kare oranını Aspect belirler. Videonun çözünürlüğü ise yalnızca netliği ve geri okuma maliyetini etkiler; nokta bulutuna yansıtılan fiziksel boyutu etkilemez. Boyutu Fov ve projeksiyon mesafesi birlikte belirler.

Projektör pozunun / Fov / Aspect / Near-Far değerlerinin video karesinin nokta bulutu üzerindeki konumuna ve boyutuna etkisi
Video Kare Hızı ile Görüntüleme Kare Hızının Hizalanması
Video decal'in en kritik kısmı budur. Video kare hızı (ör. 25/30 FPS) genellikle sahne görüntüleme kare hızından çok daha düşüktür (bir 3DGS sahnesi yüzlerce FPS ile çalışabilir). Her görüntüleme karesinde "geri okuma + SetDecalTexture" işlemi yaparsanız iki sorun ortaya çıkar:
- Gereksiz iş yükü: Aynı video karesi tekrar tekrar kopyalanır ve tekrar tekrar gönderilir; bu tamamen israftır.
- Performans yükü:
ReadPixels, maliyeti düşük olmayan bir GPU→CPU geri okumasıdır. Yüksek görüntüleme kare hızında her karede çalıştırılması belirgin kare düşüşlerine neden olur.
Ayrıştırma Stratejisi: VideoPlayer.frame Değerini Vuruş Olarak Kullanma
VideoPlayer.frame, geçerli çözülmüş kare dizinidir ve yalnızca videonun kendi oynatma hızında artar. Görüntüleme kare hızı ne kadar yüksek olursa olsun, bu dizin iki video karesi arasında değişmez. Buna dayanarak dokuyu yalnızca "dizin değiştiğinde" güncelleyin:
if (m_videoReady && m_videoPlayer.frame != m_lastVideoFrame)
{
m_lastVideoFrame = m_videoPlayer.frame;
// Only readback once and push the decal when a new decoded frame arrives
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);
}
Bu sayede:
- Sahne 300 FPS ile görüntülenirken video 30 FPS ise, 300 görüntüleme karesinin yalnızca yaklaşık 30'unda geri okuma ve aktarım yapılır. Kalan kareler
ifkoşulu tarafından doğrudan atlanır. - Vuruşu oynatıcının kendisi belirler. Video kare hızına uymak için elle yazılmış bir zamanlayıcıya gerek yoktur. Görüntüleme kare hızındaki dalgalanmalar nedeniyle kare atlanmaz veya tekrarlanmaz.
- Videonun hızı, döngüsü ve duraklatılması
VideoPlayertarafından dahili olarak yönetilir.framedizini bunları doğru biçimde yansıtır, bu nedenle betikte ek bir senkronizasyona gerek yoktur.
Neden Her Kare İçin Zamanlayıcı Kullanılmaz?
Video kare aralığını yaklaşık olarak hesaplamak için
Time.deltaTimedeğerini elle toplamak, hem görüntüleme kare hızındaki titreşimin hem de video hızı değişikliklerinin / kare atlamanın ele alınmasını gerektirir. Ayrıca oynatıcının gerçek dahili çözme ilerlemesinden kolayca sapabilir.VideoPlayer.framedeğerini doğrudan okumak, oynatıcıyı tek doğru kaynak yapar. Bu yöntem en basit ve en sağlam olanıdır.
Update Every Frame Hakkında
Betikteki
m_updateEveryFrame, projektör pozunun / opaklığın / solma efektinin her karede yenilenip yenilenmeyeceğini denetler. Bu, video karesi güncellemesinden ayrı bir konudur. Video karesi güncellemesi her zamanVideoPlayer.framevuruşunu izler ve bu anahtardan etkilenmez.
Performans ve Biçim Notları
- Geri okuma maliyeti çözünürlükle orantılıdır.
ReadPixels+Apply, GPU→CPU→GPU gidiş-dönüş işlemidir. Çözünürlük arttıkça işlem yavaşlar. Bu örnek, sadelik ve yeterli gösterim için bu yöntemi kullanır. Video çözünürlüğü çok yüksekse veya performans hassasiyeti varsa, saf GPU kopyası olanGraphics.CopyTexture(m_videoRT, m_frameTex)yöntemine geçebilirsiniz. Ancak kaynak ve hedef biçimleri eşleşmelidir (RenderTextureFormat.ARGB32,TextureFormat.RGBA32ile eşleşir). Bazı platformlar CopyTexture kullanımını kısıtlar. SetDecalTextureyalnızcaTexture2Dkabul eder.RenderTextureiçeriğinin birTexture2Düzerine geri okunması gerekmesinin nedeni tam olarak budur.VideoPlayer'ınRenderTexturenesnesini decal arayüzüne doğrudan aktaramazsınız.- Kare arabelleğini yeniden kullanın, her karede
newile oluşturmayın. Örnektem_frameTexyalnızca video hazır olduğunda bir kez oluşturulur. Sonraki her karede aynıTexture2Dyeniden kullanılır. Bu, sık bellek ayırmayı / GC yükünü önler. - Kaynakları zamanında serbest bırakın.
OnDestroyiçindeRenderTextureveTexture2Dnesneleri içinRelease()veDestroyçağırın, ayrıcaprepareCompletedkaydını kaldırın. Böylece bellek sızıntıları önlenir. - Ses bağlanmamıştır. Örnek,
audioOutputModedeğeriniNoneolarak ayarlar ve yalnızca görüntüyü gösterir. Ses gerekiyorsaAudioSourcemoduna geçin ve birAudioSourcebileşeni ekleyin.
Normal Decal ile Farkların Özeti
| Aspect | Normal Decal (Decal.cs) | Video Decal (VideoStreaming.cs) |
|---|---|---|
| Decal İçeriği | Statik Texture2D | Kare kare video çözmeden elde edilen Texture2D |
| Doku Kaynağı | Inspector'da bir görüntü sürükleyin | VideoPlayer çözme → RenderTexture → geri okuma |
| Doku Güncelleme Zamanı | Bir kez ayarlanır | VideoPlayer.frame vuruşunda kare kare güncellenir |
| Ek Bileşen | None | Çalışma zamanında AddComponent<VideoPlayer>() |
| Otomatik en-boy oranı değeri | Görüntü en-boy oranı | Video en-boy oranı |
| Geri kalan her şey (projektör / örtüşme / API) | Tamamen aynıdır | Tamamen aynıdır |
İlgili Temel API'ler
SDK tarafında video decal, yalnızca SetDecalTexture yönteminin dinamik güncelleme özelliğini ek olarak kullanır. Diğer decal API'leri normal decal ile tamamen aynıdır. Bkz. Projeksiyonlu Decal Geliştirme Kılavuzu · Decal ile İlgili API'ler.
SetDecalTexture (dinamik güncelleme)
// Return value: void
public void SetDecalTexture(Texture2D tex)
Decal dokusunu ayarlar. RGB renktir, A ise decal'in kendi maskesidir. Bu yöntem çalışma zamanında tekrar tekrar çağrılabilir: Her yeni Texture2D aktarıldığında mevcut decal içeriği hemen değiştirilir. Kare kare video projeksiyonunun temeli tam olarak budur: Update() içinde yeni bir çözülmüş kare göründüğünde yöntemi bir kez çağırın.
| Parametre | Tür | Açıklama |
|---|---|---|
tex | Texture2D | Decal dokusu, çalışma zamanında tekrar tekrar değiştirilebilir |
Diğer ilgili Unity yerleşik türleri (VideoPlayer / RenderTexture / Texture2D) standart Unity API'leridir. Kullanım için resmi Unity belgelerine bakın.
Bu bölüm XGRIDS'in resmî kullanım kılavuzundan Türkçeye çevrildi; ekran görüntüleri ve arayüz adları özgün haliyle İngilizcedir. İngilizce aslı (yeni sekmede açılır) · Güncelleme:

