splitting frustum for shadowmaps

Started by
20 comments, last by AndyTX 16 years, 11 months ago
thx for all the suggestions...

the main bottle neck here is the problem with multiple renderpasses... would it be possible to render to all 3 shadowsmaps in a single pass with multiple rendertargets?
Advertisement
Quote:Original post by Dragon_Strike
the main bottle neck here is the problem with multiple renderpasses... would it be possible to render to all 3 shadowsmaps in a single pass with multiple rendertargets?

In DX10 using instancing or geometry shader cloning and the output render target index you can do this. You cannot in DX9 because you need to actually transform and rasterize the geometry differently each time.

I'm not sure how much more efficient it will be to do it in a single pass... arguably the CPU overhead of rendering a shadow map is pretty low anyways (few, if any state changes, and low draw call cost in DX10).
Here's some progress I've made, currently I project the 8 points of the view frusum shadow region into the light's space and set my orthogonal bounds to that.

Improvements: In the code you will notice I was going to clamp the depth map depth range to a world max and min. I decided to skip this and wait until I set the depth map bounds based on light space culled geometry. Or posibly upgrade to some perspective/warped light projection.

Image:


Video: Click (google video)

Source:
void cViewable::ConfigureDepthMaps(cDepthMap *maps, int mapcnt, float *lightdir){	//shadow targets	float vec[] = {0,0,0}, vec2[3];	Vector temp, targ, corners[8];	float clampedfar = min(farplane, 500);;	float range = clampedfar - nearplane; 	float *splits = 0;	splits = new float[mapcnt+1];	Matrix view, light;	for(int i = 0; i <= mapcnt; i++) 	{ 		float expo = i/(float)mapcnt; //3 steps: 0, .33, .66, 1 		float val10 = pow(10, expo); //10^expo , 1, 2.13, 4.57, 10 		float newinterp = (val10 - 1.0f) / 9.0f; //scale [1,10] to [0,1] 		splits = nearplane - range * newinterp; 	}	for(int i = 0; i < mapcnt; i++)	{					//far corners of shadow region		vec2[2] = splits[i+1]; //depth		vec2[1] = splits[i+1] * tang;	//height		vec2[0] = splits[i+1] * tang * ratio;	//width		corners[0].set(vec2);		vec2[2] = splits[i+1]; //depth		vec2[1] = splits[i+1] * tang;	//height		vec2[0] = -splits[i+1] * tang * ratio;	//width		corners[1].set(vec2);		vec2[2] = splits[i+1]; //depth		vec2[1] = -splits[i+1] * tang;	//height		vec2[0] = -splits[i+1] * tang * ratio;	//width		corners[2].set(vec2);		vec2[2] = splits[i+1]; //depth		vec2[1] = -splits[i+1] * tang;	//height		vec2[0] = splits[i+1] * tang * ratio;	//width		corners[3].set(vec2);		//near cornes of shadow region		vec2[2] = splits; //depth		vec2[1] = splits * tang;	//height		vec2[0] = splits * tang * ratio;	//width		corners[4].set(vec2);		vec2[2] = splits; //depth		vec2[1] = splits * tang;	//height		vec2[0] = -splits * tang * ratio;	//width		corners[5].set(vec2);		vec2[2] = splits; //depth		vec2[1] = -splits * tang;	//height		vec2[0] = -splits * tang * ratio;	//width		corners[6].set(vec2);		vec2[2] = splits; //depth		vec2[1] = -splits * tang;	//height		vec2[0] = splits * tang * ratio;	//width		corners[7].set(vec2);		//target		vec[0] = 0; //right down the pipe		vec[1] = 0; //height at center		vec[2] = (splits[i+1] + splits) / 2.0; //-Z		targ.set(vec);		//move targets to world coordinates		view.set(transposeMatrix);		targ.transform(view);		//set map at target		maps.SetTranslation(targ.m_vector);		maps.SetRollToAxis(lightdir);		light.set(maps.inverseT);		//move points into light space		float maxx = 0; //get x range		float minx = 0;		float maxy = 0; //y range		float miny = 0;		float maxd = 0; //depth range		float mind = 0;		//float maxheight = 0;		//float minheight = 0;		for(int p = 0; p < 8; p++)		{			corners.transform(view); //tranform to world space			//corners.m_vector[1] = max(minheight, min(maxheight, corners.m_vector[1])); 			corners.transform(light);			if (corners.m_vector[0] < minx) minx = corners.m_vector[0]; 			if (corners.m_vector[0] > maxx) maxx = corners.m_vector[0];			if (corners.m_vector[1] < miny) miny = corners.m_vector[1]; 			if (corners.m_vector[1] > maxy) maxy = corners.m_vector[1];			if (corners.m_vector[2] < mind) mind = corners.m_vector[2]; 			if (corners.m_vector[2] > maxd) maxd = corners.m_vector[2];		}				maps.SetSize(minx, maxx, miny, maxy);		maps.ChangeFarPlane(mind);		maps.ChangeNearPlane(maxd);	}	delete[] splits;}
im not all that good with matrix math.. even worse when its in code.. could u explain to me how u calculate the maxx,minx,maxy,miny bounds for the ortho projection?

u first find the 8 points defining the view volume to be included... then multiply these by the light's modelviewmatrix and get the max coordinates from these.. or something like that?
Quote:Original post by Dragon_Strike
u first find the 8 points defining the view volume to be included... then multiply these by the light's modelviewmatrix and get the max coordinates from these.. or something like that?


Close, you must multiply the points by the light's *inverse* modelview matrix, to transform the points into light space. Then yes, just find the range of coordinates in that space and set your ortho rectangle around them.

Just to clarify, what I mean by inverse modelview, would be the inverse translation and rotation of the light. You could use gluLookAt to generate this, though I do mine manually.
Quote:Original post by honayboyz
Quote:Original post by Dragon_Strike
u first find the 8 points defining the view volume to be included... then multiply these by the light's modelviewmatrix and get the max coordinates from these.. or something like that?


Close, you must multiply the points by the light's *inverse* modelview matrix, to transform the points into light space. Then yes, just find the range of coordinates in that space and set your ortho rectangle around them.

Just to clarify, what I mean by inverse modelview, would be the inverse translation and rotation of the light. You could use gluLookAt to generate this, though I do mine manually.


glulookat and glGetDoublev(GL_MODELVIEW_MATRIX, ViewMatrix); gives the inverse modelview then...?
Quote:warping scheme
AndyTX: warping usually increases depth aliasing ... only works with probability based shadows as long as they do not have light bleeding issues. This is the standard argument of game developers to not use any warping.
Quote:Original post by wolf
Quote:warping scheme
AndyTX: warping usually increases depth aliasing ... only works with probability based shadows as long as they do not have light bleeding issues. This is the standard argument of game developers to not use any warping.

I mean spatial (x/y) warping not depth warping. That shouldn't affect depth aliasing at all and is entirely unrelated to filtering (light bleeding, probabilistic, etc). The only thing to note is that if you warp the shadow map you also need to warp the filter kernels... this is automatically handled if you're using hardware filtering or derivatives, but it needs to be done properly if you're - for example - prefiltering the shadow map.

Depth warping is interesting in its own right, but it's unrelated to this discussion.

In any case I tend to agree that spatial warping is overkill for most cases, but it's a technique that's available and the benefits and trade-off are discussed in depth in the "Warping and Partitioning for Low Error Shadow Maps" paper.
ok ive tried calculating the view frusutm points from the lightsmodelviewmatrix... its ok.. but its not right.. this is how it looks...

Image Hosted by ImageShack.us

as u can see it doesnt incldue the entire viewfrustum...

the big yellow sphere is the lightpos... the 8 green spheres are the viewpoints that are to be bound...

here is the code

>
					mat4 ModelView(ViewMatrix[0],ViewMatrix[1],ViewMatrix[2],ViewMatrix[3],				           ViewMatrix[4],ViewMatrix[5],ViewMatrix[6],ViewMatrix[7],						   ViewMatrix[8],ViewMatrix[9],ViewMatrix[10],ViewMatrix[11],						   ViewMatrix[12],ViewMatrix[13],ViewMatrix[14],ViewMatrix[15]);	                        // FurstumPoints[] n 0 -> 7, gives the 8 poitns to be bound			for (int n = 0; n < 8; n++)			{				RenderSphere(FurstumPoints[n], 5.0f, 10,10);				FurstumPoints[n] = FurstumPoints[n] * ModelView;						}						maxx = 0;			minx = 0;			maxy = 0;			miny = 0;			maxz = 0;			minz = 0;			for (int n = 0; n < 8; n++)			{				maxx = max(maxx, FurstumPoints[n].x);				minx = min(minx, FurstumPoints[n].x);					maxy = max(maxy, FurstumPoints[n].y);				miny = min(miny, FurstumPoints[n].y);				maxz = max(maxz, FurstumPoints[n].z);				minz = min(minz, FurstumPoints[n].z);				}float Matrix[16];        	mat4(float _0, float _1, float _2, float _3,			float _4, float _5, float _6, float _7,			float _8, float _9, float _10, float _11,			float _12, float _13, float _14, float _15)		{			Matrix[0] = _0; Matrix[1] = _1; Matrix[2] = _2; Matrix[3] = _3;  			Matrix[4] = _4; Matrix[5] = _5; Matrix[6] = _6; Matrix[7] = _7;  			Matrix[8] = _8; Matrix[9] = _9; Matrix[10] = _10; Matrix[11] = _11;  			Matrix[12] = _12; Matrix[13] = _13; Matrix[14] = _14; Matrix[15] = _15;  		}		mat4 operator*(const mat4& mat) const		{			const float* m1 = this->Matrix;			const float* m2 = mat.Matrix;			return mat4(			(m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]),			(m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]),			(m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]),			(m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]),			(m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]),			(m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]),			(m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]),			(m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]),			(m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]),			(m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]),			(m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]),			(m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]),			(m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]),			(m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]),			(m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]),			(m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]));		}
Quote:Original post by Dragon_Strike
ok ive tried calculating the view frusutm points from the lightsmodelviewmatrix... its ok.. but its not right.. this is how it looks...

You need to actually PROJECT the points into shadow map space (and divide by w) before computing the screen-space extents. Code is available in the various PSSM demos.

This topic is closed to new replies.

Advertisement