Skip to content

Commit

Permalink
added dynamic LOD
Browse files Browse the repository at this point in the history
  • Loading branch information
BarthPaleologue committed Nov 6, 2023
1 parent dd29411 commit 3871009
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
58 changes: 46 additions & 12 deletions src/ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {Engine} from "@babylonjs/core/Engines/engine";
import {Scene} from "@babylonjs/core/scene";
import {FreeCamera} from "@babylonjs/core/Cameras/freeCamera";
import {Vector3} from "@babylonjs/core/Maths/math.vector";
import {MeshBuilder} from "@babylonjs/core/Meshes/meshBuilder";
/*import { Effect } from "@babylonjs/core/Materials/effect";
import { PostProcess } from "@babylonjs/core/PostProcesses/postProcess";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";*/
import {PointLight} from "@babylonjs/core/Lights/pointLight";
import "@babylonjs/core/Materials/standardMaterial";
import {InstancedMesh} from "@babylonjs/core/Meshes/instancedMesh";
import {Texture} from "@babylonjs/core/Materials/Textures/texture";
import "@babylonjs/core/Loading/loadingScreen";

Expand Down Expand Up @@ -36,13 +35,6 @@ camera.attachControl();

const light = new DirectionalLight("light", new Vector3(-5, 5, 10).negateInPlace().normalize(), scene);

const ground = MeshBuilder.CreateGround("ground", {width: 10, height: 10}, scene);
const groundMaterial = new StandardMaterial("groundMaterial", scene);
groundMaterial.specularColor.scaleInPlace(0);
groundMaterial.diffuseColor.copyFromFloats(0.5, 0.5, 0.5);

ground.material = groundMaterial;

const highQualityGrassBlade = makeGrassBlade(scene, 4);
highQualityGrassBlade.isVisible = false;

Expand All @@ -58,15 +50,25 @@ lowQualityGrassBlade.material = material;
const patchSize = 10;
const patchResolution = 50;
const fieldPosition = new Vector3(0, 0, 0);
const fieldRadius = 4;
const fieldRadius = 3;

enum LOD_LEVEL {
HIGH,
LOW
}

const map = new Map<Vector3, [InstancedMesh[], LOD_LEVEL, number]>();

for (let x = -fieldRadius; x < fieldRadius; x++) {
for (let z = -fieldRadius; z < fieldRadius; z++) {
const radiusSquared = x * x + z * z;
if (radiusSquared > fieldRadius * fieldRadius) continue;
const patchPosition = new Vector3(x * patchSize, 0, z * patchSize).addInPlace(fieldPosition);
const grassBlade = radiusSquared < 2 * 2 ? highQualityGrassBlade : lowQualityGrassBlade;
makeInstancePatch(grassBlade, patchPosition, patchSize, patchResolution);
const isHighQuality = Vector3.Distance(patchPosition, camera.position) < patchSize * 2;
const grassBlade = isHighQuality ? highQualityGrassBlade : lowQualityGrassBlade;
const instances = makeInstancePatch(grassBlade, patchPosition, patchSize, patchResolution);

map.set(patchPosition, [instances, isHighQuality ? LOD_LEVEL.HIGH : LOD_LEVEL.LOW, patchSize]);
}
}

Expand All @@ -75,12 +77,44 @@ for (let x = -fieldRadius; x < fieldRadius; x++) {

let clock = 0;

function swap(oldInstance: InstancedMesh, newInstance: InstancedMesh) {
newInstance.position.copyFrom(oldInstance.position);
newInstance.rotation.copyFrom(oldInstance.rotation);
newInstance.scaling.copyFrom(oldInstance.scaling);
oldInstance.dispose();
}

function updateScene() {
const deltaTime = engine.getDeltaTime() / 1000;
clock += deltaTime;

material.setVector3("cameraPosition", camera.position);
material.setFloat("time", clock);

// update grass LOD
for (const patchPosition of map.keys()) {
const distanceToCamera = Vector3.Distance(patchPosition, camera.position);
const patchData = map.get(patchPosition);
if (!patchData) {
throw new Error("Patch data not found");
}
const [instances, quality, patchSize] = patchData;

const isHighQuality = distanceToCamera < patchSize * 2;
if (isHighQuality && quality === LOD_LEVEL.HIGH) continue;
if (!isHighQuality && quality === LOD_LEVEL.LOW) continue;

const newInstances = [];
for (const instance of instances) {
const bladeType = isHighQuality ? highQualityGrassBlade : lowQualityGrassBlade;
const newInstance = bladeType.createInstance(instance.name);
swap(instance, newInstance);
newInstances.push(newInstance);
}

const newQuality = isHighQuality ? LOD_LEVEL.HIGH : LOD_LEVEL.LOW;
map.set(patchPosition, [newInstances, newQuality, patchSize]);
}
}

scene.executeWhenReady(() => {
Expand Down
4 changes: 4 additions & 0 deletions src/ts/instancePatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Vector3} from "@babylonjs/core/Maths/math.vector";
import {Mesh} from "@babylonjs/core/Meshes/mesh";

export function makeInstancePatch(instance: Mesh, patchPosition: Vector3, patchSize: number, patchResolution: number) {
const instances = [];
const cellSize = patchSize / patchResolution;
for(let x = 0; x < patchResolution; x++) {
for(let z = 0; z < patchResolution; z++) {
Expand All @@ -11,6 +12,9 @@ export function makeInstancePatch(instance: Mesh, patchPosition: Vector3, patchS
blade.position.x = patchPosition.x + (x / patchResolution) * patchSize - patchSize / 2 + randomCellPositionX;
blade.position.z = patchPosition.z + (z / patchResolution) * patchSize - patchSize / 2 + randomCellPositionZ;
blade.rotation.y = Math.random() * 2 * Math.PI;
instances.push(blade);
}
}

return instances;
}

0 comments on commit 3871009

Please sign in to comment.