Skip to main content
GameDev.net gamedev.net
🔒 Locked

[Solved]Shadow Map/Textured Terrain

Started by Zelxin Nov 20, 2009 at 12:20 AM 2 replies 1.9k views
Original Post
Zelxin
Zelxin
Ok, so this is a little project I've been working on over the past year, to learn PhysX and openGL (started out with a few of the physX demos, now i've started to add more graphics to it) I'm using shadow mapping (basically a direct copy past from http://www.paulsprojects.net/tutorials/smt/smt.html (for the most part, i'm sure i've changed some of it without even noticing) Anyway, I'm running into a problem when i try to texture my terrain and use my shadow map texture as well. The shadows appear fine (aliased to hell, but thats not what i'm worrying about now) when i disable the texturing on my terrain. However, when i run it with the texture on the shadows do not appear (I've tried rendering the second pass without textures on the terrain, this causes shadows to be completely black) I have also tried rending it with no texture on the third pass, which makes the shadows appear to be the terrains colour) In all honesty i think I have tried everything, and i do not know where the problem is, likely it is something to do with openGL that i have no idea about because i jumped in too far Code
[source lang=cpp]
void FirstPass()
{
	//First pass - from light's point of view
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(lightProjectionMatrix);

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(lightViewMatrix);

	//Use viewport the same size as the shadow map
	glViewport(0, 0, shadowMapSize, shadowMapSize);

	//Draw back faces into the shadow map
	glCullFace(GL_FRONT);

	//Disable color writes, and use flat shading for speed
	glShadeModel(GL_SMOOTH);
	glColorMask(0, 0, 0, 0);
	//Renders all actors in the scene
	NxU32 nbActors = gScene->getNbActors();
    NxActor** actors = gScene->getActors();
    while (nbActors--)
    {
        NxActor* actor = *actors++;
        DrawActor(actor, gSelectedActor, true);
    }
	//terr.RenderHeightMap(false);
void FirstPassFinish()
{
	//Read the depth buffer into the shadow map texture
	glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);
	//restore states
	
	glCullFace(GL_BACK);
	glShadeModel(GL_SMOOTH);
	glColorMask(1, 1, 1, 1);
}
}



SECOND PASS
[source lang=cpp]
void SecondPass()
{
	//2nd pass - Draw from camera's point of view
	glClear(GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(cameraProjectionMatrix);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(cameraViewMatrix);

	glViewport(0, 0, winWidth, winHeight);

	VECTOR3D lightc(0.1f,0.1f,0.1f);
	
	//Use dim light to represent shadowed areas
	glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(lightPosition));
	glLightfv(GL_LIGHT1, GL_AMBIENT, white*0.2f);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, white*0.2f);
	glLightfv(GL_LIGHT1, GL_SPECULAR, black);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHTING);
	//Renders all actors in the scene
	NxU32 nbActors = gScene->getNbActors();
    NxActor** actors = gScene->getActors();
    while (nbActors--)
    {
        NxActor* actor = *actors++;
        DrawActor(actor, gSelectedActor, true);
    }
	terr.RenderHeightMap(false);
}



THIRD
[source lang=cpp]
void ThirdPass()
{
	//Draw with bright light
    float DiffuseColor1[]    = { 0.9f, 0.9f, 0.9f, 0.0f };
    float SpecularColor1[]   = { 0.9f, 0.9f, 0.9f, 0.0f };     
	glLightfv(GL_LIGHT1, GL_DIFFUSE, DiffuseColor1);
	glLightfv(GL_LIGHT1, GL_SPECULAR, SpecularColor1);
	
	//Calculate texture matrix for projection
	//This matrix takes us from eye space to the light's clip space
	//It is postmultiplied by the inverse of the current view matrix when specifying texgen
	MATRIX4X4 biasMatrix(0.5f, 0.0f, 0.0f, 0.0f,
								0.0f, 0.5f, 0.0f, 0.0f,
								0.0f, 0.0f, 0.5f, 0.0f,
								0.5f, 0.5f, 0.5f, 1.0f);	//bias from [-1, 1] to [0, 1]
	MATRIX4X4 textureMatrix=biasMatrix*lightProjectionMatrix*lightViewMatrix;

	//Set up texture coordinate generation.
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0));
	glEnable(GL_TEXTURE_GEN_S);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1));
	glEnable(GL_TEXTURE_GEN_T);

	glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2));
	glEnable(GL_TEXTURE_GEN_R);

	glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3));
	glEnable(GL_TEXTURE_GEN_Q);

	//Bind & enable shadow map texture
	glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
	glEnable(GL_TEXTURE_2D);

	//Enable shadow comparison
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);

	//Shadow comparison should be true (ie not in shadow) if r<=texture
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);

	//Shadow comparison should generate an INTENSITY result
	glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);

	//Set alpha test to discard false comparisons
	glAlphaFunc(GL_GEQUAL, 0.99f);
	glEnable(GL_ALPHA_TEST);
	//Renders all actors in the scene
	terr.RenderHeightMap(false);
	NxU32 nbActors = gScene->getNbActors();
    NxActor** actors = gScene->getActors();
    while (nbActors--)
    {
        NxActor* actor = *actors++;
        DrawActor(actor, gSelectedActor, true);
    }
	
}
void ThirdPassRestore()
{
	//Disable textures and texgen
	glDisable(GL_TEXTURE_2D);

	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);
	glDisable(GL_TEXTURE_GEN_R);
	glDisable(GL_TEXTURE_GEN_Q);

	//Restore other states
	glDisable(GL_LIGHTING);
	glDisable(GL_ALPHA_TEST);
}


