feat: overhaul grass
This commit is contained in:
@@ -68,10 +68,10 @@ function Scene() {
|
||||
grassDryColor: '#495a17',
|
||||
grassLushColor: '#255825',
|
||||
grassCount: { value: 8000, min: 1000, max: 30000, step: 500 },
|
||||
grassSize: { value: 0.65, min: 0.1, max: 2.0, step: 0.05 },
|
||||
grassSize: { value: 0.85, min: 0.1, max: 2.0, step: 0.05 },
|
||||
grassLOD: { value: 60, min: 10, max: 200, step: 5 },
|
||||
grassBlades: { value: 3, min: 1, max: 4, step: 1 },
|
||||
grassSegments: { value: 3, min: 1, max: 5, step: 1 },
|
||||
grassBlades: { value: 3, min: 1, max: 5, step: 1 },
|
||||
grassSegments: { value: 4, min: 1, max: 5, step: 1 },
|
||||
grassLODStart: { value: 0.15, min: 0.0, max: 0.9, step: 0.05 },
|
||||
grassLODExponent: { value: 1.8, min: 0.5, max: 3.0, step: 0.1 },
|
||||
})
|
||||
|
||||
@@ -170,30 +170,24 @@ export default function Grass({
|
||||
dummy.position.set(localX, localY, localZ);
|
||||
|
||||
dummy.rotation.y = Math.random() * Math.PI * 2;
|
||||
dummy.rotation.x = (Math.random() - 0.5) * 0.15;
|
||||
dummy.rotation.z = (Math.random() - 0.5) * 0.15;
|
||||
|
||||
const baseScale = grassSize + Math.random() * grassSize * 0.5;
|
||||
const heightMult = 0.5 + Math.random() * 1.0;
|
||||
dummy.scale.set(baseScale, baseScale * heightMult, baseScale);
|
||||
|
||||
dummy.updateMatrix();
|
||||
meshRef.current.setMatrixAt(instanceIndex, dummy.matrix);
|
||||
dummy.rotation.x = (Math.random() - 0.5) * 0.2;
|
||||
dummy.rotation.z = (Math.random() - 0.5) * 0.2;
|
||||
|
||||
const noiseVal = noise2D(globalX * 0.02, globalZ * 0.02);
|
||||
|
||||
const t = (noiseVal + 1) / 2;
|
||||
|
||||
const randomInternal = (Math.random() - 0.5) * 0.2;
|
||||
const finalT = Math.max(0, Math.min(1, t + randomInternal));
|
||||
|
||||
color.lerpColors(dryColorObj, lushColorObj, finalT);
|
||||
|
||||
meshRef.current.setColorAt(instanceIndex, color);
|
||||
|
||||
const macroHeightBonus = (noiseVal + 1.0) * 0.2;
|
||||
const grassWidth = grassSize * (0.8 + Math.random() * 0.4);
|
||||
const grassHeight = grassSize * (0.6 + Math.random() * 1.2 + macroHeightBonus);
|
||||
const heightNoise = noise2D(globalX * 0.08, globalZ * 0.08);
|
||||
const macroHeight = (heightNoise + 1.0) * 0.5; // 0..1
|
||||
const microNoise = noise2D(globalX * 0.3, globalZ * 0.3);
|
||||
const microHeight = (microNoise + 1.0) * 0.25; // 0..0.5
|
||||
const perBladeRandom = Math.random() * 0.4;
|
||||
|
||||
const grassWidth = grassSize * (0.7 + Math.random() * 0.5);
|
||||
const grassHeight = grassSize * (0.4 + macroHeight * 0.8 + microHeight + perBladeRandom);
|
||||
|
||||
dummy.scale.set(grassWidth, grassHeight, grassWidth);
|
||||
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
float ao = smoothstep(0.0, 0.8, vGrassUv.y);
|
||||
ao = mix(0.15, 1.0, ao);
|
||||
float ao = smoothstep(0.0, 0.7, vGrassUv.y);
|
||||
ao = mix(0.05, 1.0, pow(ao, 1.6));
|
||||
|
||||
vec3 rootColor = diffuseColor.rgb * 0.35;
|
||||
vec3 tipColor = diffuseColor.rgb * 1.3;
|
||||
vec3 grassColor = mix(rootColor, tipColor, vGrassUv.y);
|
||||
vec3 rootColor = diffuseColor.rgb * 0.15;
|
||||
vec3 midColor = diffuseColor.rgb;
|
||||
vec3 tipColor = diffuseColor.rgb * 1.3 + vec3(0.06, 0.08, 0.0);
|
||||
|
||||
float heightParam = vGrassUv.y;
|
||||
vec3 grassColor;
|
||||
if (heightParam < 0.4) {
|
||||
float t = smoothstep(0.0, 0.4, heightParam);
|
||||
grassColor = mix(rootColor, midColor, t);
|
||||
} else {
|
||||
float t = smoothstep(0.4, 1.0, heightParam);
|
||||
grassColor = mix(midColor, tipColor, t);
|
||||
}
|
||||
|
||||
vec3 viewDir = normalize(cameraPosition - vWorldPos);
|
||||
vec3 lightDir = normalize(vec3(15.0, 25.0, 15.0));
|
||||
|
||||
float backLighting = max(0.0, dot(viewDir, -lightDir));
|
||||
backLighting = pow(backLighting, 3.0) * smoothstep(0.2, 1.0, vGrassUv.y);
|
||||
float VdotL = max(0.0, dot(viewDir, -lightDir));
|
||||
float sss = pow(VdotL, 3.0) * smoothstep(0.2, 0.9, vGrassUv.y);
|
||||
|
||||
vec3 sssColor = vec3(0.4, 0.8, 0.3) * diffuseColor.rgb;
|
||||
grassColor += sssColor * backLighting * 1.5;
|
||||
vec3 sssColor = diffuseColor.rgb * vec3(0.6, 1.0, 0.15) * 1.8;
|
||||
grassColor += sssColor * sss * 2.0;
|
||||
|
||||
float NdotV = 1.0 - max(0.0, dot(normalize(vNormal), viewDir));
|
||||
float rim = pow(NdotV, 3.0) * smoothstep(0.3, 1.0, vGrassUv.y) * 0.15;
|
||||
grassColor += vec3(0.3, 0.5, 0.1) * rim;
|
||||
|
||||
diffuseColor.rgb = grassColor * ao;
|
||||
@@ -21,22 +21,32 @@ float spring = sin(uTime * 2.0 + phase) * 0.06 + sin(uTime * 4.5 + phase * 1.5)
|
||||
float angleNoise = fbm(windSamplePos * 2.0 + uTime * 0.1) - 0.5;
|
||||
vec2 windDir = normalize(mainWindDir + vec2(-mainWindDir.y, mainWindDir.x) * angleNoise * 0.4);
|
||||
|
||||
float taperFactor = pow(uv.y, 4.0);
|
||||
float taper = 1.0 - taperFactor * 0.6;
|
||||
// taper (fade)
|
||||
float taperFactor = uv.y * uv.y * uv.y;
|
||||
float taper = 1.0 - taperFactor * 0.85;
|
||||
transformed.x *= taper;
|
||||
transformed.z *= taper;
|
||||
|
||||
// curve
|
||||
float curveVal = fbm(vec2(gx, gz) * 0.5);
|
||||
float curveStrength = 2.0 + curveVal * 2.0;
|
||||
float curveStrength = 1.5 + curveVal * 2.5;
|
||||
float curveAmount = uv.y * uv.y * curveStrength;
|
||||
vec2 curveDir = normalize(vec2(curveVal, fbm(vec2(gz, gx))) - 0.5);
|
||||
transformed.x += curveAmount * curveDir.x * 0.5;
|
||||
transformed.z += curveAmount * curveDir.y * 0.5;
|
||||
transformed.x += curveAmount * curveDir.x * 0.4;
|
||||
transformed.z += curveAmount * curveDir.y * 0.4;
|
||||
|
||||
// sway
|
||||
float swayAmount = (totalWind + spring) * uv.y * uv.y;
|
||||
transformed.x += swayAmount * windDir.x;
|
||||
transformed.z += swayAmount * windDir.y;
|
||||
transformed.y -= abs(swayAmount) * 0.2;
|
||||
|
||||
objectNormal = vec3(0.0, 1.0, 0.0);
|
||||
// normal comp
|
||||
vec2 totalBend = curveDir * curveAmount * 0.4 + windDir * swayAmount;
|
||||
float bendMag = length(totalBend);
|
||||
vec3 bentNormal = normalize(vec3(-totalBend.x * 0.5, 1.0, -totalBend.y * 0.5));
|
||||
|
||||
// normal mix
|
||||
objectNormal = normalize(mix(vec3(0.0, 1.0, 0.0), bentNormal, uv.y));
|
||||
|
||||
vWorldPos = (modelMatrix * instanceMatrix * vec4(transformed, 1.0)).xyz;
|
||||
Reference in New Issue
Block a user