Axiom.Core.Light.GetNearClipVolume C# (CSharp) Method

GetNearClipVolume() private method

Internal method for calculating the 'near clip volume', which is the volume formed between the near clip rectangle of the camera and the light.
This volume is a pyramid for a point/spot light and a cuboid for a directional light. It can used to detect whether an object could be casting a shadow on the viewport. Note that the reference returned is to a shared volume which will be reused across calls to this method.
private GetNearClipVolume ( Camera camera ) : PlaneBoundedVolume
camera Camera
return Axiom.Math.PlaneBoundedVolume
		internal virtual PlaneBoundedVolume GetNearClipVolume( Camera camera )
		{
			const float THRESHOLD = -1e-06f;

			float n = camera.Near;

			// First check if the light is close to the near plane, since
			// in this case we have to build a degenerate clip volume
			this.nearClipVolume.planes.Clear();
			this.nearClipVolume.outside = PlaneSide.Negative;

			// Homogenous position
			Vector4 lightPos = this.GetAs4DVector();
			// 3D version (not the same as DerivedPosition, is -direction for
			// directional lights)
			Vector3 lightPos3 = new Vector3( lightPos.x, lightPos.y, lightPos.z );

			// Get eye-space light position
			// use 4D vector so directional lights still work
			Vector4 eyeSpaceLight = camera.ViewMatrix * lightPos;
			Matrix4 eyeToWorld = camera.ViewMatrix.Inverse();

			// Find distance to light, project onto -Z axis
			float d = eyeSpaceLight.Dot( new Vector4( 0, 0, -1, -n ) );

			if ( d > THRESHOLD || d < -THRESHOLD )
			{
				// light is not too close to the near plane
				// First find the worldspace positions of the corners of the viewport
				Vector3[] corners = camera.WorldSpaceCorners;

				// Iterate over world points and form side planes
				Vector3 normal = Vector3.Zero;
				Vector3 lightDir = Vector3.Zero;

				for ( int i = 0; i < 4; i++ )
				{
					// Figure out light dir
					lightDir = lightPos3 - ( corners[ i ] * lightPos.w );
					// Cross with anticlockwise corner, therefore normal points in
					// Note: C++ mod returns 3 for the first case where C# returns -1
					int test = i > 0 ? ( ( i - 1 ) % 4 ) : 3;

					normal = ( corners[ i ] - corners[ test ] ).Cross( lightDir );
					normal.Normalize();

					if ( d < THRESHOLD )
					{
						// invert normal
						normal = -normal;
					}
					// NB last param to Plane constructor is negated because it's -d
					this.nearClipVolume.planes.Add( new Plane( normal, normal.Dot( corners[ i ] ) ) );
				}

				// Now do the near plane plane
				if ( d > THRESHOLD )
				{
					// In front of near plane
					// remember the -d negation in plane constructor
					normal = eyeToWorld * -Vector3.UnitZ;
					normal.Normalize();
					this.nearClipVolume.planes.Add( new Plane( normal, -normal.Dot( camera.DerivedPosition ) ) );
				}
				else
				{
					// Behind near plane
					// remember the -d negation in plane constructor
					normal = eyeToWorld * Vector3.UnitZ;
					normal.Normalize();
					this.nearClipVolume.planes.Add( new Plane( normal, -normal.Dot( camera.DerivedPosition ) ) );
				}

				// Finally, for a point/spot light we can add a sixth plane
				// This prevents false positives from behind the light
				if ( this.type != LightType.Directional )
				{
					// Direction from light to centre point of viewport
					normal = ( eyeToWorld * new Vector3( 0, 0, -n ) ) - lightPos3;
					normal.Normalize();
					// remember the -d negation in plane constructor
					this.nearClipVolume.planes.Add( new Plane( normal, normal.Dot( lightPos3 ) ) );
				}
			}
			else
			{
				// light is close to being on the near plane
				// degenerate volume including the entire scene
				// we will always require light / dark caps
				this.nearClipVolume.planes.Add( new Plane( Vector3.UnitZ, -n ) );
				this.nearClipVolume.planes.Add( new Plane( -Vector3.UnitZ, n ) );
			}

			return this.nearClipVolume;
		}

