Ontwikkelgids voor het ophalen van scène-Meshgegevens
Bij het reconstrueren van LCC-gegevens genereert de LCC Unity SDK ook Meshgegevens die voor botsingen worden gebruikt. Naast botsingsdetectie biedt de SDK de mogelijkheid om deze Meshgegevens te extraheren, om te zetten naar Unity Mesh-objecten en te visualiseren, wat handig is voor scenario's zoals exporteren en het bakken van NavMesh.
Hieronder wordt aan de hand van een volledig voorbeeld beschreven hoe je alle Meshgegevens synchroon ophaalt en hoe je Meshgegevens van een opgegeven bereik op aanvraag ophaalt.
Omgevingsopzet
Maak een gloednieuwe scène aan in Unity. Unity maakt standaard Main Camera en Directional Light aan.
Main Camera instellen
Selecteer Main Camera in het Hiërarchie-venster en stel de eigenschappen in het Inspector-venster in zoals hieronder wordt weergegeven.

Stel de eigenschappen van Main Camera in
LCCManager aanmaken
Klik met de rechtermuisknop op een leeg gebied in het Hiërarchie-venster, selecteer Create Empty in het pop-upmenu om een leeg GameObject aan te maken, geef het de naam LCCManager, normaliseer de Transform en voeg het LCCManager-script eraan toe via Component toevoegen.

Maak het LCCManager-GameObject aan en voeg het LCCManager-script toe
LCCRenderer aanmaken
Klik met de rechtermuisknop op een leeg gebied in het Hiërarchie-venster, selecteer Create Empty om een leeg GameObject aan te maken, geef het de naam LCCRenderer en stel de Transform in op Rotation.x = -90 en Scale.x = -1.

Maak LCCRenderer aan en stel de Transform in (Rotation.x = -90, Scale.x = -1)
Opmerking:
De Transform-instellingen van het LCCRenderer-GameObject (Rotation.x = -90, Scale.x = -1) lijnen het uit met het coördinatensysteem van de LCC-gegevens. Zie "Coördinatensysteem van LCC-gegevens" in LCC Unity SDK Introductie voor meer informatie over de uitlijning van het coördinatensysteem.
Gegevensvereisten
De vereiste voor het van kracht worden van het ophalen van Meshgegevens is dat de scène de bijbehorende botsings-Meshgegevens meedraagt (gegenereerd wanneer LCC Studio deze reconstrueert). Bovendien heeft deze mogelijkheid de volgende beperkingen:
- Alleen pc / Mac en alleen lokale gegevensbronnen worden ondersteund (HTTP-gegevensbronnen worden niet ondersteund).
- Kan alleen op de hoofdthread worden aangeroepen.
- Gegevens in native formaat (PLY / SOG / SPZ / splat / ksplat) dragen geen botsings-Meshgegevens mee; het aanroepen van de gerelateerde methoden retourneert
null.
Gegevens die in eerdere versies zijn gereconstrueerd, bevatten mogelijk geen botsingsgegevens; in dat geval retourneert GetMeshes() null.
Alle Meshgegevens synchroon ophalen
Alle Meshgegevens synchroon ophalen betekent dat de geometriegegevens van alle botsings-Mesh-blokken in de scène in één keer worden gelezen, geïmplementeerd via de methode Renderer.GetMeshes().
Maak een nieuw C#-script aan met de naam Meshes.cs met de volgende code:
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] laadvoortgang: {p:P1}"),
() =>
{
Debug.Log($"[Meshes] bestand geladen: {m_FilePath}");
m_isLoaded = true;
m_manager.SetAutoFov(false);
},
e => Debug.LogError($"[Meshes] laadfout van het bestand: {e}")
);
}
public void onGetAllMeshes()
{
if (!m_isLoaded || m_renderer == null)
{
Debug.LogWarning("[Meshes] Gegevens zijn nog niet geladen; kan Meshes niet ophalen.");
return;
}
var meshes = m_renderer.GetMeshes();
if (meshes == null || meshes.Count == 0)
{
Debug.LogWarning("[Meshes] Geen Meshes verkregen (de gegevens bevatten mogelijk geen colliders).");
return;
}
VisualizeMeshes(meshes);
}
private void VisualizeMeshes(List<LCCMeshBlock> meshes)
{
// Ruim het vorige visualisatieresultaat op om ophoping te voorkomen
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 };
// Het aantal hoekpunten van één blok kan 65535 overschrijden, dus er moeten 32-bits indices worden gebruikt, anders wordt de geometrie beschadigd
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] GameObjects aangemaakt en {meshes.Count} Mesh-blokken gevisualiseerd.");
}
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) };
// De winding-volgorde van botsingsmesh-driehoeken is niet gegarandeerd consistent; schakel back-face culling uit voor volledige weergave
mat.SetFloat("_Cull", (float)CullMode.Off);
return mat;
}
}
Opmerking:
GetMeshes()is een synchrone zware bewerking: het leest synchroon van schijf, parseert en wijst geheugen toe. In grote scènes, bijvoorbeeld een dataset van 262 blokken, kan het een grote hoeveelheid schijfgegevens moeten lezen en enkele GB tot tientallen GB aan beheerd geheugen toewijzen. Roep het één keer aan en cache het resultaat zelf; roep het nooit elke frame aan.vertices/boundsLocalbevinden zich in het object-lokale coördinatensysteem, dus door het visualisatie-GameObject onderRenderer.Transformte plaatsen, wordt het automatisch uitgelijnd.- Het aantal hoekpunten van één blok kan 65535 overschrijden (gemeten maximum 390.656); voordat je je eigen
Meshopbouwt, moet jemesh.indexFormat = IndexFormat.UInt32instellen, anders wordt de geometrie beschadigd.- De winding-volgorde van botsingsmesh-driehoeken is niet gegarandeerd consistent; het voorbeeld schakelt back-face culling (
_Cull = Off) uit voor volledige weergave.
Voeg het script toe aan het LCCRenderer-GameObject en sleep in de Inspector het LCCManager-GameObject naar de eigenschap Manager en vul het File Path in.
Maak vervolgens een Button en koppel de methode onGetAllMeshes() aan de gebeurtenis onClick ervan.
Klik na het uitvoeren op de Button om alle botsings-Meshes in de scène te zien.

