Eevee: First Shadows implementation

Using Texture Arrays to store shadow maps so less texture slots are used when shading. This means a large amount of shadows can be supported.

Support Projection Shadow Map for sun like in old BI/BGE.

Support Cube Shadow Map for Point/Spot/Area lights. the benefit of using it for spot light is that the spot angle does not change shadow resolution (at the cost of more memory used). The implementation of the cubemap sampling is targeted for 3.3 core. We rely on 2D texture arrays to store cubemaps faces and sample the right one manualy. Significant performance improvement can be done using Cubemap Arrays on supported hardware.

Shadows are only hardware filtered. Prefiltered shadows and settings comming next.
This commit is contained in:
2017-04-10 12:06:17 +02:00
parent 0811d089b4
commit f2f16a2568
16 changed files with 723 additions and 149 deletions

View File

@@ -7,12 +7,12 @@
/* ------- Structures -------- */
struct LightData {
vec4 position_influence; /* w : InfluenceRadius */
vec4 color_spec; /* w : Spec Intensity */
vec4 spotdata_shadow; /* x : spot size, y : spot blend */
vec4 rightvec_sizex; /* xyz: Normalized up vector, w: Lamp Type */
vec4 upvec_sizey; /* xyz: Normalized right vector, w: Lamp Type */
vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Lamp Type */
vec4 position_influence; /* w : InfluenceRadius */
vec4 color_spec; /* w : Spec Intensity */
vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */
vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */
vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */
vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Lamp Type */
};
/* convenience aliases */
@@ -21,14 +21,48 @@ struct LightData {
#define l_position position_influence.xyz
#define l_influence position_influence.w
#define l_sizex rightvec_sizex.w
#define l_radius rightvec_sizex.w
#define l_sizey upvec_sizey.w
#define l_right rightvec_sizex.xyz
#define l_up upvec_sizey.xyz
#define l_forward forwardvec_type.xyz
#define l_type forwardvec_type.w
#define l_spot_size spotdata_shadow.x
#define l_spot_blend spotdata_shadow.y
#define l_spot_size spotdata_radius_shadow.x
#define l_spot_blend spotdata_radius_shadow.y
#define l_radius spotdata_radius_shadow.z
#define l_shadowid spotdata_radius_shadow.w
struct ShadowCubeData {
vec4 near_far_bias;
};
/* convenience aliases */
#define sh_cube_near near_far_bias.x
#define sh_cube_far near_far_bias.y
#define sh_cube_bias near_far_bias.z
struct ShadowMapData {
mat4 shadowmat;
vec4 near_far_bias;
};
/* convenience aliases */
#define sh_map_near near_far_bias.x
#define sh_map_far near_far_bias.y
#define sh_map_bias near_far_bias.z
struct ShadowCascadeData {
mat4 shadowmat[MAX_CASCADE_NUM];
vec4 bias_count;
float near[MAX_CASCADE_NUM];
float far[MAX_CASCADE_NUM];
};
/* convenience aliases */
#define sh_cascade_bias bias_count.x
#define sh_cascade_count bias_count.y
struct AreaData {
vec3 corner[4];
@@ -64,6 +98,26 @@ float hypot(float x, float y) { return sqrt(x*x + y*y); }
float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
float linear_depth(float z, float zf, float zn)
{
if (gl_ProjectionMatrix[3][3] == 0.0) {
return (zn * zf) / (z * (zn - zf) + zf);
}
else {
return (z * 2.0 - 1.0) * zf;
}
}
float buffer_depth(float z, float zf, float zn)
{
if (gl_ProjectionMatrix[3][3] == 0.0) {
return (zf * (zn - z)) / (z * (zn - zf));
}
else {
return (z / (zf * 2.0)) + 0.5;
}
}
float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
{
return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);

View File

@@ -3,10 +3,18 @@ uniform int light_count;
uniform vec3 cameraPos;
uniform vec3 eye;
uniform mat4 ProjectionMatrix;
uniform sampler2DArrayShadow shadowCubes;
uniform sampler2DArrayShadow shadowMaps;
// uniform sampler2DArrayShadow shadowCascades;
layout(std140) uniform light_block {
LightData lights_data[MAX_LIGHT];
LightData lights_data[MAX_LIGHT];
};
layout(std140) uniform shadow_block {
ShadowCubeData shadows_cube_data[MAX_SHADOW_CUBE];
ShadowMapData shadows_map_data[MAX_SHADOW_MAP];
ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
};
in vec3 worldPosition;
@@ -69,6 +77,80 @@ float light_visibility(LightData ld, ShadingData sd)
vis *= step(0.0, -dot(sd.L, ld.l_forward));
}
/* shadowing */
if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) {
/* Shadow Cascade */
}
else if (ld.l_shadowid >= MAX_SHADOW_CUBE) {
/* Shadow Map */
float shid = ld.l_shadowid - MAX_SHADOW_CUBE;
ShadowMapData smd = shadows_map_data[int(shid)];
vec4 shpos = smd.shadowmat * vec4(sd.W, 1.0);
shpos.z -= smd.sh_map_bias * shpos.w;
shpos.xyz /= shpos.w;
if (shpos.w > 0.0 && min(shpos.x, shpos.y) > 0.0 && max(shpos.x, shpos.y) < 1.0) {
vis *= texture(shadowMaps, vec4(shpos.xy, shid, shpos.z));
}
}
else {
/* Shadow Cube */
float shid = ld.l_shadowid;
ShadowCubeData scd = shadows_cube_data[int(shid)];
float face;
vec2 uvs;
vec3 Linv = sd.L;
vec3 Labs = abs(Linv);
vec3 maj_axis;
if (max(Labs.y, Labs.z) < Labs.x) {
if (Linv.x > 0.0) {
face = 1.0;
uvs = vec2(1.0, -1.0) * Linv.zy / -Linv.x;
maj_axis = vec3(1.0, 0.0, 0.0);
}
else {
face = 0.0;
uvs = -Linv.zy / Linv.x;
maj_axis = vec3(-1.0, 0.0, 0.0);
}
}
else if (max(Labs.x, Labs.z) < Labs.y) {
if (Linv.y > 0.0) {
face = 2.0;
uvs = vec2(-1.0, 1.0) * Linv.xz / Linv.y;
maj_axis = vec3(0.0, 1.0, 0.0);
}
else {
face = 3.0;
uvs = -Linv.xz / -Linv.y;
maj_axis = vec3(0.0, -1.0, 0.0);
}
}
else {
if (Linv.z > 0.0) {
face = 5.0;
uvs = Linv.xy / Linv.z;
maj_axis = vec3(0.0, 0.0, 1.0);
}
else {
face = 4.0;
uvs = vec2(-1.0, 1.0) * Linv.xy / -Linv.z;
maj_axis = vec3(0.0, 0.0, -1.0);
}
}
uvs = uvs * 0.5 + 0.5;
/* Depth in lightspace to compare against shadow map */
float w = dot(maj_axis, sd.l_vector);
w -= scd.sh_map_bias * w;
float shdepth = buffer_depth(w, scd.sh_cube_far, scd.sh_cube_near);
vis *= texture(shadowCubes, vec4(uvs, shid * 6.0 + face, shdepth));
}
return vis;
}
@@ -108,8 +190,8 @@ void main()
sd.R = reflect(-sd.V, sd.N);
/* hardcoded test vars */
vec3 albedo = vec3(0.0);
vec3 specular = mix(vec3(1.0), vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0));
vec3 albedo = vec3(0.8);
vec3 specular = mix(vec3(0.03), vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0));
float roughness = 0.1;
sd.spec_dominant_dir = get_specular_dominant_dir(sd.N, sd.R, roughness);

View File

@@ -0,0 +1,3 @@
void main() {
}

View File

@@ -0,0 +1,21 @@
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
uniform mat4 ShadowMatrix;
uniform int Layer;
in vec4 vPos[];
void main() {
gl_Layer = Layer;
gl_Position = ShadowMatrix * vPos[0];
EmitVertex();
gl_Layer = Layer;
gl_Position = ShadowMatrix * vPos[1];
EmitVertex();
gl_Layer = Layer;
gl_Position = ShadowMatrix * vPos[2];
EmitVertex();
EndPrimitive();
}

View File

@@ -0,0 +1,11 @@
uniform mat4 ShadowMatrix;
uniform mat4 ModelMatrix;
in vec3 pos;
out vec4 vPos;
void main() {
vPos = ModelMatrix * vec4(pos, 1.0);
}