# Shadowmapping with Large terrains part 2

## Recommended Posts

I have my frustum drawn out now so I can see whats going on. I now have noticed that the FOV for sure affects the IQ of my shadows. So I am trying to move my shadowmaps frustum around to to follow my camera, but having no luck with that... I noticed if I move it moves in the opposite direction? I think if I can follow my camera's view around I may have solved the issue with the shadows looking like crap on large terrain areas. Thanks for any help. part 1 thread http://www.gamedev.net/community/forums/topic.asp?topic_id=387857

##### Share on other sites
is the sm cast from the sun?
if so then u shouldnt be using a perspective frustum but a orthogonal one

##### Share on other sites
Quote:
 Original post by zedzeekis the sm cast from the sun?if so then u shouldnt be using a perspective frustum but a orthogonal one

Hey Zed, yeah it's from the sun POV. Changing to a Orthogonal frustum still isn't going to follow my camera around... And if it does I guess I don't understand how. Thanks

##### Share on other sites
Hi MARS_999,

How do you calculate the mvp for the light?
Suppose it's a spot light with a pespective projection, maybe this will help:

Vec3 sunDir; // You should already have that.Vec3 camPos; // This too...Vec3 camDir; // This too...// Calculate a point in front of the cameraVec3 pointInFrontOfCam = camPos + camDir * offset;// From that and from the sun direction calculate sun's positionVec3 sunPos = pointInFrontOfCam - sunDir * sunDistance;// Setup a lookat matrix using this position...gluLookAt(sunPos.x, sunPos.y, sunPos.z, pointInFrontOfCam.x, pointInFrontOfCam.y, pointInFrontOfCam.z, 0.0f, 1.0f, 0.0f);

Have you tried that? What happens?
I haven't read your old thread, so sorry if this is completely irrelevant, but you said you are trying to make the frustum follow the camera, so i think this will do it.

Hope that helps.

HellRaiZer

##### Share on other sites
Quote:
 Original post by HellRaiZerHi MARS_999,How do you calculate the mvp for the light?Suppose it's a spot light with a pespective projection, maybe this will help:*** Source Snippet Removed ***Have you tried that? What happens? I haven't read your old thread, so sorry if this is completely irrelevant, but you said you are trying to make the frustum follow the camera, so i think this will do it.Hope that helps.HellRaiZer

Hey HellRaiZer, been awhile! It's a directional light with a perspective projection I am using... I am trying to allow my shadowmaps frustum follow me around the terrain. I am trying to move it around by giving my glTranslatef() xyz values to follow me around. Thanks

##### Share on other sites
Are you saying that you set your light looking at the origin and then you translate the frustum to the camera's position?
How are you doing that?

I think (if i understood it correctly) you are doing something like this:

void UpdateShadowmap(){  glMatrixMode(GL_PROJECTION);  glLoadMatrix(Light_Proj);  glMatrixMode(GL_MODELVIEW);  glLoadMatrix(Light_View);  glTranslatef(cam_pos.x, cam_pos.y, cam_pos.z);  RenderScene();}

Is that right?
If it is, i think it is normal that your frustum is moving in the opposite direction. What you are doing isn't translating the light's frustum around the camera, but translating the world around the origin (which the light is looking). If you really want to make it this way then try to translate the world in the opposite direction. Otherwise use the code i posted previously. In other words, try to put the camera position inside the light's view matrix.

HellRaiZer

##### Share on other sites
I am moving my lights POV I guess here is my code that I am altering