Render terrain
[source lang=cpp]if (!bTex)
		{
			NxVec3 hMap(0,0,0);
			//glEnable(GL_TEXTURE_2D);
			//glBindTexture(GL_TEXTURE_2D, texture.TextureID);
			for (int hMapX = 0; hMapX < sizeX; hMapX += STEP_SIZE)
			{
				for (int hMapZ = 0; hMapZ < sizeZ; hMapZ += STEP_SIZE)
				{
					

					glBegin(GL_QUADS);

					//glTexCoord2f((float)hMapX / sizeX, (float)hMapZ / sizeZ);
					glVertex3f( hMapX, (yMap[hMapX][hMapZ]), hMapZ);

					//glTexCoord2f((float)hMapX / sizeX, (float)(hMapZ+5) / sizeZ);
					glVertex3f( hMapX, (yMap[hMapX][hMapZ + 5]), hMapZ + 5);

					//glTexCoord2f((float)(hMapX+5) / sizeX, (float)(hMapZ+5) / sizeZ);
					glVertex3f( hMapX + 5, (yMap[hMapX + +5][hMapZ+5]), hMapZ + 5);

					//glTexCoord2f((float)(hMapX+5) / sizeX, (float)(hMapZ) / sizeZ);
					glVertex3f( hMapX + 5, (yMap[hMapX + 5][hMapZ]), hMapZ);
					glEnd();
					
				} 
			}
		}else
		{
			NxVec3 hMap(0,0,0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, texture.TextureID);
			// GLMATERIALS LOOK AT THEM!
			for (int hMapX = 0; hMapX < sizeX; hMapX += STEP_SIZE)
			{
				for (int hMapZ = 0; hMapZ < sizeZ; hMapZ += STEP_SIZE)
				{
						

					glBegin(GL_QUADS);
					glTexCoord2f((float)hMapX / sizeX, (float)hMapZ / sizeZ);
					glVertex3f( hMapX, (yMap[hMapX][hMapZ]), hMapZ);

					glTexCoord2f((float)hMapX / sizeX, (float)(hMapZ+5) / sizeZ);
					glVertex3f( hMapX, (yMap[hMapX][hMapZ + 5]), hMapZ + 5);

					glTexCoord2f((float)(hMapX+5) / sizeX, (float)(hMapZ+5) / sizeZ);
					glVertex3f( hMapX + 5, (yMap[hMapX + +5][hMapZ+5]), hMapZ + 5);

					glTexCoord2f((float)(hMapX+5) / sizeX, (float)(hMapZ) / sizeZ);
					glVertex3f( hMapX + 5, (yMap[hMapX + 5][hMapZ]), hMapZ);
					glEnd();
						
				} 
			}
			glDisable(GL_TEXTURE_2D);
		}



[Edited by - Zelxin on November 21, 2009 2:23:52 PM]
szecs
szecs
You can try drawing the shadows (shadow on terrain pass) by using blending, and with glColor4f(0,0,0,0.5) for example. (first pass: make the shadowmap, second: draw entire terrain with textures (no shadow checking), third: draw shadowed terrain with no textures and color set to(0,0,0,0.5) and blending enabled).

But the real thing is called multitexturing. It allows you to use more textures on the same objects, thus you can render the textured terrain and check the shadowmap in the same time.

However you have to have 3 passes: first: make the shadowmap, second: render shadowed area (for example with diffuse light set to (0,0,0), but ambient is the same -> ambient shadows)
third, render the un-shadowed area. (you can swap the order of the 2nd-3rd passes).

More details:
If using multitexturing, you have texture units, that operate independently (sort of)
having their own states (enabled/disabled) own texture coordinates, texture binding etc. You can change these with the same commands, so you have to make the texture unit active, if you want to change its properties. Look into it, it's not hard.
In shadow mapping (SM):

you have to use a texture unit for the SM, and an other for all the other textures.
Make the SM's texture unit active, when you copy the depth buffer to the depth texture, and when you generate the texture coordinates for the SM. Otherwise make the other texture unit active.

I hope that helps
Zelxin
Zelxin
Thank you so much, got the multitexturing working properly.
Wing_Zero
Wing_Zero
I have a question regarding your PhysX and Glut stuff.
I am doing similar stuff working with OGL and PhysX, however, whenever I compile my code I get these error messages:

too many arguments to function ‘void DrawActor(NxActor*, NxActor*)

I have included these at the beginning of my code:
#include
#include
#include
#include
#include

#include "NxPhysics.h"
#include "Actors.h"
#include "DrawObjects.h"

and use the exact same while loop to DrawActors:

while(nbActors--)
{
NxActor* actor = *actors++;
DrawActor(actor, gSelectedActor, false);
}

However if i change the code to resemble either of these:
while(nbActors--)
{
NxActor* actor = *actors++;
DrawActor(actor, gSelectedActor);
}
OR....
while(nbActors--)
{
NxActor* actor = *actors++;
DrawActor(actor, false);
}

undefined reference to `DrawActor(NxActor*, NxActor*)

Help would be greatly appreciated.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.