Sign in to follow this  

How to read the float values of a depth component in the vertex shader?

This topic is 1116 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everybody,

 

I'm trying to use the depth component of a frame buffer as a texture in my vertex shader. However, when I try to use these float values I get the wrong results, even though the texture I see in the debugger has the correct values.

 

The scene looks as follows:

 

lB5P73G.png

First of all, here I create the framebuffer and depth component:

	// Initialise the texture to be used for shadow mapping.
	glGenTextures(1, &texture_id_);
	glBindTexture(GL_TEXTURE_2D, texture_id_);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, depth_texture_size_, depth_texture_size_, 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);
	// Set up depth comparison mode.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
	// Set up wrapping mode.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	// Set the texture id for the depth texture.
	glActiveTexture(GL_TEXTURE0 + light_->getDepthTextureId());
	glBindTexture(GL_TEXTURE_2D, texture_id_);

	// Create FBO to render depth into.
	glGenFramebuffers(1, &fbo_id_);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
	// Attach the depth texture to it.
	glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_id_, 0);
	// Disable colour rendering.
	glDrawBuffer(GL_NONE);
	glReadBuffer(GL_NONE);

	// Unbind.
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glActiveTexture(GL_TEXTURE0 + 30);

Here is how I render using this framebuffer:

void ShadowRenderer::render(const FrustumCaster& cam)
{
	active_entities_.clear();

	// Gather all the leaf nodes.
	//scene_manager_->visitLeafs(*this);
	unsigned int pre_rendered_objects_ = 0;

	glCullFace(cull_mode_);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
	glViewport(0, 0, depth_texture_size_, depth_texture_size_);

	glClearDepth(1.0f);
	glClear(GL_DEPTH_BUFFER_BIT);
	
	glm::vec3 camera_location = cam.getLocation();
	glm::mat4 view_matrix = cam.getViewMatrix();
	glm::mat4 perspective_matrix = cam.getPerspectiveMatrix();

	CreateAnimatedShadowMapShader& animated_shader = CreateAnimatedShadowMapShader::getShader();
	ShadowShader& shader = ShadowShader::getShader();
	frustum_->setFrustum(perspective_matrix * view_matrix);
	
	// New rendering method.
	Region* region = scene_manager_->getRoot().findRegion(cam.getLocation());
	if (region != NULL)
	{
		std::stringstream ss;
		std::vector<const Portal*> processed_portals;
		region->preRender(*frustum_, cam.getLocation(), *this, false, pre_rendered_objects_, 0, processed_portals, ss);
		for (std::vector<SceneNode*>::const_iterator ci = scene_manager_->getPlayers().begin(); ci != scene_manager_->getPlayers().end(); ++ci)
		{
			(*ci)->preRender(*frustum_, cam.getLocation(), *this, false, pre_rendered_objects_);
		}
	}
	// If we cannot find a region we fall back on the true and tested... Although this
	// is more a debuf feature and should be removed in future versions of this rendering
	// engine.
	else
	{
		SceneNode& root = scene_manager_->getRoot();
		root.preRender(*frustum_, cam.getLocation(), *this, false, pre_rendered_objects_);
	}

	for (std::vector<const RenderableSceneLeaf*>::const_iterator ci = active_entities_.begin(); ci != active_entities_.end(); ++ci)
	{
		const RenderableSceneLeaf* leaf = *ci;

		if (leaf->getShadowType() == ShadowRenderer::NO_SHADOW || !leaf->isInFrustum(*frustum_))
		{
			continue;
		}

		if (leaf->isDoubleSided())
		{
			glDisable(GL_CULL_FACE);
		}
		else
		{
			glEnable(GL_CULL_FACE);
		}

		switch (leaf->getShadowType())
		{
		case ShadowRenderer::ANIMATED_SHADOW:
			leaf->draw(view_matrix, perspective_matrix, active_lights_, &animated_shader);
			break;
		case ShadowRenderer::STATIC_SHADOW:
			leaf->draw(view_matrix, perspective_matrix, active_lights_, &shader);
			break;
		}
	}

	// Unbind.
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glBindTexture(GL_TEXTURE_2D, 0);

	// Reset viewport.
	int orgWidth, orgHeight;
	glfwGetWindowSize(&orgWidth, &orgHeight);
	glViewport(0, 0, orgWidth, orgHeight);
}

This all works fine. When I read out the values in the depth attachment:

std::vector<float> m_depth_;	
m_depth_.resize(light.getShadowMapDimension() * light.getShadowMapDimension());
glBindFramebuffer(GL_FRAMEBUFFER, light.getShadowRenderer().getFramebufferId());
m_depth_.resize(light.getShadowMapDimension() * light.getShadowMapDimension());
glReadPixels(0, 0, light.getShadowMapDimension(), light.getShadowMapDimension(), GL_DEPTH_COMPONENT, GL_FLOAT, &m_depth_[0]);

It returns the right values and all read 5.19999, which is the value I expected. When I look at the debugger I see the following:

 