void CTerrain::StoreLightMatrix(void){	memset(modelViewMatrix, 0, sizeof(float) * 16);	memset(modelProjectionMatrix, 0, sizeof(float) * 16);	glPushMatrix();		glPushMatrix();			glLoadIdentity();			gluLookAt(lightPosition[0],  lightPosition[1],  lightPosition[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);			glTranslatef(moveShadowPosX, 0.0f, moveShadowPosZ);			glRotatef(37.5f, 0.0f, 1.0f, 0.0f);			glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);		glPopMatrix();		glLoadIdentity();		gluPerspective(20.0f, 1.0f, 200.0f, 300.0f);		//glOrtho(0.0, gWidth, 0.0, gHeight, 200.0, 400.0);		glGetFloatv(GL_MODELVIEW_MATRIX, modelProjectionMatrix);	glPopMatrix();}

Now I am also trying to do a orthographic projection but that isn't working out to well either... I just figured all I had to do was change my gluPerspective to glOrtho but the shadows look like round blobs...

##### Share on other sites
with your method youre wasting large part of SM on stuff that is offscreen, instead of covering the whole terrain, u want to focus on the area infront of the camera
eg
gluLookAT( campos+cam_forward_dir*100 )
also u can take the suns direction relative to the camera into consideration

##### Share on other sites
Quote:
 Original post by zedzeekwith your method youre wasting large part of SM on stuff that is offscreen, instead of covering the whole terrain, u want to focus on the area infront of the cameraeggluLookAT( campos+cam_forward_dir*100 )also u can take the suns direction relative to the camera into consideration

Hi Zedzeek, yeah you are correct. That is what I am trying to do. I moved my frustum and WOW when its closer and a smaller FOV the shadows are really nice vs. covering the whole terrain. I just need to get the shadowmap frustum to move with my camera. So this gluLookAT( campos+cam_forward_dir*100 ) is that formula only for the camera position? I will give your idea a shot. Will you be on much longer? Thanks

##### Share on other sites
Hmm I just dumped the lightposition parameters from my code with the camera positions and the frustum is way off and the shadows are coming from the wrong direction... I never thought this would be so hard to get working, just seems like I should only have to translate my frustum around so it follows my camera from behind a bit....

##### Share on other sites
Try this code and see what it will give.

float g_CameraPos[3];float g_CameraDir[3];float g_LightDirection[3]; // this is from sun to earthfloat g_LightDistance; // distance from sun to the ground.float g_LightLookAtOffset; // How far in front of the camera should the light focus. void CTerrain::StoreLightMatrix(void){	memset(modelViewMatrix, 0, sizeof(float) * 16);	memset(modelProjectionMatrix, 0, sizeof(float) * 16);        float pointInFrontOfCamera[3] = { g_CameraPos[0] + g_CameraDir[0] * g_LightLookAtOffset,                                           g_CameraPos[1] + g_CameraDir[1] * g_LightLookAtOffset,                                           g_CameraPos[2] + g_CameraDir[2] * g_LightLookAtOffset};        float lightPosition[3] = { pointInFrontOfCamera[0] - g_LightDirection[0] * g_LightDistance,                                    pointInFrontOfCamera[1] - g_LightDirection[1] * g_LightDistance,                                    pointInFrontOfCamera[2] - g_LightDirection[2] * g_LightDistance};	glPushMatrix();		glPushMatrix();			glLoadIdentity();			gluLookAt(lightPosition[0],  lightPosition[1],  lightPosition[2], pointInFrontOfCamera[0], pointInFrontOfCamera[1], pointInFrontOfCamera[2], 0.0, 1.0, 0.0);			glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);		glPopMatrix();		glLoadIdentity();		gluPerspective(20.0f, 1.0f, 200.0f, 300.0f);		glGetFloatv(GL_MODELVIEW_MATRIX, modelProjectionMatrix);	glPopMatrix();}

Btw, this is what i tried to say in my first post, and i think is the same thing zedzeek suggested.

HellRaiZer

##### Share on other sites
THanks for the reply HellRaizer. Here is what I have put in your code you posted but now my frustum has disappeared...

void CTerrain::StoreLightMatrix(void){	float g_CameraDir[3] = {g_Camera.m_vView.x - g_Camera.m_vPosition.x,							g_Camera.m_vView.y - g_Camera.m_vPosition.y,							g_Camera.m_vView.z - g_Camera.m_vPosition.z};	float g_LightDirection[3] = {lightPosition[0] - g_Camera.m_vPosition.x,								 lightPosition[1] - g_Camera.m_vPosition.y,								 lightPosition[2] - g_Camera.m_vPosition.z};	float g_LightDistance = lightPosition[1] - 0.0f;	float g_LightLookAtOffset = 0.0f;	memset(modelViewMatrix, 0, sizeof(float) * 16);	memset(modelProjectionMatrix, 0, sizeof(float) * 16);	float pointInFrontOfCamera[3] = {g_Camera.m_vPosition.x + g_CameraDir[0] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.y + g_CameraDir[1] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.z + g_CameraDir[2] * g_LightLookAtOffset};    float lightPosition[3] = {pointInFrontOfCamera[0] - g_LightDirection[0] * g_LightDistance,                               pointInFrontOfCamera[1] - g_LightDirection[1] * g_LightDistance,                               pointInFrontOfCamera[2] - g_LightDirection[2] * g_LightDistance};	glPushMatrix();		glPushMatrix();			glLoadIdentity();			gluLookAt(lightPosition[0],  lightPosition[1],  lightPosition[2], pointInFrontOfCamera[0], pointInFrontOfCamera[1], pointInFrontOfCamera[2], 0.0, 1.0, 0.0);			glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);		glPopMatrix();		glLoadIdentity();		gluPerspective(20.0f, 1.0f, 200.0f, 300.0f);		glGetFloatv(GL_MODELVIEW_MATRIX, modelProjectionMatrix);	glPopMatrix();}

