Add basis for variance shadow mapping

This commit is contained in:
karl 2021-05-21 22:38:40 +02:00
parent 88611815e1
commit 3dcfc89b52
4 changed files with 39 additions and 27 deletions

View File

@ -60,9 +60,6 @@ vec2 get_parallax_offset_uv(vec2 uv, vec3 view_direction) {
}
float get_shadow(vec4 fragPosLightSpace, vec3 normal) {
// The bias varies depending on the angle to the light (the steeper the angle, the bigger the bias needs to be)
mediump float bias = max(0.005 * (1.0 - dot(normal, fs_in.TangentLightDir)), 0.0005);
// perform perspective divide
mediump vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
@ -71,14 +68,25 @@ float get_shadow(vec4 fragPosLightSpace, vec3 normal) {
// If we're outside of [0.0, 1.0] in the coordinates, return 0
if (projCoords.x < 0.0 || projCoords.y < 0.0 || projCoords.x > 1.0 || projCoords.y > 1.0) return 0.0;
// Variance Shadow Map Calculation
vec2 moments = texture(shadowMap, projCoords.xy).rg;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
mediump float closestDepth = texture(shadowMap, projCoords.xy).r;
// get depth of current fragment from light's perspective
mediump float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
mediump float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
float p = step(projCoords.z, moments.x);
// We divide by this later, so make sure it's not exactly 0
// It seems like it should always be 0.0, but due to interpolation it's not -- it increases with the deviation!
float variance = max(moments.y - moments.x * moments.x, 0.00002);
return shadow;
float d = projCoords.z - moments.x * 1.0; // bias should be "compare", what is that?
float p_max = variance / (variance + d * d);
// If this pixel is exactly in the light, p is 1, so make sure we return that in that case
// min() to make sure that it doesn't get greater than 1.0
return 1.0 - min(max(p, p_max), 1.0);
}
void main() {

View File

@ -2,6 +2,6 @@
void main()
{
// This happens implicitly anyways
// gl_FragDepth = gl_FragCoord.z;
// The mean and the mean squared, which we need to calculate the variance
gl_FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z * gl_FragCoord.z, 0.0, 0.0);
}

View File

@ -17,16 +17,16 @@ class DirectionalLight {
// Create depth texture
glGenTextures(1, &depth_map);
glBindTexture(GL_TEXTURE_2D, depth_map);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// R and G with 32 bit floats: stores mean and variance
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depth_map, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -43,8 +43,8 @@ class DirectionalLight {
glBindTexture(GL_TEXTURE_2D, depth_map);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
@ -96,8 +96,8 @@ class DirectionalLight {
unsigned int depth_map;
unsigned int depth_map_fbo;
const unsigned int SHADOW_WIDTH = 4096;
const unsigned int SHADOW_HEIGHT = 4096;
const unsigned int SHADOW_WIDTH = 2048;
const unsigned int SHADOW_HEIGHT = 2048;
Gedeng::Shader shadow_shader;
};

View File

@ -37,9 +37,9 @@ void renderQuad() {
glBindVertexArray(0);
}
class ShadowApp : public Gedeng::Application {
class mesh3 : public Gedeng::Application {
public:
ShadowApp(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
mesh3(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
Gedeng::String window_name)
: Application(ms_per_update, window_size_x, window_size_y, window_name), particle_interval(0.2),
number_of_steps(10.0), number_of_refinement_steps(10.0), bump_depth(0.1),
@ -53,7 +53,9 @@ class ShadowApp : public Gedeng::Application {
particle_tex2("Resources/Textures/Particles/magic.png", Gedeng::Texture::Settings()),
particle_tex3("Resources/Textures/Particles/smoke.png", Gedeng::Texture::Settings()),
quad_mesh(Gedeng::QuadMesh(10.0)), light(glm::vec3(0.57735, -0.57735, 0.57735)),
monkey_mesh("Resources/Meshes/Monkey.obj", Gedeng::ObjMesh::Settings()) {
mesh1("Resources/Meshes/Monkey.obj", Gedeng::ObjMesh::Settings()),
mesh2("Resources/Meshes/Monkey.obj", Gedeng::ObjMesh::Settings()),
mesh3("Resources/Meshes/Monkey.obj", Gedeng::ObjMesh::Settings()) {
particles.set_position(glm::vec3(0.0f, 0.0f, -10.0f));
particles.set_velocity(glm::vec3(-2, 4, -2), glm::vec3(2, 6, 2));
particles.set_gravity(glm::vec3(0, -4, 0));
@ -67,10 +69,10 @@ class ShadowApp : public Gedeng::Application {
camera.translate(glm::vec3(0.0, 2.0, 1.0));
// camera.rotate(30, glm::vec3(1.0, 0.0, 0.0));
monkey_mesh.translate(glm::vec3(2.0, 3.0, -2.0));
mesh1.translate(glm::vec3(2.0, 3.0, -2.0));
}
~ShadowApp() = default;
~mesh3() = default;
void fixed_update(double delta) override {
camera.update(delta);
@ -87,7 +89,7 @@ class ShadowApp : public Gedeng::Application {
void dynamic_update(double delta) override {
// Shadows
light.clear_shadows();
light.render_shadow(monkey_mesh);
light.render_shadow(mesh1);
light.render_shadow(quad_mesh);
glViewport(0, 0, 1920, 1080);
@ -124,7 +126,7 @@ class ShadowApp : public Gedeng::Application {
// Props
render_shader.use();
monkey_mesh.render(render_shader);
mesh1.render(render_shader);
/* // Render the light's depth map to a quad for debugging
debug_shader.use();
@ -159,10 +161,12 @@ class ShadowApp : public Gedeng::Application {
Gedeng::ParticleSystem particles;
Gedeng::DirectionalLight light;
Gedeng::ObjMesh monkey_mesh;
Gedeng::ObjMesh mesh1;
Gedeng::ObjMesh mesh2;
Gedeng::ObjMesh mesh3;
};
Gedeng::Application *Gedeng::create_application() {
GG_CLIENT_INFO("Creating Application");
return new ShadowApp(20, 1920, 1080, String("Parallax Demo"));
return new mesh3(20, 1920, 1080, String("Parallax Demo"));
}