protected void RenderTextureShadowOnGeometry()
{
// no world transform required
targetRenderSystem.WorldMatrix = Matrix4.Identity;
// Set view / proj
targetRenderSystem.ViewMatrix = cameraInProgress.ViewMatrix;
targetRenderSystem.ProjectionMatrix = cameraInProgress.ProjectionMatrix;
Camera shadowCam = null;
Vector3 camPos = Vector3.Zero, camDir = Vector3.Zero;
TextureUnitState shadowTex = shadowReceiverPass.GetTextureUnitState( 0 );
for ( int i = 0; i < shadowTex.NumEffects; i++ )
{
if ( shadowTex.GetEffect( i ).type == TextureEffectType.ProjectiveTexture )
{
shadowCam = (Camera)shadowTex.GetEffect( i ).frustum;
camPos = shadowCam.DerivedPosition;
camDir = shadowCam.DerivedDirection;
break;
}
}
CullingMode prevCullMode = shadowReceiverPass.CullingMode;
LayerBlendModeEx colorBlend = shadowTex.ColorBlendMode;
LayerBlendSource prevSource = colorBlend.source2;
ColorEx prevColorArg = colorBlend.colorArg2;
// Quake uses counter-clockwise culling
shadowReceiverPass.CullingMode = CullingMode.CounterClockwise;
colorBlend.source2 = LayerBlendSource.Manual;
colorBlend.colorArg2 = ColorEx.White;
SetPass( shadowReceiverPass );
shadowReceiverPass.CullingMode = prevCullMode;
colorBlend.source2 = prevSource;
colorBlend.colorArg2 = prevColorArg;
// Empty existing cache
renderOp.indexData.indexCount = 0;
// lock index buffer ready to receive data
unsafe
{
uint* pIdx = (uint*)renderOp.indexData.indexBuffer.Lock( BufferLocking.Discard );
// For each material in turn, cache rendering data
IEnumerator mapEnu = matFaceGroupMap.Keys.GetEnumerator();
while ( mapEnu.MoveNext() )
{
// Get Material
Material thisMaterial = (Material)mapEnu.Current;
BspStaticFaceGroup[] faceGrp = matFaceGroupMap[ thisMaterial ].ToArray();
// if one face group is a quake shader then the material is a quake shader
if ( faceGrp[ 0 ].isQuakeShader )
continue;
for ( int i = 0; i < faceGrp.Length; i++ )
{
float dist = faceGrp[ i ].plane.GetDistance( camPos );
float angle = faceGrp[ i ].plane.Normal.Dot( camDir );
if ( ( ( dist < 0 && angle > 0 ) || ( dist > 0 && angle < 0 ) ) &&
Utility.Abs( angle ) >= Utility.Cos( shadowCam.FieldOfView * 0.5f ) )
{
// face is in shadow's frustum
// Cache each
int numElems = CacheGeometry( (IntPtr)pIdx, faceGrp[ i ] );
renderOp.indexData.indexCount += numElems;
pIdx += numElems;
}
}
}
}
// Unlock the buffer
renderOp.indexData.indexBuffer.Unlock();
// Skip if no faces to process
if ( renderOp.indexData.indexCount == 0 )
return;
targetRenderSystem.Render( renderOp );
}