Hmm if I make my the g_LightDistance .5 then the frustum shows up. So I am assuming I need to normalize the value?

##### Share on other sites
Make sure the near plane of your directional orthographic projection is far enough away from the camera frustrum so you don t miss some geometry.

Just imagine you were walking through new york city and the orthographic frustrum

would cut the sky scrapers in the middle, some faces would not be shaded then.

##### Share on other sites
Quote:
 Original post by BasirorMake sure the near plane of your directional orthographic projection is far enough away from the camera frustrum so you don t miss some geometry.Just imagine you were walking through new york city and the orthographic frustrumwould cut the sky scrapers in the middle, some faces would not be shaded then.

I am still using a perspective projection. I couldn't get the orhto version to work. I thought I only needed to change the gluPerspective call to gluOrtho2D and that was it, but apparently not. So I am assuming the method to calculate the shadowmatrix is different also?

##### Share on other sites
First of all, usually when i think about direction vector, i always think them normalized, so sorry for not mentioning this.

I think in the code you posted there is something wrong.
In my code i assumed that the light direction is known (e.g. for a directional light like the sun). When you calculate the direction from the light's position and the camera position, and subtract it afterwards from then point in front of camera (which is the camera position btw, because you set g_LightLookAtOffset = 0.0f), the result is the inverse light position.

The whole thing gets a little bit more complex than it actually is. Try this.
Instead of calculating the light direction, set it to a constant values (like (-1, -1, 0)). Don't set it to (0, -1, 0) because there is a singularity with the up vector (0, 1, 0). Remember to normalize the direction vectors, in case to be able to thing in world space coordinates.

I think this will work. Remember to set the light distance to a correct value, so the near and far planes you specify in gluPespective() make sense. E.g. from your code i would suggest setting it to something around 250.0.

Hope the above makes sense. If not, just ask.

HellRaiZer

##### Share on other sites
Thanks for the help so far HellRaiZer. I am getting frustrated due to I can't figure this out and seems to me it should be very simple to do and I can't do it... With this code the frustum is vertical up and down...

