Shadowmapping with Large terrains part 2

Started by
22 comments, last by _the_phantom_ 17 years, 10 months ago
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
HellRaiZer
Advertisement
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?
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.
http://www.8ung.at/basiror/theironcross.html
Quote:Original post by Basiror
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.


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?
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
HellRaiZer
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!
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();}

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

HellRaiZer
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?

This topic is closed to new replies.

Advertisement