Usage Example

Beispiel #1
0
		/// <summary>
		///		Internal method for rendering all the objects for a given light into the stencil buffer.
		/// </summary>
		/// <param name="light">The light source.</param>
		/// <param name="camera">The camera being viewed from.</param>
		protected virtual void RenderShadowVolumesToStencil( Light light, Camera camera )
		{
			// get the shadow caster list
			IList casters = this.FindShadowCastersForLight( light, camera );
			if ( casters.Count == 0 )
			{
				// No casters, just do nothing
				return;
			}

			// Set up scissor test (point & spot lights only)
			bool scissored = false;
			if ( light.Type != LightType.Directional &&
				 this.targetRenderSystem.Capabilities.HasCapability( Capabilities.ScissorTest ) )
			{
				// Project the sphere onto the camera
				float left, right, top, bottom;
				Sphere sphere = new Sphere( light.DerivedPosition, light.AttenuationRange );
				if ( camera.ProjectSphere( sphere, out left, out top, out right, out bottom ) )
				{
					scissored = true;
					// Turn normalised device coordinates into pixels
					int iLeft, iTop, iWidth, iHeight;
					this.currentViewport.GetActualDimensions( out iLeft, out iTop, out iWidth, out iHeight );
					int szLeft, szRight, szTop, szBottom;

					szLeft = (int)( iLeft + ( ( left + 1 ) * 0.5f * iWidth ) );
					szRight = (int)( iLeft + ( ( right + 1 ) * 0.5f * iWidth ) );
					szTop = (int)( iTop + ( ( -top + 1 ) * 0.5f * iHeight ) );
					szBottom = (int)( iTop + ( ( -bottom + 1 ) * 0.5f * iHeight ) );

					this.targetRenderSystem.SetScissorTest( true, szLeft, szTop, szRight, szBottom );
				}
			}

			this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment );

			// Can we do a 2-sided stencil?
			bool stencil2sided = false;

			if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.TwoSidedStencil ) &&
				 this.targetRenderSystem.Capabilities.HasCapability( Capabilities.StencilWrap ) )
			{
				// enable
				stencil2sided = true;
			}

			// Do we have access to vertex programs?
			bool extrudeInSoftware = true;

			bool finiteExtrude = !this.shadowUseInfiniteFarPlane ||
								 !this.targetRenderSystem.Capabilities.HasCapability(
									  Capabilities.InfiniteFarPlane );

			if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.VertexPrograms ) )
			{
				extrudeInSoftware = false;
				this.EnableHardwareShadowExtrusion( light, finiteExtrude );
			}
			else
			{
				this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );
			}

			// Add light to internal list for use in render call
			tmpLightList.Clear();
			tmpLightList.Add( light );

			// Turn off color writing and depth writing
			this.targetRenderSystem.SetColorBufferWriteEnabled( false, false, false, false );
			this.targetRenderSystem.DepthBufferWriteEnabled = false;
			this.targetRenderSystem.StencilCheckEnabled = true;
			this.targetRenderSystem.DepthBufferFunction = CompareFunction.Less;

			// Calculate extrusion distance
			float extrudeDistance = 0;
			if ( light.Type == LightType.Directional )
			{
				extrudeDistance = this.shadowDirLightExtrudeDist;
			}

			// get the near clip volume
			PlaneBoundedVolume nearClipVol = light.GetNearClipVolume( camera );

			// Determine whether zfail is required
			// We need to use zfail for ALL objects if we find a single object which
			// requires it
			bool zfailAlgo = false;

			this.CheckShadowCasters( casters,
									 nearClipVol,
									 light,
									 extrudeInSoftware,
									 finiteExtrude,
									 zfailAlgo,
									 camera,
									 extrudeDistance,
									 stencil2sided,
									 tmpLightList );
			// revert colour write state
			this.targetRenderSystem.SetColorBufferWriteEnabled( true, true, true, true );
			// revert depth state
			this.targetRenderSystem.SetDepthBufferParams();

			this.targetRenderSystem.StencilCheckEnabled = false;

			this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );

			if ( scissored )
			{
				// disable scissor test
				this.targetRenderSystem.SetScissorTest( false );
			}
		}