void CTerrain::StoreLightMatrix(void){	float g_CameraDir[3] = {g_Camera.m_vView.x - g_Camera.m_vPosition.x,							g_Camera.m_vView.y - g_Camera.m_vPosition.y,							g_Camera.m_vView.z - g_Camera.m_vPosition.z};	float dp = 1 / (float)sqrt(g_CameraDir[0] * g_CameraDir[0] + g_CameraDir[1] * g_CameraDir[1] + g_CameraDir[2] * g_CameraDir[2]);	g_CameraDir[0] *= dp;	g_CameraDir[1] *= dp;	g_CameraDir[2] *= dp;	/*float g_LightDirection[3] = {lightPosition[0] - g_Camera.m_vPosition.x,								 lightPosition[1] - g_Camera.m_vPosition.y,								 lightPosition[2] - g_Camera.m_vPosition.z};	dp = 1 / (float)sqrt(g_LightDirection[0] * g_LightDirection[0] + g_LightDirection[1] * g_LightDirection[1] + g_LightDirection[2] * g_LightDirection[2]);	g_LightDirection[0] *= dp;	g_LightDirection[1] *= dp;	g_LightDirection[2] *= dp;*/	float g_LightDirection[3] = {-1.0f, -1.0f, 0.0f};	dp = 1 / (float)sqrt(g_LightDirection[0] * g_LightDirection[0] + g_LightDirection[1] * g_LightDirection[1] + g_LightDirection[2] * g_LightDirection[2]);	g_LightDirection[0] *= dp;	g_LightDirection[1] *= dp;	g_LightDirection[2] *= dp;	float g_LightDistance = lightPosition[1] - g_Camera.m_vPosition.y;	dp = 1 / (float)sqrt(g_LightDistance * g_LightDistance);	g_LightDistance *= dp;   	float g_LightLookAtOffset = 1.0f;	memset(modelViewMatrix, 0, sizeof(float) * 16);	memset(modelProjectionMatrix, 0, sizeof(float) * 16);	float pointInFrontOfCamera[3] = {g_Camera.m_vPosition.x + g_CameraDir[0] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.y + g_CameraDir[1] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.z + g_CameraDir[2] * g_LightLookAtOffset};    float lightPosition[3] = {pointInFrontOfCamera[0] - g_LightDirection[0] * g_LightDistance,                               pointInFrontOfCamera[1] - g_LightDirection[1] * g_LightDistance,                               pointInFrontOfCamera[2] - g_LightDirection[2] * g_LightDistance};	glPushMatrix();		glPushMatrix();			glLoadIdentity();			gluLookAt(lightPosition[0],  lightPosition[1],  lightPosition[2], pointInFrontOfCamera[0], pointInFrontOfCamera[1], pointInFrontOfCamera[2], 0.0, 1.0, 0.0);			glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);		glPopMatrix();		glLoadIdentity();		gluPerspective(20.0f, 1.0f, 2.0f, 300.0f);		glGetFloatv(GL_MODELVIEW_MATRIX, modelProjectionMatrix);	glPopMatrix();}

Please bare with my misunderstanding if you all can!

##### Share on other sites
Ok with this code the frustum cube is now from what I can tell centered on my view and positioned behind me a tad bit due to the -10.0f for the offset amount. Now the problem is when I rotate my camera so I can see the shadows myself the shadows move and get longer if I rotate the view up and down, and the frustum doesn't move either when I rotate it...

void CTerrain::StoreLightMatrix(void){	float g_CameraDir[3] = {g_Camera.m_vView.x - g_Camera.m_vPosition.x,							g_Camera.m_vView.y - g_Camera.m_vPosition.y,							g_Camera.m_vView.z - g_Camera.m_vPosition.z};	float dp = 1 / (float)sqrt(g_CameraDir[0] * g_CameraDir[0] + g_CameraDir[1] * g_CameraDir[1] + g_CameraDir[2] * g_CameraDir[2]);	g_CameraDir[0] *= dp;	g_CameraDir[1] *= dp;	g_CameraDir[2] *= dp;	float g_LightDirection[3] = {lightPosition[0] - g_Camera.m_vPosition.x,								 lightPosition[1] - g_Camera.m_vPosition.y,								 lightPosition[2] - g_Camera.m_vPosition.z};	dp = 1 / (float)sqrt(g_LightDirection[0] * g_LightDirection[0] + g_LightDirection[1] * g_LightDirection[1] + g_LightDirection[2] * g_LightDirection[2]);	g_LightDirection[0] *= dp;	g_LightDirection[1] *= dp;	g_LightDirection[2] *= dp;		float g_LightDistance = lightPosition[0] - g_Camera.m_vPosition.x;	dp = 1 / (float)sqrt(g_LightDistance * g_LightDistance);	g_LightDistance *= dp;   	float g_LightLookAtOffset = -10.0f;	float pointInFrontOfCamera[3] = {g_Camera.m_vPosition.x + g_CameraDir[0] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.y + g_CameraDir[1] * g_LightLookAtOffset,                                      g_Camera.m_vPosition.z + g_CameraDir[2] * g_LightLookAtOffset};    float lightPosition[3] = {pointInFrontOfCamera[0] - g_LightDirection[0] * g_LightDistance,                               pointInFrontOfCamera[1] - g_LightDirection[1] * g_LightDistance,                               pointInFrontOfCamera[2] - g_LightDirection[2] * g_LightDistance};	memset(modelViewMatrix, 0, sizeof(float) * 16);	memset(modelProjectionMatrix, 0, sizeof(float) * 16);	glPushMatrix();		glPushMatrix();			glLoadIdentity();			gluLookAt(lightPosition[0],  lightPosition[1],  lightPosition[2], pointInFrontOfCamera[0], pointInFrontOfCamera[1], pointInFrontOfCamera[2], 0.0, 1.0, 0.0);			glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);		glPopMatrix();		glLoadIdentity();		gluPerspective(65.0f, 1.0f, 10.0f, 100.0f);		glGetFloatv(GL_MODELVIEW_MATRIX, modelProjectionMatrix);	glPopMatrix();}

