feat/fix: misc shader changes (fix normals, lighting, uv)

This commit is contained in:
2026-06-01 16:56:28 -03:00
parent 569a4f29fb
commit aeee2158ba
3 changed files with 83 additions and 76 deletions
+59 -60
View File
@@ -7,24 +7,24 @@ import grassVert from './shaders/grass.vert';
import grassFrag from './shaders/grass.frag'; import grassFrag from './shaders/grass.frag';
interface GrassProps { interface GrassProps {
x: number; x: number;
y: number; y: number;
size: number; size: number;
count: number; count: number;
grassSize: number; grassSize: number;
scale: number; scale: number;
hillScale: number; hillScale: number;
hillHeight: number; hillHeight: number;
detailScale: number; detailScale: number;
detailHeight: number; detailHeight: number;
noise2D: (x: number, y: number) => number; noise2D: (x: number, y: number) => number;
grassLOD: number; grassLOD: number;
dryColor: string; dryColor: string;
lushColor: string; lushColor: string;
grassBlades?: number; grassBlades?: number;
grassSegments?: number; grassSegments?: number;
grassLODStart?: number; grassLODStart?: number;
grassLODExponent?: number; grassLODExponent?: number;
} }
export default function Grass({ export default function Grass({
@@ -222,62 +222,61 @@ export default function Grass({
shader.uniforms.uTime = { value: 0 }; shader.uniforms.uTime = { value: 0 };
shader.vertexShader = ` shader.vertexShader = `
uniform float uTime; uniform float uTime;
varying vec2 vGrassUv; varying vec2 vGrassUv;
varying vec3 vWorldPos;
float hash(vec2 p) { float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
} }
float noise(vec2 p) { float noise(vec2 p) {
vec2 i = floor(p); vec2 i = floor(p);
vec2 f = fract(p); vec2 f = fract(p);
f = f * f * (3.0 - 2.0 * f); 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 a = hash(i); float fbm(vec2 p) {
float b = hash(i + vec2(1.0, 0.0)); float value = 0.0;
float c = hash(i + vec2(0.0, 1.0)); float amplitude = 0.5;
float d = hash(i + vec2(1.0, 1.0)); float frequency = 1.0;
for(int i = 0; i < 4; i++) {
value += amplitude * noise(p * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return value;
}
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); ${shader.vertexShader}
} `;
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( shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>', '#include <begin_vertex>',
` `
#include <begin_vertex> #include <begin_vertex>
vGrassUv = uv; ${grassVert}
${grassVert} `
`
); );
shader.fragmentShader = ` shader.fragmentShader = `
uniform float uTime; uniform float uTime;
varying vec2 vGrassUv; varying vec2 vGrassUv;
${shader.fragmentShader} varying vec3 vWorldPos;
`; ${shader.fragmentShader}
`;
shader.fragmentShader = shader.fragmentShader.replace( shader.fragmentShader = shader.fragmentShader.replace(
'#include <color_fragment>', '#include <color_fragment>',
` `
#include <color_fragment> #include <color_fragment>
${grassFrag} ${grassFrag}
` `
); );
if (materialRef.current) { if (materialRef.current) {
@@ -1,13 +1,17 @@
float ao = smoothstep(0.0, 0.7, vGrassUv.y); float ao = smoothstep(0.0, 0.8, vGrassUv.y);
ao = mix(0.05, 1.0, ao); ao = mix(0.15, 1.0, ao);
vec3 rootColor = diffuseColor.rgb * 0.4;
vec3 tipColor = diffuseColor.rgb * 1.5;
vec3 rootColor = diffuseColor.rgb * 0.35;
vec3 tipColor = diffuseColor.rgb * 1.3;
vec3 grassColor = mix(rootColor, tipColor, vGrassUv.y); vec3 grassColor = mix(rootColor, tipColor, vGrassUv.y);
grassColor *= ao;
float translucency = pow(vGrassUv.y, 2.0) * 0.5; vec3 viewDir = normalize(cameraPosition - vWorldPos);
grassColor += diffuseColor.rgb * translucency; 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;
@@ -1,3 +1,5 @@
vGrassUv = uv;
vec4 worldPos = modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0); vec4 worldPos = modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0);
float gx = worldPos.x; float gx = worldPos.x;
float gz = worldPos.z; float gz = worldPos.z;
@@ -8,7 +10,6 @@ float windSpeed = 1.5;
float windTime = uTime * windSpeed; float windTime = uTime * windSpeed;
vec2 windSamplePos = (worldPos.xz * 0.05) - (mainWindDir * windTime * 0.2); vec2 windSamplePos = (worldPos.xz * 0.05) - (mainWindDir * windTime * 0.2);
float windBase = fbm(windSamplePos * 0.8) * 0.4 + 0.2; float windBase = fbm(windSamplePos * 0.8) * 0.4 + 0.2;
float gustNoise = fbm(windSamplePos * 0.4); float gustNoise = fbm(windSamplePos * 0.4);
float gust = pow(gustNoise, 3.0) * 1.8; float gust = pow(gustNoise, 3.0) * 1.8;
@@ -36,3 +37,6 @@ float swayAmount = (totalWind + spring) * uv.y * uv.y;
transformed.x += swayAmount * windDir.x; transformed.x += swayAmount * windDir.x;
transformed.z += swayAmount * windDir.y; transformed.z += swayAmount * windDir.y;
transformed.y -= abs(swayAmount) * 0.2; transformed.y -= abs(swayAmount) * 0.2;
objectNormal = vec3(0.0, 1.0, 0.0);
vWorldPos = (modelMatrix * instanceMatrix * vec4(transformed, 1.0)).xyz;