mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 23:57:28 +01:00
Cast shadows of the cab lamp from the cab in the GL 4.6 renderer
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
uniform sampler2DArrayShadow shadowmap;
|
||||
#endif
|
||||
uniform sampler2D headlightmap;
|
||||
// cube shadow maps of the lamps, see gl::LOCAL_SHADOW_TEX and opengl46_local_shadows
|
||||
layout(binding = LOCAL_SHADOW_TEX) uniform samplerCubeArrayShadow local_shadowmap;
|
||||
|
||||
#include <envmapping.glsl>
|
||||
#include <conversion.glsl>
|
||||
@@ -232,10 +234,58 @@ vec2 calc_headlights(light_s light, vec3 fragnormal, vec3 dpdx, vec3 dpdy)
|
||||
// closest distance (squared) the light of a lamp is computed for: nearer the inverse square would grow without a limit
|
||||
const float LOCAL_LIGHT_MIN_DISTANCE2 = 0.01;
|
||||
|
||||
// one comparison with the cube shadow map at the point of the space of the map, moved towards the lamp by Bias (metres)
|
||||
float local_light_shadow_tap(vec3 position, float layer, float near, float bias)
|
||||
{
|
||||
vec3 axes = abs(position);
|
||||
float major = max(axes.x, max(axes.y, axes.z));
|
||||
return texture(local_shadowmap, vec4(position, layer), near / max(major - bias, near));
|
||||
}
|
||||
|
||||
// share of the light of a lamp with a cube shadow map (headlight_weights.x is its layer) which reaches the fragment, 0..1.
|
||||
// the map holds n / d of the closest surface, d the distance along the axis of the face, n the near plane: the farther, the
|
||||
// smaller (as the depth of the scene, reverse z). the comparison gives 1 where the map holds a value at least as large as
|
||||
// the reference, i.e. a surface at most as far: in shadow
|
||||
float local_light_shadow(light_s light, vec3 fragnormal)
|
||||
{
|
||||
// the space of the map: origin at the lamp, axes of the model the shadows are cast by
|
||||
vec3 position = (light.headlight_projection * vec4(f_pos.xyz, 1.0)).xyz;
|
||||
vec3 normal = normalize(mat3(light.headlight_projection) * fragnormal);
|
||||
float distance = length(position);
|
||||
// a texel of the map is as large as this here. the point is moved along the normal by about a texel, which keeps a surface
|
||||
// from shadowing itself at grazing angles, and the reference is moved towards the lamp by a part of a texel
|
||||
float texel = light.headlight_weights.z * distance;
|
||||
vec3 tolamp = -position / max(distance, 1e-4);
|
||||
float NdotL = clamp(dot(normal, tolamp), 0.0, 1.0);
|
||||
position += normal * (texel * (0.5 + 1.5 * (1.0 - NdotL)));
|
||||
float bias = texel * 1.5;
|
||||
float layer = light.headlight_weights.x;
|
||||
float radius = light.headlight_weights.w;
|
||||
if (radius <= 0.0)
|
||||
return local_light_shadow_tap(position, layer, light.headlight_weights.y, bias);
|
||||
// a disc of samples in the plane of the surface, each compared with its own distance: points of the surface itself, which
|
||||
// samples spread across the direction to the lamp would not be at grazing angles. rotated per pixel to turn the banding into noise
|
||||
vec3 side = normalize(cross(normal, (abs(normal.y) < 0.99) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0)));
|
||||
vec3 up = cross(normal, side);
|
||||
float angle = 6.2831853 * fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));
|
||||
vec2 rotation = vec2(cos(angle), sin(angle));
|
||||
float spread = texel * radius;
|
||||
const vec2 disc[8] = vec2[](vec2(-0.326, -0.406), vec2(-0.840, -0.074), vec2(-0.696, 0.457), vec2(-0.203, 0.621),
|
||||
vec2(0.962, -0.195), vec2(0.473, -0.480), vec2(0.519, 0.767), vec2(0.185, -0.893));
|
||||
int count = (radius > 1.5) ? 8 : 4;
|
||||
float shadow = 0.0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
vec2 offset = vec2(disc[i].x * rotation.x - disc[i].y * rotation.y, disc[i].x * rotation.y + disc[i].y * rotation.x) * spread;
|
||||
shadow += local_light_shadow_tap(position + side * offset.x + up * offset.y, layer, light.headlight_weights.y, bias);
|
||||
}
|
||||
return shadow / float(count);
|
||||
}
|
||||
|
||||
// light of a lamp (point or spot light: the lamps of models and vehicles, the cab lamp) reaching the fragment, x the diffuse
|
||||
// and y the specular part. it falls off with the square of the distance, and smoothly to nothing at the range of the light,
|
||||
// 1 / sqrt(quadratic), past which the culling of the clusters does not take it. a spot light fades from its inner cone to the
|
||||
// outer one
|
||||
// outer one. a lamp with a shadow map is held back by what is between it and the fragment
|
||||
vec2 calc_local_light(light_s light, vec3 fragnormal)
|
||||
{
|
||||
vec3 tolight = light.pos - f_pos.xyz;
|
||||
@@ -245,6 +295,8 @@ vec2 calc_local_light(light_s light, vec3 fragnormal)
|
||||
float atten = edge * edge / max(distance2, LOCAL_LIGHT_MIN_DISTANCE2);
|
||||
if (light.type == LIGHT_SPOT)
|
||||
atten *= smoothstep(light.out_cutoff, light.in_cutoff, dot(-light_dir, normalize(light.dir)));
|
||||
if ((atten > 0.0) && (light.headlight_weights.x >= 0.0) && (dot(fragnormal, light_dir) > 0.0))
|
||||
atten *= 1.0 - local_light_shadow(light, fragnormal);
|
||||
if (atten <= 0.0)
|
||||
return vec2(0.0);
|
||||
vec2 part = calc_light(light_dir, fragnormal);
|
||||
|
||||
47
shaders/shadowcube.geom
Normal file
47
shaders/shadowcube.geom
Normal file
@@ -0,0 +1,47 @@
|
||||
// draws the geometry into the six faces of a cube shadow map at once, one invocation per face. the input is in the space of the
|
||||
// map, with the lamp at the origin. the faces go in the order of the faces of a cube map (+x, -x, +y, -y, +z, -z), each looks the
|
||||
// way glm::lookAt() with the usual up vectors of cube maps sets it, with a 90 degree projection of infinite reach and reversed
|
||||
// depth like the one of the scene: the depth is near / d, d the distance along the axis of the face
|
||||
layout(triangles, invocations = 6) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
|
||||
in vec3 g_pos[];
|
||||
in vec2 g_coord[];
|
||||
out vec2 f_coord;
|
||||
|
||||
// near plane of the map, metres: closer surfaces (the lamp itself) cast no shadows
|
||||
layout(location = 0) uniform float cube_near;
|
||||
// layer of the cube map array the first face of the map is in
|
||||
layout(location = 1) uniform int cube_layer;
|
||||
|
||||
// right, up and forward axes of the faces
|
||||
const vec3 face_right[6] = vec3[](vec3(0.0, 0.0, -1.0), vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));
|
||||
const vec3 face_up[6] = vec3[](vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0));
|
||||
const vec3 face_forward[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
|
||||
|
||||
void main()
|
||||
{
|
||||
int face = gl_InvocationID;
|
||||
vec4 clip[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
clip[i] = vec4(dot(g_pos[i], face_right[face]), dot(g_pos[i], face_up[face]), cube_near, dot(g_pos[i], face_forward[face]));
|
||||
// triangles wholly outside of the face are not sent further
|
||||
if ((clip[0].w < cube_near) && (clip[1].w < cube_near) && (clip[2].w < cube_near))
|
||||
return;
|
||||
if ((clip[0].x > clip[0].w) && (clip[1].x > clip[1].w) && (clip[2].x > clip[2].w))
|
||||
return;
|
||||
if ((clip[0].x < -clip[0].w) && (clip[1].x < -clip[1].w) && (clip[2].x < -clip[2].w))
|
||||
return;
|
||||
if ((clip[0].y > clip[0].w) && (clip[1].y > clip[1].w) && (clip[2].y > clip[2].w))
|
||||
return;
|
||||
if ((clip[0].y < -clip[0].w) && (clip[1].y < -clip[1].w) && (clip[2].y < -clip[2].w))
|
||||
return;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
gl_Layer = cube_layer + face;
|
||||
gl_Position = clip[i];
|
||||
f_coord = g_coord[i];
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
15
shaders/shadowcube.vert
Normal file
15
shaders/shadowcube.vert
Normal file
@@ -0,0 +1,15 @@
|
||||
layout(location = 0) in vec3 v_vert;
|
||||
layout(location = 2) in vec2 v_coord;
|
||||
|
||||
// position in the space of the cube shadow map being drawn (origin at the lamp), see shadowcube.geom
|
||||
out vec3 g_pos;
|
||||
out vec2 g_coord;
|
||||
|
||||
#include <common>
|
||||
|
||||
void main()
|
||||
{
|
||||
g_pos = (effective_modelview() * vec4(v_vert, 1.0f)).xyz;
|
||||
g_coord = v_coord;
|
||||
gl_Position = vec4(g_pos, 1.0f);
|
||||
}
|
||||
Reference in New Issue
Block a user