LCC verisi yeniden oluşturulurken LCC Unity SDK, çarpışmalar için kullanılan Mesh verisini de üretir. Çarpışma algılamanın yanı sıra SDK, bu Mesh verisini çıkarma, Unity Mesh nesnelerine dönüştürme ve görselleştirme imkânı sunar. Bu, NavMesh dışa aktarma ve bake etme gibi senaryolar için kullanışlıdır.
Aşağıdaki tam örnek, tüm Mesh verisini eşzamanlı olarak alma ve belirli bir aralıktaki Mesh verisini istek üzerine alma adımlarını açıklar.
Ortam Kurulumu
Unity'de yepyeni bir sahne oluşturun. Unity varsayılan olarak Main Camera ve Directional Light oluşturur.
Main Camera Ayarlama
Hierarchy penceresinde Main Camera nesnesini seçin ve özelliklerini Inspector penceresinde aşağıda gösterildiği gibi ayarlayın.

Main Camera özelliklerini ayarlama
LCCManager Oluşturma
Hierarchy penceresinde boş bir alana sağ tıklayın, açılan menüden Create Empty seçeneğini seçerek boş bir GameObject oluşturun, adını LCCManager yapın, Transform değerini normalleştirin ve Add Component ile bu nesneye LCCManager betiğini ekleyin.

LCCManager GameObject'ini oluşturun ve LCCManager betiğini ekleyin
LCCRenderer Oluşturma
Hierarchy penceresinde boş bir alana sağ tıklayın, Create Empty seçeneğini seçerek boş bir GameObject oluşturun, adını LCCRenderer yapın ve Transform değerlerini Rotation.x = -90 ve Scale.x = -1 olarak ayarlayın.

