Infinite Projection Matrix

Started by
4 comments, last by L. Spiro 13 years, 10 months ago
I am trying to get shadow volumes working and am in need of an infinite far plane in my projection matrix.

I build a normal projection matrix with the following code:
	/**	 * Create a right-handed perspective projection matrix based on a field of view.	 *	 * \param _fFov Field of view in the y direction, in radians.	 * \param _fAspect Aspect ratio, defined as view space width divided by height.	 * \param _fNear Z-value of the near view-plane.	 * \param _fFar Z-value of the far view-plane.	 */	LSMVOID LSM_CALL CMatrix4x4::PerspectiveFovRH( LSMREAL _fFov, LSMREAL _fAspect, LSMREAL _fNear, LSMREAL _fFar ) {		// Zero out the ones that need to be zero.		_12 = _13 = _14 = LSM_ZERO;		_21 = _23 = _24 = LSM_ZERO;		_31 = _32 = LSM_ZERO;		_41 = _42 = _44 = LSM_ZERO;				LSMREAL fDist = LSM_ONE / (_fNear - _fFar);				// Set the remaining ones.		_22 = LSM_ONE / CMath::Tan( LSM_HALF * _fFov );		_11 = _22 / _fAspect;				_33 = (_fFar + _fNear) * fDist;		_34 = -LSM_ONE;				_43 = (LSM_TWO * _fFar * _fNear) * fDist;	}


This is row-major, as in DirectX®. _33 and _43 are the important values.


When I render my shadow volumes I basically do this:
_33 = LSM_FLT_EPSILON - LSM_ONE; // Standard machine epsilon here._43 = static_cast<LSMREAL>(0.2) * -LSM_TWO; // As an example, assume the near plane is at 0.2.


But no matter what values I set there I get clipping, and quite close to the camera. It actually clips at the near plane too, heavily noticeably.

I am extruding my shadow volume out at about 10,000 units. My regular far plane is at 2,000 units.


Any idea what I am doing wrong? The shadow volumes themselves are fine (as far as being correct geometry, but maybe I need to adjust how far I extrude them). If I use my normal projection, it works perfectly as long as I position my view so that none of the shadow volumes pass the far plane.


Thank you,
Yogurt Emperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Advertisement
This is what I do in my code for this purpose (shadow volumes).

	const float zNear = mat[3][2] / mat[2][2];	static const float epsilon = 0.0001f;	mat[2][2] = epsilon - 1.0f;	mat[3][2] = (zNear * 0.5f) * (epsilon - 2.0f);


This code works well for me.
The major difference seems to be that I'm using HALF the zNear value (also the epsilon is used for the second multiplier.

Cheers,
This is what I get with a normal projection matrix unmodified.

http://memoryhacking.com/Pictures/The%20Error.png


Your values are actually exactly the same as mine. My near plane is 0.2 but mat[3][2] / mat[2][2] returns 0.4 since I multiplied by LSM_TWO when I made the matrix. So when I apply your division by 2 it is the same as plugging in the actual near plane, which is what I was hardcoding.

This screenshot shows the result of that.

http://memoryhacking.com/Pictures/Error2.png

Those strips are hard to see, but easy to see when the game is in motion, since they stay the same distance away from the camera at all times. It is like they are parts of the shadow volume that are trapped inside a small region of clipping planes out in the distance.


Regards,
Yogurt Emperor

[Edited by - YogurtEmperor on June 14, 2010 8:44:46 PM]

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Is there some special way I should be extruding the vertices when making the shadow volume? I am only working with directional lights for the moment and my code follows. My vertex buffer has 2 halves, one set matching the terrain geometry where the terrain faces away from the light (front cap of my volume, closest to the light source) and an exact copy of those vertices for the second half (back cap, extruded away from the light). The vertices are connected via an index buffer which gives proper winding through the vertices in order to make a closed volume with the normal of each triangle facing inward towards the center of the box. The volume itself is correct. Extrusion code below.

// Triangles may have been generated or not.  At this point at least we know we need to extrude them away from the light source.//	Extrude the second half of the vertices only._cvsShadow.vbVertexBuffer.Lock();LSMUINT32 ui32Total = _cvsShadow.vbVertexBuffer.GetElements();LSMUINT32 ui32HalfTotal = ui32Total >> 1UL;switch ( _cvsShadow.ui32Type ) {	case LST_LT_DIRECTIONAL : {		CVector3 vDir = _cvsShadow.vDir * static_cast<LSMREAL>(30000.0);		for ( LSMUINT32 I = ui32HalfTotal; I < ui32Total; ++I ) {			LSGREAL * pfBaseVerts = _cvsShadow.vbVertexBuffer.GetVertex( I - ui32HalfTotal );			CVector3 vBaseVert( static_cast<LSMREAL>(pfBaseVerts[0]), static_cast<LSMREAL>(pfBaseVerts[1]),				static_cast<LSMREAL>(pfBaseVerts[2]) );			CVector3 vVert = vBaseVert + vDir;			_cvsShadow.vbVertexBuffer.SetVertex( I, static_cast<LSGREAL>(vVert.x),				static_cast<LSGREAL>(vVert.y), static_cast<LSGREAL>(vVert.z) );		}		break;	}}_cvsShadow.vbVertexBuffer.Unlock();



The correct vertices are being extruded, but should I pick a different extrusion amount?
Should I offset the vertices somehow?






[EDIT]
Using the depth-pass method my shadows work as expected. Including the bug caused by being inside the shadow volumes.
The only difference between the two methods is the stencil operation and the infinite projection matrix.
My depth-fail works as far as the stencil-operation is concerned, meaning the ONLY problem I am having should be related to the projection matrix, and that should be a very simple change which I have shown above and of which I have tried many variations.

Any ideas at all??
[/EDIT]

Thank you,
Yogurt Emperor

[Edited by - YogurtEmperor on June 15, 2010 3:00:53 AM]

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

I haven't read your code but one thing I seemed to remember (it was years since I wrote my stencil-shadow code) is that for the vertices that you extrude, you just set the .w value to zero, and for the ones you don't want to extrude keep it at one (default).
I.e, you don't need to manually manipulate your vertex positions.
I haven’t been able to find any tutorials that do that (in code), though I have seen mention of it.

But for me to give a meaningful reply I would have had to extend my vertex-buffer class with the ability to support a W coordinate, so it took some time.

But while adding support, I discovered that DirectX documentation says D3DFVF_XYZW is only for shaders.
Any way to do this in DirectX without shaders? I cannot find a single tutorial that:
#A: Uses depth fail.
#2: Does not use shaders.
#C: Does not take shortcuts (using a closed scene in which the camera far plane is guaranteed never to clip with the extruded geometry, therefore eliminating the need for this hassle).


I know this DirectX specific question could be better placed in a certain other section but I consider this a small part of a more general problem at hand, and I am working in OpenGL and DirectX equally (literally).
This is no problem with OpenGL of course.


Regards,
L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement