[QUOTE=arekkusu;1257618]Keep debugging your transforms to understand the resulting window Z.
Remember that the gl_Position output of your shader is not NDC, it is clip space (-w…w). After the shader runs, homogenous divide by w produces NDC, and that result is scaled by glViewport and glDepthRange to produce window coords. That window Z (or optionally, your replacement value written to gl_FragDepth) is used during the depth test.
You can debug all of those transforms yourself on the CPU, and compare with the real Z written to the depth buffer, via GetTexImage or ReadPixels, until you understand your transforms.[/QUOTE]
I’m using the programmable pipeline, and setting w to 1.0 to use homogeneous coordinates, so that should not be an issue. GlViewport runs from 0, 0 to 4096, 4096, so it should write into that range in the texture and glDepthRange has not been modified.
I do have to post the code of the tutorial here, of the book called OpenGL SuperBible: Sixth Edition
/*
* Copyright © 2012-2013 Graham Sellers
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <sb6.h>
#include <vmath.h>
#include <object.h>
#include <sb6ktx.h>
#include <shader.h>
#define DEPTH_TEXTURE_SIZE 4096
#define FRUSTUM_DEPTH 1000
class shadowmapping_app : public sb6::application
{
public:
shadowmapping_app()
: light_program(0),
view_program(0),
show_light_depth_program(0),
mode(RENDER_FULL),
paused(false)
{
}
protected:
void init()
{
static const char title[] = "OpenGL SuperBible - Shadow Mapping";
sb6::application::init();
memcpy(info.title, title, sizeof(title));
}
void startup();
void render(double currentTime);
void render_scene(double currentTime, bool from_light);
void onKey(int key, int action);
void load_shaders();
GLuint light_program;
GLuint view_program;
GLint show_light_depth_program;
struct
{
struct
{
GLint mvp;
} light;
struct
{
GLint mv_matrix;
GLint proj_matrix;
GLint shadow_matrix;
GLint full_shading;
} view;
} uniforms;
GLuint depth_fbo;
GLuint depth_tex;
GLuint depth_debug_tex;
enum { OBJECT_COUNT = 4 };
struct
{
sb6::object obj;
vmath::mat4 model_matrix;
} objects[OBJECT_COUNT];
vmath::mat4 light_view_matrix;
vmath::mat4 light_proj_matrix;
vmath::mat4 camera_view_matrix;
vmath::mat4 camera_proj_matrix;
GLuint quad_vao;
enum
{
RENDER_FULL,
RENDER_LIGHT,
RENDER_DEPTH
} mode;
bool paused;
};
void shadowmapping_app::startup()
{
load_shaders();
int i;
static const char * const object_names[] =
{
"media/objects/dragon.sbm",
"media/objects/sphere.sbm",
"media/objects/cube.sbm",
"media/objects/torus.sbm"
};
for (i = 0; i < OBJECT_COUNT; i++)
{
objects[i].obj.load(object_names[i]);
}
glGenFramebuffers(1, &depth_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
glGenTextures(1, &depth_tex);
glBindTexture(GL_TEXTURE_2D, depth_tex);
glTexStorage2D(GL_TEXTURE_2D, 11, GL_DEPTH_COMPONENT32F, DEPTH_TEXTURE_SIZE, DEPTH_TEXTURE_SIZE);
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_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_tex, 0);
glGenTextures(1, &depth_debug_tex);
glBindTexture(GL_TEXTURE_2D, depth_debug_tex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, DEPTH_TEXTURE_SIZE, DEPTH_TEXTURE_SIZE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, depth_debug_tex, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
glGenVertexArrays(1, &quad_vao);
glBindVertexArray(quad_vao);
}
void shadowmapping_app::render(double currentTime)
{
static const GLfloat zeros[] = { 0.0f, 0.0f, 0.0f, 0.0f };
static double last_time = 0.0;
static double total_time = 0.0;
if (!paused)
total_time += (currentTime - last_time);
last_time = currentTime;
const float f = (float)total_time + 30.0f;
vmath::vec3 light_position = vmath::vec3(20.0f, 20.0f, 20.0f);
vmath::vec3 view_position = vmath::vec3(0.0f, 0.0f, 40.0f);
light_proj_matrix = vmath::frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 200.0f);
light_view_matrix = vmath::lookat(light_position,
vmath::vec3(0.0f), vmath::vec3(0.0f, 1.0f, 0.0f));
camera_proj_matrix = vmath::perspective(50.0f,
(float)info.windowWidth / (float)info.windowHeight,
1.0f,
200.0f);
camera_view_matrix = vmath::lookat(view_position,
vmath::vec3(0.0f),
vmath::vec3(0.0f, 1.0f, 0.0f));
objects[0].model_matrix = vmath::rotate(f * 14.5f, 0.0f, 1.0f, 0.0f) *
vmath::rotate(20.0f, 1.0f, 0.0f, 0.0f) *
vmath::translate(0.0f, -4.0f, 0.0f);
objects[1].model_matrix = vmath::rotate(f * 3.7f, 0.0f, 1.0f, 0.0f) *
vmath::translate(sinf(f * 0.37f) * 12.0f, cosf(f * 0.37f) * 12.0f, 0.0f) *
vmath::scale(2.0f);
objects[2].model_matrix = vmath::rotate(f * 6.45f, 0.0f, 1.0f, 0.0f) *
vmath::translate(sinf(f * 0.25f) * 10.0f, cosf(f * 0.25f) * 10.0f, 0.0f) *
vmath::rotate(f * 99.0f, 0.0f, 0.0f, 1.0f) *
vmath::scale(2.0f);
objects[3].model_matrix = vmath::rotate(f * 5.25f, 0.0f, 1.0f, 0.0f) *
vmath::translate(sinf(f * 0.51f) * 14.0f, cosf(f * 0.51f) * 14.0f, 0.0f) *
vmath::rotate(f * 120.3f, 0.707106f, 0.0f, 0.707106f) *
vmath::scale(2.0f);
glEnable(GL_DEPTH_TEST);
render_scene(total_time, true);
if (mode == RENDER_DEPTH)
{
glDisable(GL_DEPTH_TEST);
glBindVertexArray(quad_vao);
glUseProgram(show_light_depth_program);
glBindTexture(GL_TEXTURE_2D, depth_debug_tex);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
else
{
render_scene(total_time, false);
}
}
void shadowmapping_app::render_scene(double currentTime, bool from_light)
{
static const GLfloat ones[] = { 1.0f };
static const GLfloat zero[] = { 0.0f };
static const GLfloat gray[] = { 0.1f, 0.1f, 0.1f, 0.0f };
static const vmath::mat4 scale_bias_matrix = vmath::mat4(vmath::vec4(0.5f, 0.0f, 0.0f, 0.0f),
vmath::vec4(0.0f, 0.5f, 0.0f, 0.0f),
vmath::vec4(0.0f, 0.0f, 0.5f, 0.0f),
vmath::vec4(0.5f, 0.5f, 0.5f, 1.0f));
vmath::mat4 light_vp_matrix = light_proj_matrix * light_view_matrix;
vmath::mat4 shadow_sbpv_matrix = scale_bias_matrix * light_proj_matrix * light_view_matrix;
if (from_light)
{
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
glViewport(0, 0, DEPTH_TEXTURE_SIZE, DEPTH_TEXTURE_SIZE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(4.0f, 4.0f);
glUseProgram(light_program);
static const GLenum buffs[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, buffs);
glClearBufferfv(GL_COLOR, 0, zero);
}
else
{
glViewport(0, 0, info.windowWidth, info.windowHeight);
glClearBufferfv(GL_COLOR, 0, gray);
glUseProgram(view_program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depth_tex);
glUniformMatrix4fv(uniforms.view.proj_matrix, 1, GL_FALSE, camera_proj_matrix);
glDrawBuffer(GL_BACK);
}
glClearBufferfv(GL_DEPTH, 0, ones);
int i;
for (i = 0; i < 4; i++)
{
vmath::mat4& model_matrix = objects[i].model_matrix;
if (from_light)
{
glUniformMatrix4fv(uniforms.light.mvp, 1, GL_FALSE, light_vp_matrix * objects[i].model_matrix);
}
else
{
vmath::mat4 shadow_matrix = shadow_sbpv_matrix * model_matrix;
glUniformMatrix4fv(uniforms.view.shadow_matrix, 1, GL_FALSE, shadow_matrix);
glUniformMatrix4fv(uniforms.view.mv_matrix, 1, GL_FALSE, camera_view_matrix * objects[i].model_matrix);
glUniform1i(uniforms.view.full_shading, mode == RENDER_FULL ? 1 : 0);
}
objects[i].obj.render();
}
if (from_light)
{
glDisable(GL_POLYGON_OFFSET_FILL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
else
{
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void shadowmapping_app::onKey(int key, int action)
{
if (action)
{
switch (key)
{
case '1':
mode = RENDER_FULL;
break;
case '2':
mode = RENDER_LIGHT;
break;
case '3':
mode = RENDER_DEPTH;
break;
case 'R':
load_shaders();
break;
case 'P':
paused = !paused;
break;
}
}
}
void shadowmapping_app::load_shaders()
{
GLuint vs;
GLuint fs;
vs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-light.vs.glsl", GL_VERTEX_SHADER);
fs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-light.fs.glsl", GL_FRAGMENT_SHADER);
if (light_program)
glDeleteProgram(light_program);
light_program = glCreateProgram();
glAttachShader(light_program, vs);
glAttachShader(light_program, fs);
glLinkProgram(light_program);
glDeleteShader(vs);
glDeleteShader(fs);
uniforms.light.mvp = glGetUniformLocation(light_program, "mvp");
vs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-camera.vs.glsl", GL_VERTEX_SHADER);
fs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-camera.fs.glsl", GL_FRAGMENT_SHADER);
if (light_program)
glDeleteProgram(view_program);
view_program = glCreateProgram();
glAttachShader(view_program, vs);
glAttachShader(view_program, fs);
glLinkProgram(view_program);
glDeleteShader(vs);
glDeleteShader(fs);
uniforms.view.proj_matrix = glGetUniformLocation(view_program, "proj_matrix");
uniforms.view.mv_matrix = glGetUniformLocation(view_program, "mv_matrix");
uniforms.view.shadow_matrix = glGetUniformLocation(view_program, "shadow_matrix");
uniforms.view.full_shading = glGetUniformLocation(view_program, "full_shading");
if (show_light_depth_program)
glDeleteProgram(show_light_depth_program);
show_light_depth_program = glCreateProgram();
vs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-light-view.vs.glsl", GL_VERTEX_SHADER);
fs = sb6::shader::load("media/shaders/shadowmapping/shadowmapping-light-view.fs.glsl", GL_FRAGMENT_SHADER);
glAttachShader(show_light_depth_program, vs);
glAttachShader(show_light_depth_program, fs);
glLinkProgram(show_light_depth_program);
glDeleteShader(vs);
glDeleteShader(fs);
}
DECLARE_MAIN(shadowmapping_app)
Light vertex shader
#version 420 core
uniform mat4 mvp;
layout (location = 0) in vec4 position;
void main(void)
{
gl_Position = mvp * position;
}
Light fragment shader:
#version 420 core
layout (location = 0) out vec4 color;
void main(void)
{
color = vec4(gl_FragCoord.z);
}
Render vertex shader:
#version 420 core
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 shadow_matrix;
layout (location = 0) in vec4 position;
layout (location = 1) in vec3 normal;
out VS_OUT
{
vec4 shadow_coord;
vec3 N;
vec3 L;
vec3 V;
} vs_out;
// Position of light
uniform vec3 light_pos = vec3(100.0, 100.0, 100.0);
void main(void)
{
// Calculate view-space coordinate
vec4 P = mv_matrix * position;
// Calculate normal in view-space
vs_out.N = mat3(mv_matrix) * normal;
// Calculate light vector
vs_out.L = light_pos - P.xyz;
// Calculate view vector
vs_out.V = -P.xyz;
// Light-space coordinates
vs_out.shadow_coord = shadow_matrix * position;
// Calculate the clip-space position of each vertex
gl_Position = proj_matrix * P;
}
Render fragment shader:
#version 420 core
layout (location = 0) out vec4 color;
layout (binding = 0) uniform sampler2DShadow shadow_tex;
in VS_OUT
{
vec4 shadow_coord;
vec3 N;
vec3 L;
vec3 V;
} fs_in;
// Material properties
uniform vec3 diffuse_albedo = vec3(0.9, 0.8, 1.0);
uniform vec3 specular_albedo = vec3(0.7);
uniform float specular_power = 300.0;
uniform bool full_shading = true;
void main(void)
{
// Normalize the incoming N, L and V vectors
vec3 N = normalize(fs_in.N);
vec3 L = normalize(fs_in.L);
vec3 V = normalize(fs_in.V);
// Calculate R locally
vec3 R = reflect(-L, N);
// Compute the diffuse and specular components for each fragment
vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;
// Write final color to the framebuffer
color = textureProj(shadow_tex, fs_in.shadow_coord) * mix(vec4(1.0), vec4(diffuse + specular, 1.0), bvec4(full_shading));
}
Another thing I am worried about is that a lot of questions online refer to glFrameRenderBuffer, what exactly is a renderBuffer? And since I’ve seen no one complain about me not using it, it should be no problem?