Add basis for variance shadow mapping
This commit is contained in:
parent
88611815e1
commit
3dcfc89b52
@ -60,9 +60,6 @@ vec2 get_parallax_offset_uv(vec2 uv, vec3 view_direction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float get_shadow(vec4 fragPosLightSpace, vec3 normal) {
|
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
|
// perform perspective divide
|
||||||
mediump vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
mediump vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
// transform to [0,1] range
|
// 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 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;
|
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)
|
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
|
||||||
mediump float closestDepth = texture(shadowMap, projCoords.xy).r;
|
mediump float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||||
// get depth of current fragment from light's perspective
|
// get depth of current fragment from light's perspective
|
||||||
mediump float currentDepth = projCoords.z;
|
mediump float currentDepth = projCoords.z;
|
||||||
// check whether current frag pos is in shadow
|
// 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() {
|
void main() {
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// This happens implicitly anyways
|
// The mean and the mean squared, which we need to calculate the variance
|
||||||
// gl_FragDepth = gl_FragCoord.z;
|
gl_FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z * gl_FragCoord.z, 0.0, 0.0);
|
||||||
}
|
}
|
@ -17,16 +17,16 @@ class DirectionalLight {
|
|||||||
// Create depth texture
|
// Create depth texture
|
||||||
glGenTextures(1, &depth_map);
|
glGenTextures(1, &depth_map);
|
||||||
glBindTexture(GL_TEXTURE_2D, 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,
|
// R and G with 32 bit floats: stores mean and variance
|
||||||
NULL);
|
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_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
|
||||||
// Attach depth texture as FBO's depth buffer
|
// Attach depth texture as FBO's depth buffer
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo);
|
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);
|
glDrawBuffer(GL_NONE);
|
||||||
glReadBuffer(GL_NONE);
|
glReadBuffer(GL_NONE);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
@ -43,8 +43,8 @@ class DirectionalLight {
|
|||||||
glBindTexture(GL_TEXTURE_2D, 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,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
|
||||||
NULL);
|
NULL);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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;
|
||||||
unsigned int depth_map_fbo;
|
unsigned int depth_map_fbo;
|
||||||
|
|
||||||
const unsigned int SHADOW_WIDTH = 4096;
|
const unsigned int SHADOW_WIDTH = 2048;
|
||||||
const unsigned int SHADOW_HEIGHT = 4096;
|
const unsigned int SHADOW_HEIGHT = 2048;
|
||||||
|
|
||||||
Gedeng::Shader shadow_shader;
|
Gedeng::Shader shadow_shader;
|
||||||
};
|
};
|
||||||
|
@ -37,9 +37,9 @@ void renderQuad() {
|
|||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShadowApp : public Gedeng::Application {
|
class mesh3 : public Gedeng::Application {
|
||||||
public:
|
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)
|
Gedeng::String window_name)
|
||||||
: Application(ms_per_update, window_size_x, window_size_y, window_name), particle_interval(0.2),
|
: 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),
|
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_tex2("Resources/Textures/Particles/magic.png", Gedeng::Texture::Settings()),
|
||||||
particle_tex3("Resources/Textures/Particles/smoke.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)),
|
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_position(glm::vec3(0.0f, 0.0f, -10.0f));
|
||||||
particles.set_velocity(glm::vec3(-2, 4, -2), glm::vec3(2, 6, 2));
|
particles.set_velocity(glm::vec3(-2, 4, -2), glm::vec3(2, 6, 2));
|
||||||
particles.set_gravity(glm::vec3(0, -4, 0));
|
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.translate(glm::vec3(0.0, 2.0, 1.0));
|
||||||
// camera.rotate(30, glm::vec3(1.0, 0.0, 0.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 {
|
void fixed_update(double delta) override {
|
||||||
camera.update(delta);
|
camera.update(delta);
|
||||||
@ -87,7 +89,7 @@ class ShadowApp : public Gedeng::Application {
|
|||||||
void dynamic_update(double delta) override {
|
void dynamic_update(double delta) override {
|
||||||
// Shadows
|
// Shadows
|
||||||
light.clear_shadows();
|
light.clear_shadows();
|
||||||
light.render_shadow(monkey_mesh);
|
light.render_shadow(mesh1);
|
||||||
light.render_shadow(quad_mesh);
|
light.render_shadow(quad_mesh);
|
||||||
|
|
||||||
glViewport(0, 0, 1920, 1080);
|
glViewport(0, 0, 1920, 1080);
|
||||||
@ -124,7 +126,7 @@ class ShadowApp : public Gedeng::Application {
|
|||||||
|
|
||||||
// Props
|
// Props
|
||||||
render_shader.use();
|
render_shader.use();
|
||||||
monkey_mesh.render(render_shader);
|
mesh1.render(render_shader);
|
||||||
|
|
||||||
/* // Render the light's depth map to a quad for debugging
|
/* // Render the light's depth map to a quad for debugging
|
||||||
debug_shader.use();
|
debug_shader.use();
|
||||||
@ -159,10 +161,12 @@ class ShadowApp : public Gedeng::Application {
|
|||||||
Gedeng::ParticleSystem particles;
|
Gedeng::ParticleSystem particles;
|
||||||
|
|
||||||
Gedeng::DirectionalLight light;
|
Gedeng::DirectionalLight light;
|
||||||
Gedeng::ObjMesh monkey_mesh;
|
Gedeng::ObjMesh mesh1;
|
||||||
|
Gedeng::ObjMesh mesh2;
|
||||||
|
Gedeng::ObjMesh mesh3;
|
||||||
};
|
};
|
||||||
|
|
||||||
Gedeng::Application *Gedeng::create_application() {
|
Gedeng::Application *Gedeng::create_application() {
|
||||||
GG_CLIENT_INFO("Creating Application");
|
GG_CLIENT_INFO("Creating Application");
|
||||||
return new ShadowApp(20, 1920, 1080, String("Parallax Demo"));
|
return new mesh3(20, 1920, 1080, String("Parallax Demo"));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user