diff --git a/src/app/niko/scene-components/grass.tsx b/src/app/niko/scene-components/grass.tsx index e961bb6..6af1a17 100644 --- a/src/app/niko/scene-components/grass.tsx +++ b/src/app/niko/scene-components/grass.tsx @@ -7,24 +7,24 @@ import grassVert from './shaders/grass.vert'; import grassFrag from './shaders/grass.frag'; interface GrassProps { - x: number; - y: number; - size: number; - count: number; - grassSize: number; - scale: number; - hillScale: number; - hillHeight: number; - detailScale: number; - detailHeight: number; - noise2D: (x: number, y: number) => number; - grassLOD: number; - dryColor: string; - lushColor: string; - grassBlades?: number; - grassSegments?: number; - grassLODStart?: number; - grassLODExponent?: number; + x: number; + y: number; + size: number; + count: number; + grassSize: number; + scale: number; + hillScale: number; + hillHeight: number; + detailScale: number; + detailHeight: number; + noise2D: (x: number, y: number) => number; + grassLOD: number; + dryColor: string; + lushColor: string; + grassBlades?: number; + grassSegments?: number; + grassLODStart?: number; + grassLODExponent?: number; } export default function Grass({ @@ -222,62 +222,61 @@ export default function Grass({ shader.uniforms.uTime = { value: 0 }; shader.vertexShader = ` - uniform float uTime; - varying vec2 vGrassUv; - - float hash(vec2 p) { - return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); - } - - float noise(vec2 p) { - vec2 i = floor(p); - vec2 f = fract(p); - f = f * f * (3.0 - 2.0 * f); - - float a = hash(i); - float b = hash(i + vec2(1.0, 0.0)); - float c = hash(i + vec2(0.0, 1.0)); - float d = hash(i + vec2(1.0, 1.0)); - - return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); - } - - float fbm(vec2 p) { - float value = 0.0; - float amplitude = 0.5; - float frequency = 1.0; - - for(int i = 0; i < 4; i++) { - value += amplitude * noise(p * frequency); - frequency *= 2.0; - amplitude *= 0.5; - } - - return value; - } - - ${shader.vertexShader} - `; + uniform float uTime; + varying vec2 vGrassUv; + varying vec3 vWorldPos; + + float hash(vec2 p) { + return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); + } + + float noise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + f = f * f * (3.0 - 2.0 * f); + float a = hash(i); + float b = hash(i + vec2(1.0, 0.0)); + float c = hash(i + vec2(0.0, 1.0)); + float d = hash(i + vec2(1.0, 1.0)); + return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); + } + + float fbm(vec2 p) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + for(int i = 0; i < 4; i++) { + value += amplitude * noise(p * frequency); + frequency *= 2.0; + amplitude *= 0.5; + } + return value; + } + + ${shader.vertexShader} + `; + shader.vertexShader = shader.vertexShader.replace( '#include ', ` - #include - vGrassUv = uv; - ${grassVert} - ` + #include + ${grassVert} + ` ); shader.fragmentShader = ` - uniform float uTime; - varying vec2 vGrassUv; - ${shader.fragmentShader} - `; + uniform float uTime; + varying vec2 vGrassUv; + varying vec3 vWorldPos; + ${shader.fragmentShader} + `; + shader.fragmentShader = shader.fragmentShader.replace( '#include ', ` - #include - ${grassFrag} - ` + #include + ${grassFrag} + ` ); if (materialRef.current) { diff --git a/src/app/niko/scene-components/shaders/grass.frag b/src/app/niko/scene-components/shaders/grass.frag index 7358f74..7cf7c99 100644 --- a/src/app/niko/scene-components/shaders/grass.frag +++ b/src/app/niko/scene-components/shaders/grass.frag @@ -1,13 +1,17 @@ -float ao = smoothstep(0.0, 0.7, vGrassUv.y); -ao = mix(0.05, 1.0, ao); - -vec3 rootColor = diffuseColor.rgb * 0.4; -vec3 tipColor = diffuseColor.rgb * 1.5; +float ao = smoothstep(0.0, 0.8, vGrassUv.y); +ao = mix(0.15, 1.0, ao); +vec3 rootColor = diffuseColor.rgb * 0.35; +vec3 tipColor = diffuseColor.rgb * 1.3; vec3 grassColor = mix(rootColor, tipColor, vGrassUv.y); -grassColor *= ao; -float translucency = pow(vGrassUv.y, 2.0) * 0.5; -grassColor += diffuseColor.rgb * translucency; +vec3 viewDir = normalize(cameraPosition - vWorldPos); +vec3 lightDir = normalize(vec3(15.0, 25.0, 15.0)); -diffuseColor.rgb = grassColor; +float backLighting = max(0.0, dot(viewDir, -lightDir)); +backLighting = pow(backLighting, 3.0) * smoothstep(0.2, 1.0, vGrassUv.y); + +vec3 sssColor = vec3(0.4, 0.8, 0.3) * diffuseColor.rgb; +grassColor += sssColor * backLighting * 1.5; + +diffuseColor.rgb = grassColor * ao; \ No newline at end of file diff --git a/src/app/niko/scene-components/shaders/grass.vert b/src/app/niko/scene-components/shaders/grass.vert index fab2125..f032e13 100644 --- a/src/app/niko/scene-components/shaders/grass.vert +++ b/src/app/niko/scene-components/shaders/grass.vert @@ -1,3 +1,5 @@ +vGrassUv = uv; + vec4 worldPos = modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0); float gx = worldPos.x; float gz = worldPos.z; @@ -8,7 +10,6 @@ float windSpeed = 1.5; float windTime = uTime * windSpeed; vec2 windSamplePos = (worldPos.xz * 0.05) - (mainWindDir * windTime * 0.2); - float windBase = fbm(windSamplePos * 0.8) * 0.4 + 0.2; float gustNoise = fbm(windSamplePos * 0.4); float gust = pow(gustNoise, 3.0) * 1.8; @@ -35,4 +36,7 @@ transformed.z += curveAmount * curveDir.y * 0.5; float swayAmount = (totalWind + spring) * uv.y * uv.y; transformed.x += swayAmount * windDir.x; transformed.z += swayAmount * windDir.y; -transformed.y -= abs(swayAmount) * 0.2; \ No newline at end of file +transformed.y -= abs(swayAmount) * 0.2; + +objectNormal = vec3(0.0, 1.0, 0.0); +vWorldPos = (modelMatrix * instanceMatrix * vec4(transformed, 1.0)).xyz; \ No newline at end of file