17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-04 04:12:05 +01:00

Use clustered light lists in forward shading

This commit is contained in:
2026-10-15 16:16:53 +02:00
parent 6aa6e505e8
commit 9f2ae071a6
9 changed files with 117 additions and 51 deletions

View File

@@ -194,7 +194,10 @@ vec2 calc_dir_light(light_s light, vec3 fragnormal)
return calc_light(light_dir, fragnormal);
}
vec2 calc_headlights(light_s light, vec3 fragnormal)
// dpdx and dpdy are the change of the view space position of the fragment from a pixel to the next one. the beam texture is
// sampled with gradients worked out from them instead of the ones of the hardware: those are undefined where the fragments of
// a quad do not go through the same lights, which is what happens at the edges of the clusters
vec2 calc_headlights(light_s light, vec3 fragnormal, vec3 dpdx, vec3 dpdy)
{
vec4 headlightpos = light.headlight_projection * f_pos;
vec3 coords = headlightpos.xyz / headlightpos.w;
@@ -203,6 +206,10 @@ vec2 calc_headlights(light_s light, vec3 fragnormal)
return vec2(0.0);
if (coords.z < 0.0)
return vec2(0.0);
// the beam is what the projection takes in. beyond its sides the texture would be clamped to its edge, and near the projector
// (where a pixel spans many texels) its coarsest levels spill the average of the whole beam over the surroundings
if (coords.x < 0.0 || coords.x > 1.0 || coords.y < 0.0 || coords.y > 1.0)
return vec2(0.0);
vec3 light_dir = normalize(light.pos - f_pos.xyz);
// Tighter wrap (was +0.25): faces angled away from the headlight cone
@@ -212,11 +219,58 @@ vec2 calc_headlights(light_s light, vec3 fragnormal)
float distance = length(light.pos - f_pos.xyz);
float atten = 1.0f / (1.0f + light.linear * distance + light.quadratic * (distance * distance));
atten *= mix(1.0, 0.0, clamp((coords.z - 0.998) * 500.0, 0.0, 1.0));
vec3 lights = textureProj(headlightmap, headlightpos).rgb * light.headlight_weights.rgb;
vec2 beamcoords = headlightpos.xy / headlightpos.w;
vec4 dheadlightposdx = light.headlight_projection * vec4(dpdx, 0.0);
vec4 dheadlightposdy = light.headlight_projection * vec4(dpdy, 0.0);
vec2 dbeamdx = (dheadlightposdx.xy - beamcoords * dheadlightposdx.w) / headlightpos.w;
vec2 dbeamdy = (dheadlightposdy.xy - beamcoords * dheadlightposdy.w) / headlightpos.w;
vec3 lights = textureGrad(headlightmap, beamcoords, dbeamdx, dbeamdy).rgb * light.headlight_weights.rgb;
float lightintensity = max(max(lights.r, lights.g), lights.b);
return part * atten * lightintensity;
}
// index of the light cluster the fragment is in, see gl/cluster_grid.h: its screen tile and slice of depth. the depth is the clip
// space w, which is 1 / gl_FragCoord.w. a tile is kept in the grid, as the far edge of the render target and rounding
// right below it give one past the last
uint fragment_cluster()
{
ivec2 tile = ivec2(gl_FragCoord.xy * (vec2(CLUSTER_GRID_X, CLUSTER_GRID_Y) / cluster_viewport_size));
tile = clamp(tile, ivec2(0), ivec2(CLUSTER_GRID_X - 1, CLUSTER_GRID_Y - 1));
int slice = clamp(int(floor(cluster_slice_bias - log(gl_FragCoord.w) * cluster_slice_scale)), 0, CLUSTER_GRID_Z - 1);
return uint(tile.x + CLUSTER_GRID_X * (tile.y + CLUSTER_GRID_Y * slice));
}
// adds the light of the headlights which reach the fragment to its colour. these are the ones in the list of its cluster
// when the lights are clustered (the sun is not on the list, the callers take care of it), and the first lights_count - 1 of
// lights[] otherwise
vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
{
// worked out before the loops, which the fragments of a quad do not leave together
vec3 dpdx = dFdx(f_pos.xyz);
vec3 dpdy = dFdy(f_pos.xyz);
if (lights_clustered != 0U)
{
cluster_range_s range = cluster_ranges[fragment_cluster()];
for (uint i = 0U; i < range.count; i++)
{
light_s light = lights[cluster_light_indices[range.offset + i]];
vec2 part = calc_headlights(light, fragnormal, dpdx, dpdy);
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
}
}
else
{
for (uint i = 1U; i < lights_count; i++)
{
light_s light = lights[i];
vec2 part = calc_headlights(light, fragnormal, dpdx, dpdy);
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
}
}
return fragcolor;
}
// -----------------------------------------------------------------------
// Split-sum environment BRDF (Karis / UE4 analytic approximation).
//
@@ -312,12 +366,7 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
// direct sun read as too hot/burnt; raise it for more punch.
fragcolor += lights[0].color * SUN_DIFFUSE_SCALE * (1.0 - shadow1) * diffuseamount;
for (uint i = 1U; i < lights_count; i++)
{
light_s light = lights[i];
vec2 part = calc_headlights(light, fragnormal);
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
}
fragcolor = add_headlights(fragcolor, fragnormal);
float specularamount = sunlight.y * param[1].y * specularity * lights[0].intensity
* clamp(1.0 - shadowtone, 0.0, 1.0);

View File

@@ -66,22 +66,7 @@ vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, fl
float specularamount = (sunlight.y * param[1].y * specularity) * lights[0].intensity;
glossiness = abs(param[1].w);
for (uint i = 1U; i < lights_count; i++)
{
light_s light = lights[i];
vec2 part = vec2(0.0);
// if (light.type == LIGHT_SPOT)
// part = calc_spot_light(light, fragnormal);
// else if (light.type == LIGHT_POINT)
// part = calc_point_light(light, fragnormal);
// else if (light.type == LIGHT_DIR)
// part = calc_dir_light(light, fragnormal);
// else if (light.type == LIGHT_HEADLIGHTS)
part = calc_headlights(light, fragnormal);
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
}
fragcolor = add_headlights(fragcolor, fragnormal);
if (shadowtone < 1.0)
{

View File

@@ -76,12 +76,7 @@ vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, fl
float specularamount = sunlight.y * param[1].y * specularity * lights[0].intensity;
for (uint i = 1U; i < lights_count; i++)
{
light_s light = lights[i];
vec2 part = calc_headlights(light, fragnormal);
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
}
fragcolor = add_headlights(fragcolor, fragnormal);
if (shadowtone < 1.0)
{