Visualiseer alle botsings-Meshgegevens nadat je op de knop hebt geklikt
Meshgegevens op aanvraag ophalen
Ophalen op aanvraag betekent dat alleen het opgegeven deel van de Meshgegevens wordt gelezen in plaats van alle Meshgegevens in één keer, om grote I/O- en geheugenoverhead te vermijden. Hieronder wordt het lezen van de Mesh-blokken binnen een bepaald bereik rond de camera als voorbeeld gebruikt.
Gebruik eerst GetMeshBlockInfos() om de metadata van alle blokken op te halen (inclusief begrenzingskaders in wereldruimte), bereken de afstand van het centrum van de rendercamera tot het BBOX-oppervlak van het blok in wereldcoördinaten, filter de blok-ids met een afstand kleiner dan 100 m eruit en gebruik vervolgens de geparameteriseerde GetMeshes(ids) om alleen die blokken te lezen.
Voeg de volgende methoden toe aan Meshes.cs:
public void onRequireMeshes()
{
if (!m_isLoaded || m_renderer == null)
{
Debug.LogWarning("[Meshes] Gegevens zijn nog niet geladen; kan Meshes niet ophalen.");
return;
}
// 1. Zero-I/O-lezing van alle blokmetadata, blokken binnen 100 m filteren op basis van de afstand van camera tot BBOX-oppervlak
var infos = m_renderer.GetMeshBlockInfos();
if (infos == null || infos.Count == 0)
{
Debug.LogWarning("[Meshes] Geen Mesh-info verkregen (de gegevens bevatten mogelijk geen colliders).");
return;
}
Vector3 camPos = m_camera.transform.position;
var ids = new List<string>();
foreach (var info in infos)
{
// Wanneer de camera zich binnen de BBOX bevindt, retourneert ClosestPoint de camera zelf en is de afstand 0, dus wordt deze ook geselecteerd
if (calculateMinDistanceToAABB(info.boundsWorld, camPos) < 100f)
ids.Add(info.id);
}
if (ids.Count == 0)
{
Debug.LogWarning("[Meshes] Geen Mesh-blokken binnen 100 m van de camera.");
return;
}
// 2. Lees alleen de gefilterde blokken op id en visualiseer ze
var meshes = m_renderer.GetMeshes(ids);
if (meshes == null || meshes.Count == 0)
{
Debug.LogWarning("[Meshes] Ophalen van Meshes op id mislukt.");
return;
}
VisualizeMeshes(meshes);
Debug.Log($"[Meshes] {ids.Count} blokken binnen 100 m van de camera geselecteerd, {meshes.Count} gevisualiseerd.");
}
// Bereken de kortste afstand van een punt tot het AABB-oppervlak (retourneert 0 wanneer het punt zich binnen de AABB bevindt)
private static float calculateMinDistanceToAABB(Bounds _aabb, Vector3 _point)
{
Vector3 p = _aabb.ClosestPoint(_point);
return Vector3.Distance(p, _point);
}
Opmerking:
GetMeshBlockInfos()is een zero-I/O-, zero-parsingbewerking die alleen de metadata leest die al in het geheugen staat; je kunt het vrij aanroepen.- Het afstandsfilter gebruikt
boundsWorld(begrenzingskader in wereldruimte) en het cameracentrum neemtCamera.transform.position.- Gebruik
Bounds.ClosestPointom de kortste afstand van een punt tot het AABB-oppervlak te berekenen: wanneer de camera zich binnen de BBOX bevindt, retourneertClosestPointde camera zelf en is de afstand 0, zodat dat blok ook wordt geselecteerd.- De filterstraal
100f(eenheid: meter) in het voorbeeld kan naar behoefte worden aangepast.
Maak een Button en koppel onRequireMeshes() aan de gebeurtenis onClick ervan.
Klik na het uitvoeren op de knop om de Mesh-blokken binnen 100 m van de camera te zien.