LCCRenderer oluşturma ve Transform ayarı (Rotation.x = -90, Scale.x = -1)
Not:
LCCRenderer GameObject'inin Transform ayarları (Rotation.x = -90, Scale.x = -1) onu LCC veri koordinat sistemiyle hizalar. Koordinat sistemi hizalaması hakkında ayrıntılar için Unity SDK'ya Giriş belgesindeki "LCC Veri Koordinat Sistemi" bölümüne bakın.
Veri Ön Koşulları
Mesh verisini alma özelliğinin çalışması için sahnenin ilgili çarpışma Mesh verisini içermesi gerekir (LCC Studio yeniden oluşturma sırasında üretilir). Ayrıca bu özelliğin şu kısıtları vardır:
- Yalnızca PC / Mac desteklenir ve yalnızca yerel veri kaynakları kullanılabilir (HTTP veri kaynakları desteklenmez).
- Yalnızca ana iş parçacığında çağrılabilir.
- Yerel biçimli veriler (PLY / SOG / SPZ / splat / ksplat) çarpışma Mesh verisi içermez; ilgili yöntemler çağrıldığında
nulldöner.
Önceki sürümlerde yeniden oluşturulan veriler çarpışma verisi içermeyebilir. Bu durumda GetMeshes() çağrıldığında null döner.
Tüm Mesh Verisini Eşzamanlı Alma
Tüm Mesh verisini eşzamanlı alma, sahnedeki tüm çarpışma Mesh bloklarının geometri verisini tek seferde okumak anlamına gelir. Bu işlem Renderer.GetMeshes() yöntemiyle yapılır.
Meshes.cs adında yeni bir C# betiği oluşturun ve aşağıdaki kodu ekleyin:
using System.Collections.Generic;
using LCCCore;
using UnityEngine;
using UnityEngine.Rendering;
public class Meshes : MonoBehaviour
{
public LCCManager m_manager;
public string m_FilePath;
private LCCCore.Renderer m_renderer;
private bool m_isLoaded = false;
private Camera m_camera;
private const string kContainerName = "LCCVisualizedMeshes";
void Start()
{
m_camera = Camera.main;
m_isLoaded = false;
m_manager.SetPlatformType(PlatformType.PC);
m_renderer = m_manager.GetRender(this.transform);
m_renderer.Load(m_FilePath,
p => Debug.Log($"[Meshes] load progress: {p:P1}"),
() =>
{
Debug.Log($"[Meshes] file loaded: {m_FilePath}");
m_isLoaded = true;
m_manager.SetAutoFov(false);
},
e => Debug.LogError($"[Meshes] file load error: {e}")
);
}
public void onGetAllMeshes()
{
if (!m_isLoaded || m_renderer == null)
{
Debug.LogWarning("[Meshes] Data has not finished loading; cannot get Meshes.");
return;
}
var meshes = m_renderer.GetMeshes();
if (meshes == null || meshes.Count == 0)
{
Debug.LogWarning("[Meshes] No Meshes obtained (data may not contain colliders).");
return;
}
VisualizeMeshes(meshes);
}
private void VisualizeMeshes(List<LCCMeshBlock> meshes)
{
// Clean up the previous visualization result to avoid piling up
Transform root = m_renderer.Transform;
Transform old = root.Find(kContainerName);
if (old != null) Destroy(old.gameObject);
var container = new GameObject(kContainerName).transform;
container.SetParent(root, false);
Material material = CreateVisualMaterial();
for (int i = 0; i < meshes.Count; i++)
{
LCCMeshBlock block = meshes[i];
if (block.vertices == null || block.vertices.Length == 0) continue;
if (block.triangles == null || block.triangles.Length < 3) continue;
var go = new GameObject(string.IsNullOrEmpty(block.id) ? $"MeshBlock_{i}" : block.id);
go.transform.SetParent(container, false);
var mesh = new Mesh { name = go.name };
// A single block's vertex count may exceed 65535, so 32-bit indices must be used, otherwise the geometry will be corrupted
mesh.indexFormat = IndexFormat.UInt32;
mesh.vertices = block.vertices;
mesh.triangles = block.triangles;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
var mf = go.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
var mr = go.AddComponent<MeshRenderer>();
mr.sharedMaterial = material;
}
Debug.Log($"[Meshes] Created GameObjects and visualized {meshes.Count} Mesh blocks.");
}
private Material CreateVisualMaterial()
{
Shader shader = Shader.Find("Universal Render Pipeline/Lit")
?? Shader.Find("Standard")
?? Shader.Find("Diffuse");
if (shader == null) return null;
var mat = new Material(shader) { color = new Color(0.7f, 0.7f, 0.7f, 1f) };
// Collision mesh triangle winding order is not guaranteed consistent; disable back-face culling for complete display
mat.SetFloat("_Cull", (float)CullMode.Off);
return mat;
}
}
Not:
GetMeshes()eşzamanlı ve ağır bir işlemdir: diskten eşzamanlı okur, ayrıştırır ve bellek ayırır. 262 bloklu bir veri kümesi gibi büyük sahnelerde çok miktarda disk verisi okumak ve birkaç GB ile onlarca GB arasında yönetilen bellek ayırmak gerekebilir. Bir kez çağırıp sonucu kendiniz önbelleğe alın; asla her karede çağırmayın.vertices/boundsLocaldeğerleri nesne yerel koordinat sistemindedir. Bu nedenle görselleştirme GameObject'iniRenderer.Transformaltına bağlarsanız otomatik olarak hizalanır.- Tek bir bloğun köşe noktası sayısı 65535'i aşabilir (ölçülen en yüksek değer 390.656). Kendi
Meshnesnenizi oluşturmadan öncemesh.indexFormat = IndexFormat.UInt32ayarını yapmanız gerekir; aksi halde geometri bozulur.- Çarpışma mesh'indeki üçgenlerin sarma sırasının tutarlı olduğu kesin olarak sağlanamaz. Örnekte, eksiksiz görüntüleme için arka yüz kırpma (
_Cull = Off) devre dışı bırakılmıştır.
Betiği LCCRenderer GameObject'ine ekleyin. Inspector içinde LCCManager GameObject'ini Manager özelliğine sürükleyin ve File Path alanını doldurun.
Ardından bir Button oluşturun ve onGetAllMeshes() yöntemini onClick olayıyla ilişkilendirin.
Çalıştırdıktan sonra Button'a tıklayarak sahnedeki tüm çarpışma Mesh'lerini görebilirsiniz.

