PDA

View Full Version : Shadow mapping



tictactoe13
06-16-2013, 03:04 PM
Hi! For the last couple of weeks I've been trying to render a simple scene with 3 objects, using phong shading model and simple shadow mapping. I found many tutorials and tried many things, but I still can't show any shadows currently. It's my first OpenGL project at all and unfortunately I'm completely stuck at this point.

I post my code here for reference. I would be very glad to receive any help or advice to make it work!


// MAIN
#include "ShaderUtil.h"

GLfloat camPosition [] = {-8.0f, 6.0f, 8.0f};
GLfloat lightPosition [] = {6.5f, 4.0f, 10.0f};

const int shadowMapSize = 512;

GLuint shadowMapTexture, shdrProgram;

int width = 720, height = 480;

GLfloat lightProjMatrix[16], lightViewMatrix[16];
GLfloat camProjMatrix[16], camViewMatrix[16];

void calculateMatrices()
{
glMatrixMode(GL_MODELVIEW);

glPushMatrix();

glLoadIdentity();
gluPerspective(45.0f, (float)width/height, 1.0f, 100.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, camProjMatrix);

glLoadIdentity();
gluLookAt(camPosition[0], camPosition[1], camPosition[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, camViewMatrix);

glLoadIdentity();
gluPerspective(45.0f, (float)width/height, 1.0f, 100.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightProjMatrix);

glLoadIdentity();
gluLookAt(lightPosition[0], lightPosition[1], lightPosition[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);

glPopMatrix();
}

void changeSize(int w, int h)
{
if (h == 0)
h = 1;
width = w;
height = h;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
gluPerspective(45, 1.0 * width / height, 1, 1000);

calculateMatrices();
}

void renderObjects()
{
//Plane
glPushMatrix();
glTranslatef(3, 0, -1);
glScalef(1.5, 0.05, 1.1);
glutSolidCube(8);
glPopMatrix();

//Teapot
glPushMatrix();
glTranslatef(3, 1.5, 1);
glutSolidTeapot(1);
glPopMatrix();

//Sphere
glPushMatrix();
glTranslatef(-1, 1.5, 1);
glutSolidSphere(1, 30, 30);
glPopMatrix();
}

void renderScene()
{
//First pass - from light's point of view
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(lightProjMatrix);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(lightViewMatrix);
glViewport(0, 0, shadowMapSize, shadowMapSize);
glShadeModel(GL_FLAT); // Flat shading for speed
glColorMask(0, 0, 0, 0); // Disable writing of frame buffer color components

renderObjects();

//Read the depth buffer into the shadow map texture
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);

//restore states
glShadeModel(GL_SMOOTH);
glColorMask(1, 1, 1, 1);

//2nd pass - Draw from camera's point of view
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(camProjMatrix);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(camViewMatrix);
glViewport(0, 0, width, height);

renderObjects();

//Calculate texture matrix for projection
const GLfloat bias [] = {0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};

glMatrixMode(GL_TEXTURE);
glLoadMatrixf(bias);
glMultMatrixf(lightProjMatrix);
glMultMatrixf(lightViewMatrix);
glMatrixMode(GL_MODELVIEW);

GLint matLoc = glGetUniformLocation(shdrProgram,"lightingMatrix");
glUniform1fv(matLoc, 2, bias);

glutSwapBuffers();
}

void init()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glDepthFunc(GL_LESS);
glEnable(GL_MULTISAMPLE);

// Create the shadow map texture
glGenTextures(1, &shadowMapTexture);
glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapSize, shadowMapSize,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 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_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

// Set directional light
GLfloat lightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat lightDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
GLfloat lightSspecular[] = {0.33f, 0.33f, 0.33f, 1.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSspecular);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);

// Set material
GLfloat matrlAmbient[] = {0.0f, .6f, 0.7f, 1.0f};
GLfloat matrlDiffuse[] = {1.f, .5f, 0.1f, 1.0f};
GLfloat matrlSpecular[] = { 0.7f, 0.55f, 0.7f, 1.0f };
GLfloat matrlShininess = 80.0f;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matrlAmbient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matrlDiffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matrlSpecular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matrlShininess);
}

