74 lines
2.4 KiB
GLSL
74 lines
2.4 KiB
GLSL
#version 330 core
|
|
|
|
in vec2 vTexCoord;
|
|
in vec3 vWorldPos;
|
|
|
|
uniform sampler2D texture0;
|
|
|
|
// --- Soft bubble (kept) ---
|
|
uniform vec3 u_playerPos;
|
|
uniform float u_inner;
|
|
uniform float u_outer;
|
|
uniform float u_minShadow;
|
|
|
|
// --- Flashlight cone + distance ---
|
|
uniform vec3 u_spotDir; // normalized camera forward
|
|
uniform float u_spotCos; // cos(half-angle)
|
|
uniform float u_spotSoft; // base penumbra width in cos-space
|
|
uniform float u_lightRange; // bright zone distance (>0)
|
|
uniform float u_lightFade; // fade width beyond range
|
|
|
|
// --- NEW: decouple brightness + widen with distance ---
|
|
uniform float u_intensity; // flashlight peak brightness (independent of range)
|
|
uniform float u_beamSpread; // additional penumbra growth per unit distance (0..~0.5)
|
|
|
|
// Alpha cut (trees, grass)
|
|
uniform float u_alphaCutoff;
|
|
|
|
out vec4 finalColor;
|
|
|
|
// Helpers
|
|
float remap01(float x, float a, float b) {
|
|
return clamp((x - a) / max(b - a, 1e-5), 0.0, 1.0);
|
|
}
|
|
float invsq(float d, float r) {
|
|
float s = d / max(r, 1e-4);
|
|
return 1.0 / (1.0 + s*s);
|
|
}
|
|
|
|
void main() {
|
|
vec4 texel = texture(texture0, vTexCoord);
|
|
if (texel.a < u_alphaCutoff) discard;
|
|
|
|
float dist = length(vWorldPos - u_playerPos);
|
|
|
|
// (A) Soft ambient bubble around the player (unchanged)
|
|
float bubble = 1.0 - remap01(dist, u_inner, u_outer); // 1 near, 0 far
|
|
float ambient = mix(1.0 - clamp(u_minShadow,0.0,1.0), 0.0, 1.0 - bubble);
|
|
|
|
// (B) Flashlight cone with penumbra + distance drop + widening
|
|
vec3 L = normalize(vWorldPos - u_playerPos);
|
|
float cosTheta = dot(normalize(u_spotDir), L);
|
|
|
|
// Widen penumbra with distance so long ranges don't look like a laser
|
|
float distNorm = dist / max(u_lightRange, 1e-4);
|
|
float softWide = clamp(u_spotSoft + u_beamSpread * distNorm, 0.0, 0.8);
|
|
|
|
float innerEdge = u_spotCos;
|
|
float outerEdge = clamp(u_spotCos - softWide, -1.0, 1.0);
|
|
|
|
float spotA = smoothstep(outerEdge, innerEdge, cosTheta);
|
|
spotA *= spotA; // mild hotspot
|
|
|
|
// Distance attenuation: inverse-square * soft fade band
|
|
float band = 1.0 - remap01(dist, u_lightRange, u_lightRange + u_lightFade);
|
|
float lightD = invsq(dist, u_lightRange) * band;
|
|
|
|
// Decoupled brightness
|
|
float flashlight = u_intensity * spotA * lightD;
|
|
|
|
// Compose
|
|
float light = clamp(ambient + flashlight, 0.0, 1.0);
|
|
finalColor = vec4(texel.rgb * light, texel.a);
|
|
}
|