Düğmeye tıkladıktan sonra tüm çarpışma Mesh verisinin görselleştirilmesi
İstek Üzerine Mesh Verisi Alma
İstek üzerine alma, tüm Mesh verisini tek seferde okumak yerine yalnızca belirtilen kısmı okumak anlamına gelir. Böylece yüksek G/Ç ve bellek yükünden kaçınılır. Aşağıdaki örnekte, kameranın çevresindeki belirli bir aralıkta kalan Mesh blokları okunmaktadır.
Önce GetMeshBlockInfos() ile tüm blokların meta verisini (dünya uzayındaki sınırlayıcı kutular dahil) alın. Görüntüleme kamerası merkezinden blok BBOX yüzeyine olan mesafeyi dünya koordinatlarında hesaplayın, mesafesi 100 m'den küçük olan blok kimliklerini süzün ve ardından yalnızca bu blokları okumak için parametreli GetMeshes(ids) yöntemini kullanın.
Aşağıdaki yöntemleri Meshes.cs dosyasına ekleyin:
public void onRequireMeshes()
{
if (!m_isLoaded || m_renderer == null)
{
Debug.LogWarning("[Meshes] Data has not finished loading; cannot get Meshes.");
return;
}
// 1. Zero-I/O read of all block metadata, filtering blocks within 100 m by the camera-to-BBOX surface distance
var infos = m_renderer.GetMeshBlockInfos();
if (infos == null || infos.Count == 0)
{
Debug.LogWarning("[Meshes] No Mesh info obtained (data may not contain colliders).");
return;
}
Vector3 camPos = m_camera.transform.position;
var ids = new List<string>();
foreach (var info in infos)
{
// When the camera is inside the BBOX, ClosestPoint returns the camera itself and the distance is 0, so it is also selected
if (calculateMinDistanceToAABB(info.boundsWorld, camPos) < 100f)
ids.Add(info.id);
}
if (ids.Count == 0)
{
Debug.LogWarning("[Meshes] No Mesh blocks within 100 m of the camera.");
return;
}
// 2. Read only the filtered blocks by id and visualize them
var meshes = m_renderer.GetMeshes(ids);
if (meshes == null || meshes.Count == 0)
{
Debug.LogWarning("[Meshes] Failed to get Meshes by id.");
return;
}
VisualizeMeshes(meshes);
Debug.Log($"[Meshes] Selected {ids.Count} blocks within 100 m of the camera, visualized {meshes.Count}.");
}
// Compute the closest distance from a point to the AABB surface (returns 0 when the point is inside the AABB)
private static float calculateMinDistanceToAABB(Bounds _aabb, Vector3 _point)
{
Vector3 p = _aabb.ClosestPoint(_point);
return Vector3.Distance(p, _point);
}
Not:
GetMeshBlockInfos()sıfır G/Ç ve sıfır ayrıştırma gerektiren bir işlemdir; yalnızca bellekte hazır bulunan meta veriyi okur ve serbestçe çağrılabilir.- Mesafe süzme işlemi
boundsWorld(dünya uzayı sınırlayıcı kutusu) değerini kullanır; kamera merkezi olarakCamera.transform.positionalınır.- Bir noktanın AABB yüzeyine en yakın mesafesini hesaplamak için
Bounds.ClosestPointkullanın: kamera BBOX içindeykenClosestPointkameranın kendisini döndürür ve mesafe 0 olur. Bu nedenle o blok da seçilir.- Örnekteki süzme yarıçapı
100f(birim: metre) gerektiğinde ayarlanabilir.
Bir Button oluşturun ve onRequireMeshes() yöntemini onClick olayıyla ilişkilendirin.
Çalıştırdıktan sonra düğmeye tıklayarak kameranın 100 m çevresindeki Mesh bloklarını görebilirsiniz.