##### Share on other sites
Could someone tell me if the behavior I stated in the previous posting is fixable? If not then this method of following my camera around isn't going to work. I need to have the frustum follow and when I rotate my view around in a circle the frustum needs to follow that also. The issue I am starting to see as of now is that when I rotate my camera when I stop moving the shadows move also and that is incorrect behavior. I need the shadows to stay static when rotating and moving around, but maybe this isn't possible with what we were trying to accomplish? Thanks

##### Share on other sites
Quote:
 Ok with this code the frustum cube is now from what I can tell centered on my view and positioned behind me a tad bit due to the -10.0f for the offset amount. Now the problem is when I rotate my camera so I can see the shadows myself the shadows move and get longer if I rotate the view up and down, and the frustum doesn't move either when I rotate it.

This is normal behavior because you are using a focus point other than the camera's position. One thing i must say is that in case to have a point in front of the camera you need to set g_LightLookAtOffset to a positive value.

The point in front of camera is suppose to give better resolution for the things in front of the camera, and not for all the things surrounding the camera. If you do that, and you rotate the camera, this focus point will change and this will result in shadow movement.

If you can't live with the shadow movement (i don't know how bad it is), then you have to set g_LightLookAtOffset to 0. BUT, make sure you don't have a light direction parallel to the up vector. If you do, then gluLookAt will fail. gluLookAt does a cross product between the view direction and the up vector, in case to find a perpendicular right vector (build the third coord axis from the other two). Then it does another cross product between the view dir and the right vec in case to find the correct up vector. If the two vectors are parallel, then the cross product will be zero (rightVec = (0,0,0)). Which means the "correct" up vector will be zero. Unfortunatelly that's not a coord system (two axis are zero vector).
That's why i suggested using a constant light direction, instead of specifying light's position, and then calc the light dir from that.

Will this shadowmap focusing thing work? I don't know. You have to test it with your scene and see for yourself. Or maybe someone else can confirm that. But i suspect there will be errors when tall things are in the light view. I think Basiror mentioned this.

HellRaiZer

##### Share on other sites
HellRaiZer thanks for the reply. As of now I don't know for sure if this is going to work or not... I don't like the shadows moving around the screen. What other options does one have though for this situation. I was suggested to use this method and tried it and it isn't perfect or realistic from a gamers stand point. I can say the shadows do look better with the frustum following the camera around ALOT better quality. I heard about doing per patch but that will add in the problem of overlapping and making sure you line up each one so there isn't seam issues or bleeding over. I can't remember for sure but is it cascading shadowmapping??? that others are looking at for large terrain areas? What if any shadowmapping are you all using for larger outdoor areas?

##### Share on other sites
Ok, I got it working for the most part with the help of everyone here. Thanks a million. I know have tried to switch back to rendering my terrain with my objects in the shadowmap pass to try and do self shadowing. Well it looks like crap to be frank. I see banding lines and the shadows jiggle a bit. I have a simple ray tracer that I pre-compute at load time and use that as a lightmap and looks way better. I have tried the polygonoffset no luck, I have tried to render backfaces of my terrain no luck... So I was wondering what else is there one can do to fix that? Thanks

##### Share on other sites
any chance of some images of it going wrong?

##### Share on other sites
Quote:
 Original post by phantomany chance of some images of it going wrong?

Ah Phantom... Always wanting me to take screenshots. ;) I will try to this weekend, I have to work in 5hrs...

##### Share on other sites
*chuckles* I find it easier to see whats going on when I can visualise the problem [razz]

## 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

• ### Forum Statistics

• Total Topics
627736
• Total Posts
2978856

• 10
• 10
• 21
• 14
• 12