PDA

View Full Version : How to use a color texture to store a depth map for Variance shadow mapping



bwdun123
04-07-2017, 07:31 AM
Hello guys!
I am having trouble implementing Variance Shadow Mapping where the depth map, created during the first pass, is made by storing depth in a two component color texture (GL_RG32F) instead of a single component depth texture (GL_DEPTH_COMPONENT32) as is done in basic Shadow Mapping technique.

When i use said texture in my second pass I get a scene rendered in black ( black (https://i.stack.imgur.com/Qg911.png) ). But if I use a depth texture instead i get a correct result ( notBlack (https://i.stack.imgur.com/GtKIj.png) ).

I'm speculating that this problem is not hard to correct, but i'm not really good at opengl so i spent the last two days banging my head over this with no result. Any help would be much appreciated!

Here is my code from main.cpp and two fragment shaders (one for each pass):



const float color[4] = {1.0f, 0.0f, 0.0f, 0.0f};
const int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
const int WINDOW_WIDTH = 640, WINDOW_HEIGHT = 480;

GLuint mFramebuffer = 0;
GLuint colorTexture = 0;
GLuint depthTexture = 0;

glGenTextures(1, &colorTexture);
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, SHADOW_WIDTH, SHADOW_HEIGHT,
0, GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);

glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_WIDTH,
SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);

glGenFramebuffers(1, &mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthTexture, 0);

if( glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
GL_FRAMEBUFFER_COMPLETE )
std::cerr <<"[CHECK_FB_STATUS]: "<< std::endl;

glBindFramebuffer(GL_FRAMEBUFFER, 0);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

// I use an orthographic projection to create a depth map,
// but a perspective projection for rendering the actual scene

glm::mat4 depthP = glm::ortho<float>(-10,10,-10,10,-10,20);
glm::mat4 P = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);

do{
// First Pass
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glViewport(0,0, SHADOW_WIDTH, SHADOW_HEIGHT);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(firstPassID);

// Drawing MY CUBE
glUniformMatrix4fv(glGetUniformLocation(firstPassI D, "depthMVP"),
1,GL_FALSE, &depthMVP[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 12*3);

// Second Pass

computeMatricesFromInputs(mWindow); //I'm using fabien's
P = getProjectionMatrix(); //functions to move
V = getViewMatrix(); //the camera with wsad and mouse

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER,0);
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(secondPassID);

// Drawing MY CUBE

glUniform3f(glGetUniformLocation(
secondPassID,"pointLights.position"), worldSpace_lightPos.x,
worldSpace_lightPos.y, worldSpace_lightPos.z);
glUniformMatrix4fv(glGetUniformLocation(secondPass ID, "model"), 1,
GL_FALSE, &M[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID, "view"), 1,
GL_FALSE, &V[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID,
"projection"), 1, GL_FALSE, &P[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID,
"depthBiasMVP"), 1, GL_FALSE, &depthBiasMVP[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTexture);
// If i bind depthTexture here instead it works
glUniform1i(glGetUniformLocation(secondPassID, "ShadowMap"), 0);
glDrawArrays(GL_TRIANGLES, 0, 12*3);

// Drawing MY PLANE
glUniform3f(glGetUniformLocation(
secondPassID,"pointLights.position"), worldSpace_lightPos.x,
worldSpace_lightPos.y, worldSpace_lightPos.z);
glUniformMatrix4fv(glGetUniformLocation(secondPass ID, "model"), 1,
GL_FALSE, &M[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID, "view"), 1,
GL_FALSE, &V[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID,
"projection"), 1, GL_FALSE, &P[0][0] );
glUniformMatrix4fv(glGetUniformLocation(secondPass ID,
"depthBiasMVP"), 1, GL_FALSE, &depthBiasMVP[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTexture);
// If i bind depthTexture here instead it works
glUniform1i(glGetUniformLocation(secondPassID, "ShadowMap"), 0);
glDrawArrays(GL_TRIANGLES, 0, 2*3);

glfwSwapBuffers(mWindow);
glfwPollEvents();

}while(glfwGetKey(mWindow, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(mWindow) == 0);

This is my firstPassID's fragment shader:


#version 330 core
in vec4 mvp_pos; // I pass it as depthMVP * vec4(position,1)

void main()
{
float depth = mvp_pos.z / mvp_pos.w ;
depth = depth * 0.5 + 0.5;

float moment1 = depth;
float moment2 = depth * depth;

float dx = dFdx(depth);
float dy = dFdy(depth);

moment2 += 0.25*(dx*dx+dy*dy);

gl_FragColor = vec4( moment1,moment2, 0.0, 0.0 );
}

My secondPassID's fragment shader:


struct pointlight {
vec3 position;

float constant;
float linear;
float quadratic;

vec3 ambient;
vec3 diffuse;
vec3 specular;
};

in vec3 eyeSpace_coordinates;
in vec3 eyeSpace_normals;
in vec4 lightSpace_coordinates;

uniform sampler2D ShadowMap;
uniform pointlight pointLights;

uniform mat4 view;
uniform mat4 projection;

float chebyshevUpperBound( float distance, vec2 myPos)
{
vec2 moments = texture2D(ShadowMap, myPos).rg;

if (distance <= moments.x)
return 1.0f;

float variance = moments.y - ( moments.x*moments.x );
variance = max( variance, 0.00002 );

float d = distance - moments.x;
float p_max = variance / (variance + d*d);
p_max = clamp(p_max, 0, 1);

return p_max;
}

vec3 CalcPointLight(pointlight light, vec3 normal, vec3 fragPos)
{
vec3 eyeSpace_lightPos = ( view * vec4( light.position, 1.0f )).xyz;

vec3 lightDir = normalize(eyeSpace_lightPos - fragPos);

float cosTheta = max(dot(normal, lightDir), 0.0);

vec3 ambient = light.ambient * vec3(1.0f, 0.0f, 0.0f);
vec3 diffuse = light.diffuse * cosTheta * vec3(1.0f, 0.0f, 0.0f);

return (ambient + diffuse);
}

void main()
{
vec4 ls_Pos = lightSpace_coordinates/ lightSpace_coordinates.w;

vec3 eyespace_cameraDir = -eyeSpace_coordinates;
vec3 n = normalize(eyeSpace_normals);

float shadow = chebyshevUpperBound(ls_Pos.z, ls_Pos.xy);
vec3 light = CalcPointLight(pointLights, n, eyeSpace_coordinates);

gl_FragColor = vec4( vec3(shadow), 1.0f ) * vec4(light, 1.0f);
}

bwdun123
04-09-2017, 08:09 AM
Turns out you have to enable writing to first two components in color texture:
glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_FALSE);


God bless!