Kameranın 100 m çevresindeki Mesh verisinin istek üzerine alınması
Temel Adımlar
Sahne Mesh verisini alma ve görselleştirmenin temel adımları:
SetPlatformTypegibi ön yapılandırmaları tamamlayın ve LCC sahnesiniGetRender+Loadile yükleyin.- Verinin çarpışma Mesh verisi içerdiğini doğrulayın (yerel biçimler veya önceki sürümlerde yeniden oluşturulan veriler içermeyebilir).
- Tam alma: tüm blokları tek seferde okumak için
GetMeshes()yöntemini çağırın ve tekrarlı çağrılardan kaçınmak için sonucu kendiniz önbelleğe alın. - İstek üzerine alma: önce
GetMeshBlockInfos()ile blokların dünya sınırlayıcı kutularını alın, kimlikleri kamera mesafesine göre süzün, ardından yalnızca hedef blokları okumak içinGetMeshes(ids)yöntemini kullanın. - Görselleştirirken yerel koordinatlarla hizalamak için GameObject'i
Renderer.Transformaltına bağlayın ve Mesh'iIndexFormat.UInt32ile oluşturun.
Mesh Alma API'leri
Aşağıdaki yöntemlerin tümü Renderer üzerindedir. Bu yöntemler sahne yüklenmesi tamamlandıktan sonra çağrılmalıdır ve verinin çarpışma Mesh verisi içermesi gerekir.
GetMeshBlockInfos
// Return value: List<LCCMeshBlockInfo> → collision Mesh block metadata; null when there is no Mesh or unavailable
public List<LCCMeshBlockInfo> GetMeshBlockInfos()
Tüm çarpışma Mesh bloklarının meta verisini döndürür (kimlik, dünya/yerel sınırlayıcı kutu, köşe noktası sayısı, yüz sayısı). Sıfır G/Ç ve sıfır ayrıştırma gerektirir; yalnızca bellekte hazır bulunan meta veriyi okur.
Kullanım örneği:
var infos = renderer.GetMeshBlockInfos();
foreach (var info in infos)
{
Debug.Log($"{info.id}: verts={info.vertexCount}, faces={info.faceCount}, bbox={info.boundsWorld.size}");
}
Notlar:
- Yalnızca PC / Mac + yerel veri kaynağı; yalnızca ana iş parçacığı.
- Tipik kullanım: önce her bloğun dünya BBox değerini almak, gerekli kimlikleri seçmek ve ardından yalnızca bu blokları okumak için
GetMeshes(ids)yöntemini çağırmak. - Yerel biçimlerde (PLY / SOG / SPZ / splat / ksplat) Mesh bulunmaz ve
nulldöner (bu normaldir ve günlüğe kaydedilmez).
GetMeshes
// Return value: List<LCCMeshBlock> → all collision Mesh geometry data; null when unavailable
public List<LCCMeshBlock> GetMeshes()
Tüm çarpışma Mesh bloklarının geometri verisini (köşe noktaları + üçgen indeksleri, yerel koordinat sisteminde) eşzamanlı olarak döndürür. Bu ağır bir işlemdir (eşzamanlı disk okuma + ayrıştırma + bellek ayırma). Bir kez çağırıp sonucu kendiniz önbelleğe alın; asla her karede çağırmayın.
Kullanım örneği:
var meshes = renderer.GetMeshes();
foreach (var block in meshes)
{
// block.vertices / block.triangles are in the object local coordinate system
}
Notlar:
- Yalnızca PC / Mac + yerel veri kaynağı; yalnızca ana iş parçacığı.
- Büyük sahnelerde, çok miktarda yönetilen belleğin tek seferde ayrılmasını önlemek için bunun yerine
GetMeshBlockInfos()ile kimlikleri seçin veGetMeshes(ids)yöntemini kullanın. - Tek bir bloğun köşe (vertex) sayısı 65535'i aşabilir; kendi Mesh'inizi oluşturmadan önce
mesh.indexFormat = IndexFormat.UInt32ayarını yapmalısınız.
GetMeshes (id ile)
// Return value: List<LCCMeshBlock> → collision Mesh geometry data for the specified ids; null when no hits
public List<LCCMeshBlock> GetMeshes(IEnumerable<string> _ids)
Belirtilen id'lere sahip çarpışma Mesh bloklarının geometri verilerini (yerel koordinat sistemi) eşzamanlı olarak döndürür. Id'ler GetMeshBlockInfos() ile sağlanır.
| Parametre | Tür | Açıklama |
|---|---|---|
_ids | IEnumerable<string> | Hedef blok id koleksiyonu (GetMeshBlockInfos() ile sağlanır) |
Kullanım örneği:
var ids = new List<string> { "block-0", "block-3" };
var meshes = renderer.GetMeshes(ids);
Notlar:
- Bilinmeyen id'ler uyarı verilerek atlanır; yinelenen id'ler tekilleştirilir (diskten tekrar tekrar okunmaz); dönüş sırası, tekilleştirmeden sonraki id geçiş sırasıdır.
nullveya boş girdi verilirse ya da eşleşme bulunmazsa uyarı verilir venulldöndürülür.- Diğer kısıtlar
GetMeshes()ile aynıdır.
LCCMeshBlockInfo Veri Yapısı
public struct LCCMeshBlockInfo {
public string id; // node id, corresponding to LCCMeshBlock.id
public Bounds boundsWorld; // world-space AABB, used to select ids
public Bounds boundsLocal; // local-space AABB
public int vertexCount; // vertex count
public int faceCount; // face count
}
| Alan | Tür | Açıklama |
|---|---|---|
id | string | Düğüm id'si, LCCMeshBlock.id ile eşleşir |
boundsWorld | Bounds | Dünya uzayında AABB, id seçmek için kullanılır |
boundsLocal | Bounds | Yerel uzayda AABB |
vertexCount | int | Köşe sayısı |
faceCount | int | Yüz sayısı |
LCCMeshBlock Veri Yapısı
public struct LCCMeshBlock {
public string id; // node id
public Vector3[] vertices; // vertices, local coordinate system
public int[] triangles; // triangle indices, 3 per triangle
public Bounds boundsLocal; // bounds in the same space as vertices
}
| Alan | Tür | Açıklama |
|---|---|---|
id | string | Düğüm id'si |
vertices | Vector3[] | Köşe dizisi, nesne yerel koordinat sisteminde |
triangles | int[] | Üçgen indeksleri, her üçgen için 3 indeks |
boundsLocal | Bounds | Köşelerle aynı uzayda sınırlar |
Not:
vertices/boundsLocaldeğerlerinin ikisi de nesne yerel koordinat sistemindedir. Bunları Unity'de görselleştirmek için Mesh'i taşıyan GameObject'iRenderer.Transformaltına bağlayın; böylece otomatik olarak hizalanır. Tek bir bloğun köşe sayısı 65535'i aşabilir; kendi Mesh'inizi oluşturmadan öncemesh.indexFormat = IndexFormat.UInt32ayarını yapmalısınız.
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:

