airframe.io / src /game /rendering /TerrainMaterial.ts
LATTICEWORKS's picture
feat: integrate Google Earth 3D Tiles and optimize engine hooks
565f6e7
Raw
History Blame Contribute Delete
1.83 kB
import * as THREE from 'three/webgpu';
import { color, mx_noise_vec3, positionLocal, mix, float, step, Fn, max, abs } from 'three/tsl';
/**
* Creates a TSL node material for the procedural terrain.
* Blends dirt, grass, tilled soil, and wetness based on noise and altitude.
*/
export function createTerrainMaterial() {
const material = new THREE.MeshStandardNodeMaterial({
roughness: 0.8,
metalness: 0.0,
});
// TSL Function for Ridged Multifractal Noise
const ridgedNoise = Fn(([p_input]: any[]) => {
const p = p_input.mul(0.005).toVar();
const sum = float(0.0).toVar();
const amp = float(0.5).toVar();
const freq = float(1.0).toVar();
// 4 octaves of ridged noise
for(let i = 0; i < 4; i++) {
let n = mx_noise_vec3(p.mul(freq)).x;
n = float(1.0).sub(abs(n));
n = n.mul(n);
sum.addAssign(n.mul(amp));
amp.mulAssign(0.5);
freq.mulAssign(2.0);
}
return sum;
});
// Position
const pos = positionLocal;
const worldY = pos.y;
const noiseVal = ridgedNoise(pos);
// Base colors
const dirtColor = color("#5A4D41");
const grassColor = color("#3B5E2B");
const soilColor = color("#3D2817");
const snowColor = color("#F0F4F8");
// Blend grass and dirt/soil using noise
const terrainColor = mix(
mix(dirtColor, soilColor, noiseVal),
grassColor,
step(0.4, noiseVal)
);
// Wandering snow line capping high peaks
const snowThreshold = float(150.0).add(noiseVal.mul(40.0));
const isSnow = step(snowThreshold, worldY);
const finalColor = mix(terrainColor, snowColor, isSnow);
// Wetness mapping in valleys
const wetness = max(0.0, float(1.0).sub(worldY.mul(0.02)));
material.colorNode = finalColor;
material.roughnessNode = mix(float(0.9), float(0.3), wetness);
return material;
}