Meshgegevens binnen 100 m van de camera op aanvraag ophalen
Belangrijkste stappen
De belangrijkste stappen voor het ophalen en visualiseren van scène-Meshgegevens:
- Voltooi de pre-configuratie zoals
SetPlatformTypeen laad de LCC-scène viaGetRender+Load. - Controleer of de gegevens botsings-Meshgegevens meedragen (native formaten of in eerdere versies gereconstrueerde gegevens mogelijk niet).
- Volledige ophaling: roep
GetMeshes()aan om alle blokken in één keer te lezen en cache het resultaat zelf om herhaalde aanroepen te voorkomen. - Ophaling op aanvraag: gebruik eerst
GetMeshBlockInfos()om de wereldbegrenzingskaders van blokken op te halen, filter ids op camera-afstand en gebruik vervolgensGetMeshes(ids)om alleen de doelblokken te lezen. - Plaats bij het visualiseren het GameObject onder
Renderer.Transformom het uit te lijnen met lokale coördinaten en bouw de Mesh metIndexFormat.UInt32.
Mesh-ophaal-API's
De volgende methoden bevinden zich allemaal op Renderer; ze moeten worden aangeroepen nadat de scène is geladen en de gegevens moeten botsings-Meshgegevens meedragen.
GetMeshBlockInfos
// Retourwaarde: List<LCCMeshBlockInfo> → metadata van botsings-Mesh-blokken; null wanneer er geen Mesh is of niet beschikbaar
public List<LCCMeshBlockInfo> GetMeshBlockInfos()
Retourneert de metadata van alle botsings-Mesh-blokken (id, begrenzingskader in wereld/lokaal, aantal hoekpunten, aantal vlakken). Zero-I/O en zero-parsing; leest alleen de metadata die al in het geheugen staat.
Gebruiksvoorbeeld:
var infos = renderer.GetMeshBlockInfos();
foreach (var info in infos)
{
Debug.Log($"{info.id}: verts={info.vertexCount}, faces={info.faceCount}, bbox={info.boundsWorld.size}");
}
Opmerkingen:
- Alleen pc / Mac + lokale gegevensbron; alleen hoofdthread.
- Typisch gebruik: gebruik het eerst om de wereld-BBox van elk blok op te halen, kies de benodigde ids en roep vervolgens
GetMeshes(ids)aan om alleen die blokken te lezen. - Native formaten (PLY / SOG / SPZ / splat / ksplat) hebben geen Mesh en retourneren
null(wat normaal is en niet wordt gelogd).
GetMeshes
// Retourwaarde: List<LCCMeshBlock> → alle geometriegegevens van botsings-Meshes; null wanneer niet beschikbaar
public List<LCCMeshBlock> GetMeshes()
Retourneert synchroon de geometriegegevens van alle botsings-Mesh-blokken (hoekpunten + driehoeksindices, in het lokale coördinatensysteem). Dit is een zware bewerking (synchrone schijflezing + parsen + allocatie); roep het één keer aan en cache het zelf, nooit elke frame.
Gebruiksvoorbeeld:
var meshes = renderer.GetMeshes();
foreach (var block in meshes)
{
// block.vertices / block.triangles bevinden zich in het object-lokale coördinatensysteem
}
Opmerkingen:
- Alleen pc / Mac + lokale gegevensbron; alleen hoofdthread.
- Gebruik voor grote scènes
GetMeshBlockInfos()om ids te kiezen +GetMeshes(ids)in plaats daarvan, om te voorkomen dat er in één keer een enorme hoeveelheid beheerd geheugen wordt toegewezen. - Het aantal hoekpunten van één blok kan 65535 overschrijden; voordat je je eigen Mesh opbouwt, moet je
mesh.indexFormat = IndexFormat.UInt32instellen.
GetMeshes (op id)
// Retourwaarde: List<LCCMeshBlock> → geometriegegevens van botsings-Meshes voor de opgegeven ids; null wanneer geen treffers
public List<LCCMeshBlock> GetMeshes(IEnumerable<string> _ids)
Retourneert synchroon de geometriegegevens van de botsings-Mesh-blokken met de opgegeven ids (lokaal coördinatensysteem). De ids worden geleverd door GetMeshBlockInfos().
| Parameter | Type | Beschrijving |
|---|---|---|
_ids | IEnumerable<string> | De verzameling doelblok-ids (geleverd door GetMeshBlockInfos()) |
Gebruiksvoorbeeld:
var ids = new List<string> { "block-0", "block-3" };
var meshes = renderer.GetMeshes(ids);
Opmerkingen:
- Onbekende ids worden overgeslagen met een waarschuwing; dubbele ids worden gededupliceerd (niet herhaaldelijk van schijf gelezen); de retourvolgorde is de doorloopvolgorde van de ids (na deduplicatie).
- Het doorgeven van
null, lege invoer of geen treffers retourneertnullmet een waarschuwing. - Andere beperkingen zijn hetzelfde als bij
GetMeshes().
Gegevensstructuur LCCMeshBlockInfo
public struct LCCMeshBlockInfo {
public string id; // knoop-id, overeenkomend met LCCMeshBlock.id
public Bounds boundsWorld; // wereldruimte-AABB, gebruikt om ids te selecteren
public Bounds boundsLocal; // lokale-ruimte-AABB
public int vertexCount; // aantal hoekpunten
public int faceCount; // aantal vlakken
}
| Veld | Type | Beschrijving |
|---|---|---|
id | string | Knoop-id, overeenkomend met LCCMeshBlock.id |
boundsWorld | Bounds | Wereldruimte-AABB, gebruikt om ids te selecteren |
boundsLocal | Bounds | Lokale-ruimte-AABB |
vertexCount | int | Aantal hoekpunten |
faceCount | int | Aantal vlakken |
Gegevensstructuur LCCMeshBlock
public struct LCCMeshBlock {
public string id; // knoop-id
public Vector3[] vertices; // hoekpunten, lokaal coördinatensysteem
public int[] triangles; // driehoeksindices, 3 per driehoek
public Bounds boundsLocal; // begrenzingen in dezelfde ruimte als de hoekpunten
}
| Veld | Type | Beschrijving |
|---|---|---|
id | string | Knoop-id |
vertices | Vector3[] | Hoekpuntarray, object-lokaal coördinatensysteem |
triangles | int[] | Driehoeksindices, 3 per driehoek |
boundsLocal | Bounds | Begrenzingen in dezelfde ruimte als de hoekpunten |
Opmerking:
vertices/boundsLocalbevinden zich beide in het object-lokale coördinatensysteem. Om ze in Unity te visualiseren, plaats je het GameObject dat de Mesh bevat onderRenderer.Transformom automatisch uit te lijnen. Het aantal hoekpunten van één blok kan 65535 overschrijden; voordat je je eigen Mesh opbouwt, moet jemesh.indexFormat = IndexFormat.UInt32instellen.