Shadow mapping orthographic directional light .w=1

Started by
2 comments, last by polyfrag 10 years, 2 months ago

I'm using an orthographic projection matrix for the light and it doesn't seem correct unless in the depth vertex shader I set gl_Position.w = 1; (I just noticed in my other project that I had to set a drawing orthographic projection matrix gl_Position.w = 1; to make it pixel-perfect with the dimensions I specified when constructing the matrix, and that the shadow actually moved if I moved the light, which shouldn't happen for a directional/orthographic projection light, so I noticed today that I had to set gl_Position.w = 1; for the light orthographic matrix too.)


attribute vec4 position;

uniform mat4 projection;
uniform mat4 model;
uniform mat4 view;

attribute vec2 texCoordIn0;
varying vec2 texCoordOut0;

void main(void)
{
	gl_Position = projection * (view * (model * position));
	gl_Position.w = 1;	// sun light is orthographic directional light
	texCoordOut0 = texCoordIn0;
}

However that causes the shadow to show up wrong. lpos is the vertex in the light's clip-space on a range [0,1] (scaled by 0.5 and translated 0.5 for texture mapping).

Heightmap vertex shader:


void main(void)
{
	//vec4 vpos = (view * (model * position));
	vec4 vpos = model * position;
	//vec4 vpos = position;
	//vpos.w = 1;
	lpos = lightMatrix * vpos;
	lpos.w = 1;
	gl_Position = projection * (view * (model * position));
	//gl_Position.w = 1;

Setting lpos.w = 1 doesn't help.

Heightmap frag shader:


void main (void)
{
	//....

	vec3 smcoord = lpos.xyz / lpos.w;
	//vec3 smcoord = lpos.xyz;
	float shadow = max(0.6, 
		float(smcoord.z <= texture(shadowmap, smcoord.xy).x));
  	
Advertisement

Orthographic projection matrices typically use [0 0 0 1] was their last column (or row, if you're using column-major matrices) which means that the resulting w component should always be 1.0 provided that the w component of input vector is 1.0. If the w component isn't 1 (or very close to it), then it suggests that you may be doing something wrong when transforming your vertex position or creating your matrices.

Here's what I use.

Pretty sure this function is correct, and the problem is with postMultiply.



// http://www.songho.ca/opengl/gl_projectionmatrix.html
// http://www.scratchapixel.com/lessons/3d-advanced-lessons/perspective-and-orthographic-projection-matrix/orthographic-projection/
// http://www.opengl.org/discussion_boards/showthread.php/172280-Constructing-an-orthographic-matrix-for-2D-drawing
Matrix setorthographicmat(float l, float r, float t, float b, float n, float f)
{
    float m[16];
	
#define M(row,col)  m[col*4+row]
    M(0, 0) = 2 / (r - l);
    M(0, 1) = 0;
    M(0, 2) = 0;
    M(0, 3) = 0;
 
    M(1, 0) = 0;
    M(1, 1) = 2 / (t - b);
    M(1, 2) = 0;
    M(1, 3) = 0;
 
    M(2, 0) = 0;
    M(2, 1) = 0;
    M(2, 2) = -1 / (f - n);
    //M(2, 2) = -2 / (f - n);
    M(2, 3) = 0;
 
    M(3, 0) = -(r + l) / (r - l);
    M(3, 1) = -(t + b) / (t - b);
    M(3, 2) = -n / (f - n);
    //M(3, 2) = -(f + n) / (f - n);
    M(3, 3) = 1;
#undef M
	
    Matrix mat;
    mat.set(m);

	return mat;
}

void Matrix::postMultiply( const Matrix& matrix )
{
	float newMatrix[16];

#if 0

	const float *m1 = m_matrix, *m2 = matrix.m_matrix;

	newMatrix[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2];
	newMatrix[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2];
	newMatrix[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2];
	newMatrix[3] = 0;

	newMatrix[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6];
	newMatrix[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6];
	newMatrix[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6];
	newMatrix[7] = 0;

	newMatrix[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10];
	newMatrix[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10];
	newMatrix[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10];
	newMatrix[11] = 0;

	newMatrix[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12];
	newMatrix[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13];
	newMatrix[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14];
	newMatrix[15] = 1;

#else

	const float *a = m_matrix, *b = matrix.m_matrix;

	newMatrix[0]  = a[0] * b[0]  + a[4] * b[1]  + a[8] * b[2]   + a[12] * b[3];
	newMatrix[1]  = a[1] * b[0]  + a[5] * b[1]  + a[9] * b[2]   + a[13] * b[3];
	newMatrix[2]  = a[2] * b[0]  + a[6] * b[1]  + a[10] * b[2]  + a[14] * b[3];
	newMatrix[3]  = a[3] * b[0]  + a[7] * b[1]  + a[11] * b[2]  + a[15] * b[3];

	newMatrix[4]  = a[0] * b[4]  + a[4] * b[5]  + a[8] * b[6]   + a[12] * b[7];
	newMatrix[5]  = a[1] * b[4]  + a[5] * b[5]  + a[9] * b[6]   + a[13] * b[7];
	newMatrix[6]  = a[2] * b[4]  + a[6] * b[5]  + a[10] * b[6]  + a[14] * b[7];
	newMatrix[7]  = a[3] * b[4]  + a[7] * b[5]  + a[11] * b[6]  + a[15] * b[7];

	newMatrix[8]  = a[0] * b[8]  + a[4] * b[9]  + a[8] * b[10]  + a[12] * b[11];
	newMatrix[9]  = a[1] * b[8]  + a[5] * b[9]  + a[9] * b[10]  + a[13] * b[11];
	newMatrix[10] = a[2] * b[8]  + a[6] * b[9]  + a[10] * b[10] + a[14] * b[11];
	newMatrix[11] = a[3] * b[8]  + a[7] * b[9]  + a[11] * b[10] + a[15] * b[11];

	newMatrix[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14]  + a[12] * b[15];
	newMatrix[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14]  + a[13] * b[15];
	newMatrix[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15];
	newMatrix[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15];

#endif

	set( newMatrix );
}

I made a new function to use just for calculating the light matrix


void Matrix::postMultiply2( const Matrix& matrix )
{
	float newMatrix[16];

#if 1

	const float *m1 = m_matrix, *m2 = matrix.m_matrix;

	newMatrix[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2];
	newMatrix[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2];
	newMatrix[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2];
	newMatrix[3] = 0;

	newMatrix[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6];
	newMatrix[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6];
	newMatrix[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6];
	newMatrix[7] = 0;

	newMatrix[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10];
	newMatrix[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10];
	newMatrix[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10];
	newMatrix[11] = 0;

	newMatrix[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12];
	newMatrix[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13];
	newMatrix[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14];
	newMatrix[15] = 1;

#else

	const float *a = m_matrix, *b = matrix.m_matrix;

	newMatrix[0]  = a[0] * b[0]  + a[4] * b[1]  + a[8] * b[2]   + a[12] * b[3];
	newMatrix[1]  = a[1] * b[0]  + a[5] * b[1]  + a[9] * b[2]   + a[13] * b[3];
	newMatrix[2]  = a[2] * b[0]  + a[6] * b[1]  + a[10] * b[2]  + a[14] * b[3];
	newMatrix[3]  = a[3] * b[0]  + a[7] * b[1]  + a[11] * b[2]  + a[15] * b[3];

	newMatrix[4]  = a[0] * b[4]  + a[4] * b[5]  + a[8] * b[6]   + a[12] * b[7];
	newMatrix[5]  = a[1] * b[4]  + a[5] * b[5]  + a[9] * b[6]   + a[13] * b[7];
	newMatrix[6]  = a[2] * b[4]  + a[6] * b[5]  + a[10] * b[6]  + a[14] * b[7];
	newMatrix[7]  = a[3] * b[4]  + a[7] * b[5]  + a[11] * b[6]  + a[15] * b[7];

	newMatrix[8]  = a[0] * b[8]  + a[4] * b[9]  + a[8] * b[10]  + a[12] * b[11];
	newMatrix[9]  = a[1] * b[8]  + a[5] * b[9]  + a[9] * b[10]  + a[13] * b[11];
	newMatrix[10] = a[2] * b[8]  + a[6] * b[9]  + a[10] * b[10] + a[14] * b[11];
	newMatrix[11] = a[3] * b[8]  + a[7] * b[9]  + a[11] * b[10] + a[15] * b[11];

	newMatrix[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14]  + a[12] * b[15];
	newMatrix[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14]  + a[13] * b[15];
	newMatrix[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15];
	newMatrix[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15];

#endif

	set( newMatrix );
}

Notice the switch #if is 1 in this one. And it seems to do the trick. Can anybody explain why this one works specifically for orthographic matrixes but not projection?

This topic is closed to new replies.

Advertisement