Refactor terrain rendering structure to use grouped meshes for LOD management

This commit is contained in:
2026-04-29 23:02:23 +02:00
parent 1717c38c47
commit 64f12c7607

View File

@@ -731,10 +731,7 @@ export class RuntimeHost {
string, string,
Mesh<BufferGeometry, Material[]> Mesh<BufferGeometry, Material[]>
>(); >();
private readonly terrainMeshes = new Map< private readonly terrainMeshes = new Map<string, RuntimeTerrainRenderObjects>();
string,
Mesh<BufferGeometry, Material>
>();
private volumeTime = 0; private volumeTime = 0;
private readonly volumeAnimatedUniforms: Array<{ value: number }> = []; private readonly volumeAnimatedUniforms: Array<{ value: number }> = [];
private readonly runtimeWaterContactUniforms: RuntimeWaterContactUniformBinding[] = private readonly runtimeWaterContactUniforms: RuntimeWaterContactUniformBinding[] =
@@ -3118,8 +3115,11 @@ export class RuntimeHost {
applyAdvancedRenderingRenderableShadowFlags(mesh, shadowsEnabled); applyAdvancedRenderingRenderableShadowFlags(mesh, shadowsEnabled);
} }
for (const mesh of this.terrainMeshes.values()) { for (const renderObjects of this.terrainMeshes.values()) {
applyAdvancedRenderingRenderableShadowFlags(mesh, shadowsEnabled); applyAdvancedRenderingRenderableShadowFlags(
renderObjects.group,
shadowsEnabled
);
} }
for (const renderGroup of this.modelRenderObjects.values()) { for (const renderGroup of this.modelRenderObjects.values()) {
@@ -4049,30 +4049,52 @@ export class RuntimeHost {
this.clearTerrainMeshes(); this.clearTerrainMeshes();
for (const terrain of terrains) { for (const terrain of terrains) {
const geometry = buildTerrainDerivedMeshData({ const terrainForLod = {
...terrain, ...terrain,
kind: "terrain", kind: "terrain" as const,
enabled: true enabled: true
}).geometry; };
const mesh = new Mesh( const lodMeshData = buildTerrainLodMeshData(terrainForLod);
geometry, const material = this.createRuntimeTerrainMaterial(terrain);
this.createRuntimeTerrainMaterial(terrain) const group = new Group();
); const chunks: RuntimeTerrainRenderChunkObjects[] = [];
mesh.position.set( group.position.set(terrain.position.x, terrain.position.y, terrain.position.z);
terrain.position.x, group.visible = terrain.visible;
terrain.position.y,
terrain.position.z for (const chunk of lodMeshData.chunks) {
); const levels = chunk.levels.map((level) => {
mesh.visible = terrain.visible; const mesh = new Mesh(level.geometry, material);
mesh.castShadow = false; mesh.castShadow = false;
mesh.receiveShadow = true; mesh.receiveShadow = true;
applyRendererRenderCategory(mesh, "ao-world"); mesh.visible = level.level === 0;
this.terrainGroup.add(mesh); applyRendererRenderCategory(mesh, "ao-world");
this.terrainMeshes.set(terrain.id, mesh); group.add(mesh);
return mesh;
});
chunks.push({
levels,
activeLevelIndex: 0,
worldCenter: new Vector3(
terrain.position.x + chunk.localCenter.x,
terrain.position.y + chunk.localCenter.y,
terrain.position.z + chunk.localCenter.z
),
diagonal: chunk.diagonal
});
}
this.terrainGroup.add(group);
this.terrainMeshes.set(terrain.id, {
group,
chunks,
material
});
} }
this.applyShadowState(); this.applyShadowState();
this.updateTerrainLodVisibility();
} }
private createRuntimeTerrainMaterial(terrain: RuntimeTerrain): Material { private createRuntimeTerrainMaterial(terrain: RuntimeTerrain): Material {