Dlxzo0F.png

 

This value is as expected. Now, when I render the scenes and I try to use these depth values it all falls apart...

 

Here is the vertex shader:

#version 420

uniform sampler2D depth_texture;

uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
uniform mat4 model_matrix;
uniform mat4 light_shadow_matrix;

uniform float z_near;
uniform float z_far;

in vec3 a_Vertex;
in float a_cos;

void main(void) 
{
	// TODO Make these values in uniforms and calculate them on the CPU.
	float a = z_far / (z_far - z_near);
	float b = z_far * z_near / (z_near - z_far);
	
	vec4 light_pos = light_shadow_matrix * model_matrix * vec4(a_Vertex, 1.0);
	vec4 depth_value = texture2DProj(depth_texture, light_pos);
		
	float actual_depth = b / (depth_value.r - a);
		
	actual_depth /= a_cos;

	// Change the location of this vertex by multiplying it with the depth value.
	vec4 pos = modelview_matrix * vec4((normalize(a_Vertex) * actual_depth), 1.0);

	gl_Position = projection_matrix * pos;
}

Fragment shader:

#version 420

out vec4 outColor;

void main(void)
{
	outColor = vec4(1.0, 0.0, 0.0, 1.0);
}

I initialise these shaders as follows:

void ShadowVolumeShader::initialise(const SceneLeafModel& model_node, const glm::mat4& view_matrix, const glm::mat4& model_matrix, const glm::mat4& projection_matrix, const std::vector<const SceneLeafLight*>& lights)
{
	if (lights.empty())
	{
		std::cout << "Could not initialise shader as there are no lights!" << std::endl;
		return;
	}
	
	Light& light = lights[0]->getLight();

	if (depth_not_initialised_)
	{
		loadDepth(light);
		glGenBuffers(1, &m_cos_buffer_);
		glBindBuffer(GL_ARRAY_BUFFER, m_cos_buffer_);
		glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) *  m_cos_.size(), &m_cos_[0], GL_STATIC_DRAW);
		depth_not_initialised_ = false;
	}
	
	bindShader();
	
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glDisableVertexAttribArray(3);
	glDisableVertexAttribArray(4);
	glDisableVertexAttribArray(5);
	glDisableVertexAttribArray(6);
	glDisableVertexAttribArray(7);

	glm::mat4 model_view_matrix = view_matrix * model_matrix;
	
	//Send the modelview and projection matrices to the shaders
	glUniformMatrix4fv(model_matrix_loc_, 1, false, glm::value_ptr(model_matrix));
	glUniformMatrix4fv(modelview_matrix_loc_, 1, false, glm::value_ptr(model_view_matrix));
	glUniformMatrix4fv(projection_matrix_loc_, 1, false, glm::value_ptr(projection_matrix));
	glUniformMatrix4fv(light_shadow_matrix_loc_, 1, false, glm::value_ptr(light.getShadowMatrix()));
	
	glActiveTexture(GL_TEXTURE0 + light.getDepthTextureId());
	glBindTexture(GL_TEXTURE_2D, light.getTextureId());
	
	glUniform1i(depth_texture_loc_, light.getDepthTextureId());
	glUniform1f(z_near_loc_, 0.1f);
	glUniform1f(z_far_loc_, 60.0f);

	//Bind the vertex array and set the vertex pointer to point at it
	glBindBuffer(GL_ARRAY_BUFFER, model_node.getModel().getVertexBufferId());
	glVertexAttribPointer((GLint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, m_cos_buffer_);
	glVertexAttribPointer((GLint)1, 1, GL_FLOAT, GL_FALSE, 0, 0);
}

When I use these depth values to render the volume that makes up the light using this setup I get this:

97LVm3q.png

 

The values down the diagonal are correct, but the others get rendered to the far plane. Now If I use the depth values I get from reading the depth bufferr using glReadPixels and feed it as a vertex attribute I get the correct values and the volume renders correctly:

 

GU2GYkN.png

 

This result is with the updated vertex shader:

#version 420

uniform sampler2D depth_texture;

uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
uniform mat4 model_matrix;
uniform mat4 light_shadow_matrix;

uniform float z_near;
uniform float z_far;

in vec3 a_Vertex;
in float a_Depth;
in float a_cos;

out vec2 texCoord0;

void main(void) 
{
	// TODO Make these values in uniforms and calculate them on the CPU.
	float a = z_far / (z_far - z_near);
	float b = z_far * z_near / (z_near - z_far);
	
	float actual_depth = b / (a_Depth - a);
	actual_depth /= a_cos;

	// Change the location of this vertex by multiplying it with the depth value.
	vec4 pos = modelview_matrix * vec4((normalize(a_Vertex) * actual_depth), 1.0);

	texCoord0 = a_TexCoord0;
	gl_Position = projection_matrix * pos;
}

Now, what do I do wrong that gives me the wrong depth values?

 

Any help is appreciated, thanks!

Bram

Edited by Morloth

Share this post


Link to post
Share on other sites

This topic is 1116 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this