Spaces:
Sleeping
Sleeping
| 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; | |
| } | |