int main(int argc, char **argv)
{
// Init window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(width, height);
glutCreateWindow("GLSL Project");
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutReshapeFunc(changeSize);

init();

glewExperimental = GL_TRUE;
glewInit();

shdrProgram = ShaderUtil::loadShaders("shdr_shadow.vert", "shdr_shadow.frag");

glutMainLoop();

return 0;
}

// VERTEX SHADER
varying vec4 ProjShadow;
varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;
uniform mat4 lightingMatrix;

void main()
{
normal = normalize(gl_NormalMatrix * gl_Normal);

lightDir = normalize(vec3(gl_LightSource[0].position));

halfVector = normalize(gl_LightSource[0].halfVector.xyz);

diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;

//ProjShadow = gl_TextureMatrix[1] * gl_Vertex;
//gl_Position = ftransform();

ProjShadow = lightingMatrix * gl_Vertex;
gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex;
}

//FRAGMENT SHADER
uniform sampler2DShadow ShadowMap;
varying vec4 ProjShadow;
varying vec4 diffuse, ambient;
varying vec3 normal, lightDir, halfVector;

void main()
{
vec3 n, halfV;
float NdotL, NdotHV;

vec4 color = ambient;

n = normalize(normal);

NdotL = max(dot(n, lightDir), 0.0);

if (NdotL > 0.0) {
color += diffuse * NdotL;

halfV = normalize(halfVector);
NdotHV = max(dot(n, halfV), 0.0);
color += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV, gl_FrontMaterial.shininess);
}

color *= shadow2DProj(ShadowMap, ProjShadow).r ;

gl_FragColor = color;
}

Dark Photon
06-17-2013, 05:23 AM
Some random things I noticed in your code. If these don't pan out, you just need to be systematic in nailing down where the problem is. For instance, first determining whether the problem is with the rendering of the shadow map, or the application.

Your commented out use of the shadow matrix (via texture matrix) looks like it might be reasonable, given the unusual assumption that it takes WORLD-space coords as input (in your case, takes WORLD-space to biased light CLIP-space). However, gl_TextureMatrix[1] in the shader presumes that you loaded the matrix into the GL_TEXTURE matrix on texture unit 1, not 0. However, I don't see any glActiveTexture calls in your code. If you use a std GLSL uniform (vs. a legacy) you can get rid of this annoyance (see below).

Also in your shader, you're feeding gl_Vertex into this texture matrix transformation (assigning to ProjShadow, which is used for the depth lookup and comparison). This implies gl_Vertex is a WORLD-space coordinate position. Is it? This is not usually the case. And it does not appear so in your code (you are using operations which update the MODELING component of the MODELVIEW transform (e.g. Translate/Scale/Push/Pop/etc.)

Also in the code where you apparently gave up on passing the shadow matrix via texture matrix, you're trying to load a 4x4 matrix with glUniform1fv. Besides the fact that what you're passing in doesn't look useful, the way you pass a 4x4 matrix is with glUniformMatrix4fv. You can pass your shadow matrix into a std uniform (instead of a legacy built-in uniform like gl_TextureMatrix) after you get this working.

tictactoe13
06-17-2013, 02:10 PM
Thank you, I'll check all the thing you've pointed out!

tictactoe13
07-02-2013, 04:25 PM
I've tried some new things in my project recently and managed to achieve a bit different results, although still not the results I need.
I think I have some problems with the way I set my projection and view matrices for the first render pass (from the light's view), but I can't figure out what and where.
I'm sure there are still more or less random things or deprecated functions and etc. in my code, but I'm just trying to understand how to make it work for now. I would really appreciate very much any helpful comment or idea. Thank you indeed!

fragment shader - https://docs.google.com/file/d/0BxXOL7ayYi1MZE84NHB1eTVIMkk/edit?usp=sharing
vertex shader - https://docs.google.com/file/d/0BxXOL7ayYi1MZE84NHB1eTVIMkk/edit?usp=sharing
main cpp - https://docs.google.com/file/d/0BxXOL7ayYi1MX2ZQNHZnSlFrYUU/edit?usp=sharing
resulting picture - https://docs.google.com/file/d/0BxXOL7ayYi1Mb0Y2cVdaQ21yYzA/edit?usp=sharing

Alphaomega86
07-12-2013, 01:57 AM
You have to update and uniform your mvp matrix before you render an object.