public void Initialize(RenderView renderView, RenderLight renderLight, IDirectLight light, LightShadowMap shadowMap, int size, ILightShadowMapRenderer renderer) { if (renderView == null) { throw new ArgumentNullException(nameof(renderView)); } if (renderLight == null) { throw new ArgumentNullException(nameof(renderLight)); } if (light == null) { throw new ArgumentNullException(nameof(light)); } if (shadowMap == null) { throw new ArgumentNullException(nameof(shadowMap)); } if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } RenderView = renderView; RenderLight = renderLight; Light = light; Shadow = shadowMap; Size = size; FilterType = Shadow.Filter == null || !Shadow.Filter.RequiresCustomBuffer() ? null : Shadow.Filter.GetType(); Renderer = renderer; Atlas = null; // Reset the atlas, It will be setup after CascadeCount = 1; ShadowType = renderer.GetShadowType(Shadow); }
protected override void OnSceneManagementGetObjectsForShadowGeneration( Camera camera, RenderLight light, Set<SceneNode> outSceneNodes, Set<StaticMeshObject> outStaticMeshObjects ) { float farClipDistance = NearFarClipDistance.Maximum; LowLevelSceneManagement.WalkForShadowGeneration( camera, light, farClipDistance, outSceneNodes, outStaticMeshObjects ); }
public LightShadowMapTexture FindShadowMap(RenderView renderView, RenderLight light) { foreach (var shadowMap in shadowMaps) { if (shadowMap.RenderView == renderView && shadowMap.RenderLight == light) { return(shadowMap); } } return(null); }
public static void WalkForShadowGeneration( Camera camera, RenderLight light, float farClipDistance, Set<SceneNode> outSceneNodes, Set<StaticMeshObject> outStaticMeshObjects) { switch( light.Type ) { case RenderLightType.Spot: WalkSpotLightShadowGeneration( camera, light, outSceneNodes, outStaticMeshObjects ); break; case RenderLightType.Point: WalkPointLightShadowGeneration( camera, light, outSceneNodes, outStaticMeshObjects ); break; case RenderLightType.Directional: WalkDirectionalLightShadowGeneration( camera, light, farClipDistance, outSceneNodes, outStaticMeshObjects ); break; } }
void GetShadowCastersForLight( Camera mainCamera, RenderLight light, int directionalLightPSSMTextureIndex, Vec3 pointLightFaceDirection, List<SceneNode> outSceneNodes, List<StaticMeshObject> outStaticMeshObjects ) { switch( light.Type ) { case RenderLightType.Spot: WalkSpotLightShadowGeneration( mainCamera, light, outSceneNodes, outStaticMeshObjects ); break; case RenderLightType.Point: WalkPointLightShadowGeneration( mainCamera, light, pointLightFaceDirection, outSceneNodes, outStaticMeshObjects ); break; case RenderLightType.Directional: WalkDirectionalLightShadowGeneration( mainCamera, light, directionalLightPSSMTextureIndex, outSceneNodes, outStaticMeshObjects ); break; } }
public bool Update(RenderLight light) => true;
public virtual LightShadowMapTexture CreateShadowMapTexture(RenderView renderView, RenderLight renderLight, IDirectLight light, int shadowMapSize) { var shadowMap = shadowMaps.Add(); shadowMap.Initialize(renderView, renderLight, light, light.Shadow, shadowMapSize, this); return(shadowMap); }
static bool IsIntersects( RenderLight light, Bounds bounds ) { if( light.Type == RenderLightType.Point || light.Type == RenderLightType.Spot ) { //check by bounding sphere { Sphere lightSphere = new Sphere( light.Position, light.AttenuationFar ); if( !lightSphere.IsIntersectsBounds( ref bounds ) ) return false; } //check by spot light clip planes if( light.Type == RenderLightType.Spot ) { Vec3 boundsCenter = bounds.GetCenter(); Vec3 boundsHalfSize = boundsCenter - bounds.Minimum; foreach( Plane plane in light.SpotLightClipPlanes ) { if( plane.GetSide( ref boundsCenter, ref boundsHalfSize ) == Plane.Side.Positive ) return false; } } } return true; }
static Plane[] GetClipPlanesForPointLightShadowGeneration( Camera mainCamera, RenderLight light, Vec3 pointLightFaceDirection ) { Plane[] clipPlanes = new Plane[ 5 ]; Vec3 direction = pointLightFaceDirection; float attenuationRange = light.AttenuationFar; Vec3[] points = new Vec3[ 4 ]; if( direction.Equals( Vec3.XAxis, .01f ) ) { points[ 0 ] = new Vec3( 1, -1, -1 ); points[ 1 ] = new Vec3( 1, -1, 1 ); points[ 2 ] = new Vec3( 1, 1, 1 ); points[ 3 ] = new Vec3( 1, 1, -1 ); clipPlanes[ 4 ] = new Plane( direction, light.Position.X + attenuationRange ); } else if( direction.Equals( -Vec3.XAxis, .01f ) ) { points[ 0 ] = new Vec3( -1, 1, -1 ); points[ 1 ] = new Vec3( -1, 1, 1 ); points[ 2 ] = new Vec3( -1, -1, 1 ); points[ 3 ] = new Vec3( -1, -1, -1 ); clipPlanes[ 4 ] = new Plane( direction, -( light.Position.X - attenuationRange ) ); } else if( direction.Equals( Vec3.YAxis, .01f ) ) { points[ 0 ] = new Vec3( 1, 1, -1 ); points[ 1 ] = new Vec3( 1, 1, 1 ); points[ 2 ] = new Vec3( -1, 1, 1 ); points[ 3 ] = new Vec3( -1, 1, -1 ); clipPlanes[ 4 ] = new Plane( direction, light.Position.Y + attenuationRange ); } else if( direction.Equals( -Vec3.YAxis, .01f ) ) { points[ 0 ] = new Vec3( -1, -1, -1 ); points[ 1 ] = new Vec3( -1, -1, 1 ); points[ 2 ] = new Vec3( 1, -1, 1 ); points[ 3 ] = new Vec3( 1, -1, -1 ); clipPlanes[ 4 ] = new Plane( direction, -( light.Position.Y - attenuationRange ) ); } else if( direction.Equals( Vec3.ZAxis, .01f ) ) { points[ 0 ] = new Vec3( -1, 1, 1 ); points[ 1 ] = new Vec3( 1, 1, 1 ); points[ 2 ] = new Vec3( 1, -1, 1 ); points[ 3 ] = new Vec3( -1, -1, 1 ); clipPlanes[ 4 ] = new Plane( direction, light.Position.Z + attenuationRange ); } else if( direction.Equals( -Vec3.ZAxis, .01f ) ) { points[ 0 ] = new Vec3( -1, -1, -1 ); points[ 1 ] = new Vec3( 1, -1, -1 ); points[ 2 ] = new Vec3( 1, 1, -1 ); points[ 3 ] = new Vec3( -1, 1, -1 ); clipPlanes[ 4 ] = new Plane( direction, -( light.Position.Z - attenuationRange ) ); } else { Log.Fatal( "MyRenderingLowLevelMethods: GetClipPlanesForPointLightShadowGeneration: Internal error." ); } for( int n = 0; n < 4; n++ ) { clipPlanes[ n ] = Plane.FromPoints( light.Position, light.Position + points[ n ], light.Position + points[ ( n + 1 ) % 4 ] ); } return clipPlanes; }
public override void OnGetShadowmapCameraSetup( Camera mainCamera, RenderLight light, int directionalLightPSSMTextureIndex, int pointLightFaceIndex, Camera lightCamera, ref bool skipThisShadowmap ) { if( light.Type == RenderLightType.Directional ) { //Directional light float orthoWindowSize; Vec3 lightCameraPosition; Vec3 lightCameraUp; Vec3[] cornerPoints; { if( SceneManager.Instance.IsShadowTechniquePSSM() ) { float[] splitDistances = SceneManager.Instance.ShadowDirectionalLightSplitDistances; float nearSplitDistance = splitDistances[ directionalLightPSSMTextureIndex ]; float farSplitDistance = splitDistances[ directionalLightPSSMTextureIndex + 1 ]; bool lastTextureIndex = directionalLightPSSMTextureIndex == SceneManager.Instance.ShadowDirectionalLightSplitTextureCount - 1; GetDirectionalLightCameraCornerPoints( mainCamera, nearSplitDistance, farSplitDistance, lastTextureIndex, out cornerPoints ); } else { GetDirectionalLightCameraCornerPoints( mainCamera, mainCamera.NearClipDistance, SceneManager.Instance.ShadowFarDistance, true, out cornerPoints ); } } Vec3 destinationPoint = GetDirectionalLightCameraDestinationPoint( mainCamera, cornerPoints ); lightCameraPosition = destinationPoint - light.Direction * directionalLightExtrusionDistance; lightCameraUp = Vec3.ZAxis; if( Math.Abs( Vec3.Dot( lightCameraUp, light.Direction ) ) >= .99f ) lightCameraUp = Vec3.YAxis; float maxDistance = 0; { foreach( Vec3 point in cornerPoints ) { float distance = ( point - destinationPoint ).Length(); if( distance > maxDistance ) maxDistance = distance; } } orthoWindowSize = maxDistance * 2 * 1.05f; //fix epsilon error orthoWindowSize = ( (int)( orthoWindowSize / 5 ) ) * 5 + 5; //fix jittering { Quat lightRotation = Quat.FromDirectionZAxisUp( light.Direction ); //convert world space camera position into light space Vec3 lightSpacePos = lightRotation.GetInverse() * lightCameraPosition; //snap to nearest texel float textureSize = SceneManager.Instance.ShadowDirectionalLightTextureSize; float worldTexelSize = orthoWindowSize / textureSize; lightSpacePos.Y -= (float)Math.IEEERemainder( lightSpacePos.Y, worldTexelSize ); lightSpacePos.Z -= (float)Math.IEEERemainder( lightSpacePos.Z, worldTexelSize ); //convert back to world space lightCameraPosition = lightRotation * lightSpacePos; } lightCamera.ProjectionType = ProjectionTypes.Orthographic; lightCamera.AspectRatio = 1; lightCamera.OrthoWindowHeight = orthoWindowSize; lightCamera.NearClipDistance = mainCamera.NearClipDistance; lightCamera.FarClipDistance = shadowMapFarClipDistance; lightCamera.Position = lightCameraPosition; lightCamera.FixedUp = lightCameraUp; lightCamera.Direction = light.Direction; } else if( light.Type == RenderLightType.Spot ) { //Spot light Degree fov = new Radian( light.SpotlightOuterAngle * 1.05f ).InDegrees(); if( fov > 179 ) fov = 179; Vec3 up = Vec3.ZAxis; if( Math.Abs( Vec3.Dot( up, light.Direction ) ) >= 1.0f ) up = Vec3.YAxis; lightCamera.ProjectionType = ProjectionTypes.Perspective; lightCamera.AspectRatio = 1; lightCamera.Fov = fov; lightCamera.NearClipDistance = mainCamera.NearClipDistance; lightCamera.FarClipDistance = shadowMapFarClipDistance;// light.AttenuationFar * 1.05f; lightCamera.Position = light.Position; lightCamera.FixedUp = up; lightCamera.Direction = light.Direction; } else { //Point light //you can completely skip specified faces for better performance. //use "skipThisShadowmap" parameter for this. //example: //if( pointLightFaceIndex == 3 ) // skipThisShadowmap = true; Vec3 dir = Vec3.Zero; Vec3 up = Vec3.Zero; switch( pointLightFaceIndex ) { case 0: dir = -Vec3.YAxis; up = Vec3.ZAxis; break; case 1: dir = Vec3.YAxis; up = Vec3.ZAxis; break; case 2: dir = Vec3.ZAxis; up = -Vec3.XAxis; break; case 3: dir = -Vec3.ZAxis; up = Vec3.XAxis; break; case 4: dir = Vec3.XAxis; up = Vec3.ZAxis; break; case 5: dir = -Vec3.XAxis; up = Vec3.ZAxis; break; } lightCamera.ProjectionType = ProjectionTypes.Perspective; lightCamera.AspectRatio = 1; lightCamera.Fov = 90; lightCamera.NearClipDistance = mainCamera.NearClipDistance; lightCamera.FarClipDistance = shadowMapFarClipDistance;// light.AttenuationFar * 1.05f; lightCamera.Position = light.Position; lightCamera.FixedUp = up; lightCamera.Direction = dir; } }
static Plane[] GetClipPlanesForDirectionalLightShadowGeneration( Camera camera, RenderLight light, float farClipDistance) { float shadowFarDistance = SceneManager.Instance.ShadowFarDistance; Frustum cameraFrustum = FrustumUtils.GetFrustumByCamera( camera, farClipDistance ); Vec3 cameraPosition = cameraFrustum.Origin; Vec3 farCenterPoint; { float distance = shadowFarDistance; //small border distance *= 1.05f; //not optimal distance *= MathFunctions.Sqrt( 2 ); farCenterPoint = cameraPosition + cameraFrustum.Axis.Item0 * distance; } Vec3 pyramidCenter = ( cameraPosition + farCenterPoint ) * .5f; Plane farPlane; { Vec3 normal = ( farCenterPoint - cameraPosition ).GetNormalize(); float distance = Vec3.Dot( normal, farCenterPoint ); farPlane = new Plane( normal, distance ); } Vec3[] farCorners = new Vec3[ 4 ]; { //4 - top-right far, 5 - top-left far, 6 - bottom-left far, 7 - bottom-right far. Vec3[] points = camera.GetWorldSpaceCorners(); for( int n = 0; n < 4; n++ ) { Ray ray = new Ray( cameraPosition, points[ n + 4 ] - cameraPosition ); float scale; farPlane.RayIntersection( ray, out scale ); farCorners[ n ] = ray.GetPointOnRay( scale ); } } Vec3[] pyramidPoints = new Vec3[ 5 ]; { pyramidPoints[ 0 ] = cameraPosition; for( int n = 0; n < 4; n++ ) pyramidPoints[ n + 1 ] = farCorners[ n ]; } Line[] pyramidEdges = new Line[ 8 ]; { for( int n = 0; n < 4; n++ ) { pyramidEdges[ n ] = new Line( cameraPosition, farCorners[ n ] ); pyramidEdges[ n + 4 ] = new Line( farCorners[ n ], farCorners[ ( n + 1 ) % 4 ] ); } } List<Plane> clipPlanes = new List<Plane>( 7 ); { Vec3 lightDirectionOffset = light.Direction * 10000.0f; //back planes { if( farPlane.GetSide( farCenterPoint - lightDirectionOffset ) == Plane.Side.Negative ) { clipPlanes.Add( farPlane ); } for( int n = 0; n < 4; n++ ) { Plane plane = Plane.FromPoints( cameraPosition, farCorners[ n ], farCorners[ ( n + 1 ) % 4 ] ); if( plane.GetSide( cameraPosition - lightDirectionOffset ) == Plane.Side.Negative ) { clipPlanes.Add( farPlane ); } } } //generate edge planes foreach( Line pyramidEdge in pyramidEdges ) { Vec3 p1 = pyramidEdge.Start; Vec3 p2 = pyramidEdge.End; Vec3 p3 = p1 - lightDirectionOffset; Plane plane; { plane = Plane.FromPoints( p1, p2, p3 ); if( plane.GetSide( pyramidCenter ) == Plane.Side.Positive ) plane = Plane.FromPoints( p2, p1, p3 ); } bool existsPyramidPointsOnBothSides = false; { Plane.Side side = Plane.Side.No; bool sideInitialized = false; foreach( Vec3 pyramidPoint in pyramidPoints ) { if( pyramidPoint.Equals( pyramidEdge.Start, .00001f ) ) continue; if( pyramidPoint.Equals( pyramidEdge.End, .00001f ) ) continue; Plane.Side s = plane.GetSide( pyramidPoint ); if( sideInitialized ) { if( side == Plane.Side.Negative && s == Plane.Side.Positive || side == Plane.Side.Positive && s == Plane.Side.Negative ) { existsPyramidPointsOnBothSides = true; break; } } else { side = s; sideInitialized = true; } } } if( existsPyramidPointsOnBothSides ) continue; clipPlanes.Add( plane ); } } return clipPlanes.ToArray(); }
static void WalkSpotLightShadowGeneration( Camera camera, RenderLight light, Set<SceneNode> outSceneNodes, Set<StaticMeshObject> outStaticMeshObjects) { Plane[] clipPlanes = GetClipPlanesForSpotLightShadowGeneration( camera, light ); Sphere clipSphere = new Sphere( light.Position, light.AttenuationRange ); SceneManager.Instance._SceneGraph.GetObjects( clipPlanes, _SceneObjectGroups.SceneNode | _SceneObjectGroups.StaticMeshObject, delegate( _ISceneObject sceneObject ) { //clip by sphere if( !clipSphere.IsIntersectsBounds( sceneObject._SceneData.Bounds ) ) return; _SceneObjectGroups objGroups = sceneObject._SceneData.Groups; //StaticMeshObject if( ( objGroups & _SceneObjectGroups.StaticMeshObject ) != 0 ) { StaticMeshObject staticMeshObject = (StaticMeshObject)sceneObject; if( !staticMeshObject.Visible ) return; if( !staticMeshObject.CastShadows ) return; outStaticMeshObjects.Add( staticMeshObject ); return; } //SceneNode if( ( objGroups & _SceneObjectGroups.SceneNode ) != 0 ) { SceneNode sceneNode = (SceneNode)sceneObject; if( !sceneNode.Visible ) return; //if( !x.CastShadows ) //{ // can be optimized //} outSceneNodes.Add( sceneNode ); return; } Log.Fatal( "InternalSceneManagement: WalkSpotLightShadowGeneration: invalid sceneObject." ); } ); }
static void WalkPointLightShadowGeneration( Camera camera, RenderLight light, Set<SceneNode> outSceneNodes, Set<StaticMeshObject> outStaticMeshObjects) { //not optimal. need consider camera frustum. float range = light.AttenuationRange; if( range >= 10000.0f ) range = 10000.0f; Sphere sphere = new Sphere( light.Position, range ); SceneManager.Instance._SceneGraph.GetObjects( ref sphere, _SceneObjectGroups.SceneNode | _SceneObjectGroups.StaticMeshObject, delegate( _ISceneObject sceneObject ) { _SceneObjectGroups objGroups = sceneObject._SceneData.Groups; //StaticMeshObject if( ( objGroups & _SceneObjectGroups.StaticMeshObject ) != 0 ) { StaticMeshObject staticMeshObject = (StaticMeshObject)sceneObject; if( !staticMeshObject.Visible ) return; if( !staticMeshObject.CastShadows ) return; outStaticMeshObjects.Add( staticMeshObject ); return; } //SceneNode if( ( objGroups & _SceneObjectGroups.SceneNode ) != 0 ) { SceneNode sceneNode = (SceneNode)sceneObject; if( !sceneNode.Visible ) return; //if( !x.CastShadows ) //{ // can be optimized //} outSceneNodes.Add( sceneNode ); return; } Log.Fatal( "InternalSceneManagement: WalkPointLightShadowGeneration: invalid sceneObject." ); } ); }
static void WalkDirectionalLightShadowGeneration( Camera camera, RenderLight light, float farClipDistance, Set<SceneNode> outSceneNodes, Set<StaticMeshObject> outStaticMeshObjects) { Plane[] clipPlanes = GetClipPlanesForDirectionalLightShadowGeneration( camera, light, farClipDistance ); SceneManager.Instance._SceneGraph.GetObjects( clipPlanes, _SceneObjectGroups.SceneNode | _SceneObjectGroups.StaticMeshObject, delegate( _ISceneObject sceneObject ) { _SceneObjectGroups objGroups = sceneObject._SceneData.Groups; //StaticMeshObject if( ( objGroups & _SceneObjectGroups.StaticMeshObject ) != 0 ) { StaticMeshObject staticMeshObject = (StaticMeshObject)sceneObject; if( !staticMeshObject.Visible ) return; if( !staticMeshObject.CastShadows ) return; outStaticMeshObjects.Add( staticMeshObject ); return; } //SceneNode if( ( objGroups & _SceneObjectGroups.SceneNode ) != 0 ) { SceneNode sceneNode = (SceneNode)sceneObject; if( !sceneNode.Visible ) return; //if( !x.CastShadows ) //{ // can be optimized //} outSceneNodes.Add( sceneNode ); return; } Log.Fatal( "InternalSceneManagement: WalkDirectionalLightShadowGeneration: invalid sceneObject." ); } ); }
static Plane[] GetClipPlanesForSpotLightShadowGeneration( Camera camera, RenderLight light ) { Quat rotation = Quat.FromDirectionZAxisUp( light.Direction ); Plane[] clipPlanes = new Plane[ 9 ]; //side planes Plane[] sideClipPlanes = light.GetSpotSideClipPlanes(); for( int n = 0; n < 8; n++ ) clipPlanes[ n ] = sideClipPlanes[ n ]; //far plane float range = light.AttenuationRange; if( range > 10000 ) range = 10000; Vec3 dir1 = rotation * Vec3.YAxis; Vec3 dir2 = rotation * Vec3.ZAxis; Vec3 p = light.Position + light.Direction * range; clipPlanes[ 8 ] = Plane.FromVectors( dir1, dir2, p ); return clipPlanes; }
//static bool IsIntersects( RenderLight light, Sphere boundingSphere ) //{ // if( light.Type == RenderLightType.Point || light.Type == RenderLightType.Spot ) // { // //check by bounding sphere // { // float range = light.AttenuationFar; // Sphere lightSphere = new Sphere( light.Position, range ); // if( !lightSphere.IsIntersectsSphere( ref boundingSphere ) ) // return false; // } // //check by spot light clip planes // if( light.Type == RenderLightType.Spot ) // { // foreach( Plane plane in light.SpotLightClipPlanes ) // { // if( plane.GetDistance( boundingSphere.Origin ) > boundingSphere.Radius ) // return false; // } // } // } // return true; //} public override void OnSceneManagementGetAffectingLightsForObject( Camera camera, RenderLight[] affectingLights, StaticMeshObject staticMeshObject ) { if( tempLightArray.Length != affectingLights.Length ) tempLightArray = new RenderLight[ affectingLights.Length ]; int count = 0; foreach( RenderLight light in affectingLights ) { if( light.Type == RenderLightType.Point || light.Type == RenderLightType.Spot ) { if( !IsIntersects( light, staticMeshObject.Bounds ) ) continue; } tempLightArray[ count ] = light; count++; } staticMeshObject.SetAffectingLights( tempLightArray, count ); }
static ConvexPolyhedron MakeConvexPolyhedronForPointLight( RenderLight light ) { float radius = light.AttenuationFar; radius /= MathFunctions.Cos( MathFunctions.PI * 2.0f / 32.0f ); Vec3[] vertices; int[] indices; GeometryGenerator.GenerateSphere( radius, 8, 8, false, out vertices, out indices ); for( int n = 0; n < vertices.Length; n++ ) vertices[ n ] = light.Position + vertices[ n ]; return new ConvexPolyhedron( vertices, indices, .0001f ); }
public override void OnSceneManagementGetAffectingLightsForObject( Camera camera, RenderLight[] affectingLights, SceneNode sceneNode ) { if( tempLightArray.Length != affectingLights.Length ) tempLightArray = new RenderLight[ affectingLights.Length ]; int count = 0; foreach( RenderLight light in affectingLights ) { //Sphere boundingSphere = new Sphere( sceneNode.Position, 0 ); //{ // for( int n = 0; n < sceneNode.MovableObjects.Count; n++ ) // { // MovableObject movableObject = sceneNode.MovableObjects[ n ]; // float radius = movableObject._GetBoundingRadius(); // if( radius > boundingSphere.Radius ) // boundingSphere.Radius = radius; // } //} if( light.Type == RenderLightType.Point || light.Type == RenderLightType.Spot ) { Bounds bounds; sceneNode.GetWorldBounds( out bounds ); if( !IsIntersects( light, bounds ) ) continue; } tempLightArray[ count ] = light; count++; } sceneNode.SetAffectingLights( tempLightArray, count ); }
static ConvexPolyhedron MakeConvexPolyhedronForSpotLight( RenderLight light ) { float outerAngle = light.SpotlightOuterAngle; if( outerAngle < new Degree( 1 ).InRadians() ) outerAngle = new Degree( 1 ).InRadians(); if( outerAngle > new Degree( 179 ).InRadians() ) outerAngle = new Degree( 179 ).InRadians(); List<Vec3> vertices = new List<Vec3>( 10 ); List<ConvexPolyhedron.Face> faces = new List<ConvexPolyhedron.Face>( 16 ); Mat3 worldRotation = Quat.FromDirectionZAxisUp( light.Direction ).ToMat3(); float sideAngle; { float radius = MathFunctions.Sin( outerAngle / 2 ) * light.AttenuationFar; float l = MathFunctions.Sqrt( light.AttenuationFar * light.AttenuationFar - radius * radius ); radius /= MathFunctions.Cos( MathFunctions.PI * 2 / 16 ); sideAngle = MathFunctions.ATan( radius / l ); } Vec3 farPoint; { Mat3 pointRotation = worldRotation * Mat3.FromRotateByY( outerAngle / 4 ); Vec3 direction = pointRotation * Vec3.XAxis; Vec3 point = light.Position + direction * light.AttenuationFar; Plane plane = Plane.FromPointAndNormal( point, direction ); Ray ray = new Ray( light.Position, light.Direction * light.AttenuationFar ); float scale; plane.RayIntersection( ray, out scale ); farPoint = ray.GetPointOnRay( scale * 1.05f ); } vertices.Add( light.Position ); vertices.Add( farPoint ); for( int nAxisAngle = 0; nAxisAngle < 8; nAxisAngle++ ) { float axisAngle = ( MathFunctions.PI * 2 ) * ( (float)nAxisAngle / 8 ); Mat3 worldAxisRotation = worldRotation * Mat3.FromRotateByX( axisAngle ); Plane sidePlane; { Mat3 sideAngleRotation = Mat3.FromRotateByY( sideAngle + MathFunctions.PI / 2 ); Mat3 pointRotation = worldAxisRotation * sideAngleRotation; sidePlane = Plane.FromPointAndNormal( light.Position, pointRotation * Vec3.XAxis ); } { Mat3 pointRotation = worldAxisRotation * Mat3.FromRotateByY( outerAngle / 4 ); Vec3 direction = pointRotation * Vec3.XAxis; Vec3 point = light.Position + direction * ( light.AttenuationFar * 1.05f ); Ray ray = new Ray( farPoint, point - farPoint ); float scale; sidePlane.RayIntersection( ray, out scale ); Vec3 p = ray.GetPointOnRay( scale ); vertices.Add( p ); } } for( int n = 0; n < 8; n++ ) { faces.Add( new ConvexPolyhedron.Face( 0, n + 2, ( n + 1 ) % 8 + 2 ) ); faces.Add( new ConvexPolyhedron.Face( 1, ( n + 1 ) % 8 + 2, n + 2 ) ); } //foreach( ConvexPolyhedron.Face face in faces ) //{ // camera.DebugGeometry.Color = new ColorValue( 0, 0, 1 ); // Vec3 p0 = vertices[ face.Vertex0 ]; // Vec3 p1 = vertices[ face.Vertex1 ]; // Vec3 p2 = vertices[ face.Vertex2 ]; // camera.DebugGeometry.AddLine( p0, p1 ); // camera.DebugGeometry.AddLine( p1, p2 ); // camera.DebugGeometry.AddLine( p2, p0 ); // Vec3[] v = new Vec3[ 3 ] { p0, p1, p2 }; // int[] i = new int[] { 0, 1, 2 }; // camera.DebugGeometry.Color = new ColorValue( 0, 0, 1, .5f ); // camera.DebugGeometry.AddVertexIndexBuffer( v, i, Mat4.Identity, false, true ); //} //camera.DebugGeometry.Color = new ColorValue( 1, 0, 0 ); //foreach( Vec3 vertex in vertices ) // camera.DebugGeometry.AddSphere( new Sphere( vertex, .1f ) ); return new ConvexPolyhedron( vertices.ToArray(), faces.ToArray(), .0001f ); }
static Plane[] GetClipPlanesForDirectionalLightShadowGeneration( Camera mainCamera, RenderLight light, int pssmTextureIndex ) { Frustum mainFrustum = FrustumUtils.GetFrustumByCamera( mainCamera ); if( EngineDebugSettings.FrustumTest && mainCamera.AllowFrustumTestMode ) { mainFrustum.HalfWidth *= .5f; mainFrustum.HalfHeight *= .5f; } if( SceneManager.Instance.IsShadowTechniquePSSM() ) { float[] splitDistances = SceneManager.Instance.ShadowDirectionalLightSplitDistances; float nearSplitDistance = splitDistances[ pssmTextureIndex ]; float farSplitDistance = splitDistances[ pssmTextureIndex + 1 ]; const float splitPadding = 1; float splitCount = splitDistances.Length - 1; if( pssmTextureIndex > 0 ) nearSplitDistance -= splitPadding; if( pssmTextureIndex < splitCount - 1 ) farSplitDistance += splitPadding; if( nearSplitDistance < mainCamera.NearClipDistance ) nearSplitDistance = mainCamera.NearClipDistance; if( farSplitDistance <= nearSplitDistance + .001f ) farSplitDistance = nearSplitDistance + .001f; mainFrustum.NearDistance = nearSplitDistance; mainFrustum.MoveFarDistance( farSplitDistance ); } else { if( SceneManager.Instance.ShadowFarDistance > mainFrustum.NearDistance ) mainFrustum.MoveFarDistance( SceneManager.Instance.ShadowFarDistance ); } List<Plane> clipPlanes = new List<Plane>( 64 ); { Quat lightRotation = Quat.FromDirectionZAxisUp( light.Direction ); Vec3[] frustumPoints = null; mainFrustum.ToPoints( ref frustumPoints ); Vec3 frustumCenterPoint; { frustumCenterPoint = Vec3.Zero; foreach( Vec3 point in frustumPoints ) frustumCenterPoint += point; frustumCenterPoint /= frustumPoints.Length; } //calculate frustum points projected to 2d from light direction. Vec2[] projectedFrustumPoints = new Vec2[ frustumPoints.Length ]; { //Quat invertFrustumAxis = lightCameraFrustum.Rotation.GetInverse(); Quat lightRotationInv = lightRotation.GetInverse(); Vec3 translate = frustumCenterPoint - light.Direction * 1000; for( int n = 0; n < frustumPoints.Length; n++ ) { Vec3 point = frustumPoints[ n ] - translate; Vec3 localPoint = lightRotationInv * point; projectedFrustumPoints[ n ] = new Vec2( localPoint.Y, localPoint.Z ); } } int[] edges = ConvexPolygon.GetFromPoints( projectedFrustumPoints, .001f ); for( int n = 0; n < edges.Length; n++ ) { Vec3 point1 = frustumPoints[ edges[ n ] ]; Vec3 point2 = frustumPoints[ edges[ ( n + 1 ) % edges.Length ] ]; Plane plane = Plane.FromVectors( light.Direction, ( point2 - point1 ).GetNormalize(), point1 ); clipPlanes.Add( plane ); } } //add main frustum clip planes { foreach( Plane plane in mainFrustum.Planes ) { if( Vec3.Dot( plane.Normal, light.Direction ) < 0 ) continue; clipPlanes.Add( plane ); } } //add directionalLightExtrusionDistance clip plane { Quat rot = Quat.FromDirectionZAxisUp( light.Direction ); Vec3 p = mainCamera.Position - light.Direction * directionalLightExtrusionDistance; Plane plane = Plane.FromVectors( rot * Vec3.ZAxis, rot * Vec3.YAxis, p ); clipPlanes.Add( plane ); } return clipPlanes.ToArray(); }
public override void Dispose() { base.Dispose(); if(mMainLight != null) mMainLight.Dispose(); if (mBillboardSet != null) mBillboardSet.Dispose(); mMainLight = null; mBillboardSet = null; }
static Plane[] GetClipPlanesOfConvexHullAroundMainCameraAndLightPosition( Camera mainCamera, RenderLight light ) { Frustum mainFrustum = FrustumUtils.GetFrustumByCamera( mainCamera ); if( EngineDebugSettings.FrustumTest && mainCamera.AllowFrustumTestMode ) { mainFrustum.HalfWidth *= .5f; mainFrustum.HalfHeight *= .5f; } if( SceneManager.Instance.ShadowFarDistance > mainFrustum.NearDistance ) mainFrustum.MoveFarDistance( SceneManager.Instance.ShadowFarDistance ); Vec3[] frustumPoints = null; mainFrustum.ToPoints( ref frustumPoints ); //create convex hull from all camera corner points and light position. List<Vec3> convexHullVertices = new List<Vec3>(); convexHullVertices.Add( mainFrustum.Origin ); for( int n = 4; n < 8; n++ ) convexHullVertices.Add( frustumPoints[ n ] ); convexHullVertices.Add( light.Position ); Plane[] hullPlanes = ConvexPolyhedron.GetConvexPolyhedronPlanesFromVertices( convexHullVertices, .0001f ); return hullPlanes; }
public override LightShadowMapTexture CreateShadowMapTexture(RenderView renderView, RenderLight renderLight, IDirectLight light, int shadowMapSize) { var shadowMap = base.CreateShadowMapTexture(renderView, renderLight, light, shadowMapSize); shadowMap.CascadeCount = ((LightDirectionalShadowMap)light.Shadow).GetCascadeCount(); // Views with orthographic cameras cannot use cascades, we force it to 1 shadow map here. if (renderView.Projection.M44 == 1.0f) { shadowMap.ShadowType &= ~(LightShadowType.CascadeMask); shadowMap.ShadowType |= LightShadowType.Cascade1; shadowMap.CascadeCount = (int)LightShadowMapCascadeCount.OneCascade; } return(shadowMap); }
/// <summary> /// Creates the element in the world. It automatically /// sets up the mesh and the node.</summary> protected virtual void Initialise(RenderQueueGroupID renderGroup, string materialName, Vec3 scale) { mBillboardSet = SceneManager.Instance.CreateBillboardSet(2); mBillboardSet.CastShadows = false; mBillboardSet.RenderQueueGroup = renderGroup; mBillboardSet.MaterialName = materialName; mBillboardSet.DefaultSize = new Vec2(1, 1); // Attaches the mesh on a node if (mBillboardSet.ParentSceneNode == null) { mNode = new SceneNode(); mNode.Attach(mBillboardSet); } else mNode = mBillboardSet.ParentSceneNode; // Sets up the node (Position, Scale and Rotation) mBillboardSet.CreateBillboard(Vec3.Zero); mNode.Position = Vec3.Zero; mNode.Scale = scale; mMainLight = SceneManager.Instance.CreateLight(); mMainLight.Type = RenderLightType.Directional; mMainLight.AllowStaticLighting = false; mMainLight.CastShadows = true; mMainLight.Position = new Vec3(0, 0, 150); }
public bool Update(RenderLight light) { return(true); }
public override LightShadowMapTexture CreateShadowMapTexture(RenderView renderView, RenderLight renderLight, IDirectLight light, int shadowMapSize) { var shadowMapTexture = base.CreateShadowMapTexture(renderView, renderLight, light, shadowMapSize); shadowMapTexture.CascadeCount = 6; // 6 faces return(shadowMapTexture); }
static void WalkDirectionalLightShadowGeneration( Camera mainCamera, RenderLight light, int pssmTextureIndex, List<SceneNode> outSceneNodes, List<StaticMeshObject> outStaticMeshObjects ) { int[] sceneGraphIndexes; if( SceneManager.Instance.OverrideVisibleObjects != null ) { sceneGraphIndexes = GetOverrideVisibleObjectsSceneGraphIndexes(); } else { Plane[] clipPlanes = GetClipPlanesForDirectionalLightShadowGeneration( mainCamera, light, pssmTextureIndex ); uint groupMask = 0; if( outSceneNodes != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.SceneNode; if( outStaticMeshObjects != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.StaticMeshObject; sceneGraphIndexes = SceneManager.Instance.SceneGraph.GetObjects( clipPlanes, groupMask ); } foreach( int sceneGraphIndex in sceneGraphIndexes ) { SceneManager.SceneGraphObjectData data = SceneManager.Instance.SceneGraphObjects[ sceneGraphIndex ]; //SceneNode SceneNode sceneNode = data.SceneNode; if( sceneNode != null && sceneNode.Visible && sceneNode.IsContainsObjectWithCastsShadowsEnabled() ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( sceneNode.GetWorldBounds() ) ) outSceneNodes.Add( sceneNode ); } //StaticMeshObject StaticMeshObject staticMeshObject = data.StaticMeshObject; if( staticMeshObject != null && staticMeshObject.Visible && staticMeshObject.CastShadows ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( staticMeshObject.Bounds ) ) outStaticMeshObjects.Add( staticMeshObject ); } } }
static void WalkPointLightShadowGeneration( Camera mainCamera, RenderLight light, Vec3 pointLightFaceDirection, List<SceneNode> outSceneNodes, List<StaticMeshObject> outStaticMeshObjects ) { Sphere lightSphere = new Sphere( light.Position, light.AttenuationFar ); if( !pointLightFaceDirection.Equals( Vec3.Zero, .001f ) ) { //shadowmap. 6 render targets. int[] sceneGraphIndexes; if( SceneManager.Instance.OverrideVisibleObjects != null ) { sceneGraphIndexes = GetOverrideVisibleObjectsSceneGraphIndexes(); } else { Plane[] clipPlanes; { //add point light clip planes Plane[] array1 = GetClipPlanesForPointLightShadowGeneration( mainCamera, light, pointLightFaceDirection ); //add main frustum clip planes and light position Plane[] array2 = GetClipPlanesOfConvexHullAroundMainCameraAndLightPosition( mainCamera, light ); clipPlanes = new Plane[ array1.Length + array2.Length ]; Array.Copy( array1, 0, clipPlanes, 0, array1.Length ); Array.Copy( array2, 0, clipPlanes, array1.Length, array2.Length ); } Bounds clipBounds = lightSphere.ToBounds(); uint groupMask = 0; if( outSceneNodes != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.SceneNode; if( outStaticMeshObjects != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.StaticMeshObject; sceneGraphIndexes = SceneManager.Instance.SceneGraph.GetObjects( clipPlanes, clipBounds, groupMask ); } foreach( int sceneGraphIndex in sceneGraphIndexes ) { SceneManager.SceneGraphObjectData data = SceneManager.Instance.SceneGraphObjects[ sceneGraphIndex ]; //SceneNode SceneNode sceneNode = data.SceneNode; if( sceneNode != null && sceneNode.Visible && sceneNode.IsContainsObjectWithCastsShadowsEnabled() ) { Bounds sceneNodeBounds = sceneNode.GetWorldBounds(); //clip by sphere if( lightSphere.IsIntersectsBounds( sceneNodeBounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( sceneNodeBounds ) ) outSceneNodes.Add( sceneNode ); } } //StaticMeshObject StaticMeshObject staticMeshObject = data.StaticMeshObject; if( staticMeshObject != null && staticMeshObject.Visible && staticMeshObject.CastShadows ) { //clip by sphere if( lightSphere.IsIntersectsBounds( staticMeshObject.Bounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( staticMeshObject.Bounds ) ) outStaticMeshObjects.Add( staticMeshObject ); } } } } else { //stencil shadows. //check by sphere volume. int[] sceneGraphIndexes; if( SceneManager.Instance.OverrideVisibleObjects != null ) { sceneGraphIndexes = GetOverrideVisibleObjectsSceneGraphIndexes(); } else { Plane[] clipPlanes; { //add main frustum clip planes and light position Plane[] array1 = GetClipPlanesOfConvexHullAroundMainCameraAndLightPosition( mainCamera, light ); clipPlanes = new Plane[ 6 + array1.Length ]; //add 6 light clip planes. clipPlanes[ 0 ] = new Plane( Vec3.XAxis, lightSphere.Origin.X + lightSphere.Radius ); clipPlanes[ 1 ] = new Plane( -Vec3.XAxis, -( lightSphere.Origin.X - lightSphere.Radius ) ); clipPlanes[ 2 ] = new Plane( Vec3.YAxis, lightSphere.Origin.Y + lightSphere.Radius ); clipPlanes[ 3 ] = new Plane( -Vec3.YAxis, -( lightSphere.Origin.Y - lightSphere.Radius ) ); clipPlanes[ 4 ] = new Plane( Vec3.ZAxis, lightSphere.Origin.Z + lightSphere.Radius ); clipPlanes[ 5 ] = new Plane( -Vec3.ZAxis, -( lightSphere.Origin.Z - lightSphere.Radius ) ); Array.Copy( array1, 0, clipPlanes, 6, array1.Length ); } Bounds clipBounds = lightSphere.ToBounds(); uint groupMask = 0; if( outSceneNodes != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.SceneNode; if( outStaticMeshObjects != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.StaticMeshObject; sceneGraphIndexes = SceneManager.Instance.SceneGraph.GetObjects( clipPlanes, clipBounds, groupMask ); } foreach( int sceneGraphIndex in sceneGraphIndexes ) { SceneManager.SceneGraphObjectData data = SceneManager.Instance.SceneGraphObjects[ sceneGraphIndex ]; //SceneNode SceneNode sceneNode = data.SceneNode; if( sceneNode != null && sceneNode.Visible && sceneNode.IsContainsObjectWithCastsShadowsEnabled() ) { Bounds sceneNodeBounds = sceneNode.GetWorldBounds(); //clip by sphere if( lightSphere.IsIntersectsBounds( sceneNodeBounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( sceneNodeBounds ) ) outSceneNodes.Add( sceneNode ); } } //StaticMeshObject StaticMeshObject staticMeshObject = data.StaticMeshObject; if( staticMeshObject != null && staticMeshObject.Visible && staticMeshObject.CastShadows ) { //clip by sphere if( lightSphere.IsIntersectsBounds( staticMeshObject.Bounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( staticMeshObject.Bounds ) ) outStaticMeshObjects.Add( staticMeshObject ); } } } } }
static void WalkSpotLightShadowGeneration( Camera mainCamera, RenderLight light, List<SceneNode> outSceneNodes, List<StaticMeshObject> outStaticMeshObjects ) { Sphere lightSphere = new Sphere( light.Position, light.AttenuationFar ); int[] sceneGraphIndexes; if( SceneManager.Instance.OverrideVisibleObjects != null ) { sceneGraphIndexes = GetOverrideVisibleObjectsSceneGraphIndexes(); } else { Plane[] clipPlanes; { //add spot light clip planes Plane[] array1 = light.SpotLightClipPlanes; //add main frustum clip planes and light position Plane[] array2 = GetClipPlanesOfConvexHullAroundMainCameraAndLightPosition( mainCamera, light ); clipPlanes = new Plane[ array1.Length + array2.Length ]; Array.Copy( array1, 0, clipPlanes, 0, array1.Length ); Array.Copy( array2, 0, clipPlanes, array1.Length, array2.Length ); } Bounds clipBounds = lightSphere.ToBounds(); uint groupMask = 0; if( outSceneNodes != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.SceneNode; if( outStaticMeshObjects != null ) groupMask |= 1 << (int)SceneManager.SceneGraphGroups.StaticMeshObject; sceneGraphIndexes = SceneManager.Instance.SceneGraph.GetObjects( clipPlanes, clipBounds, groupMask ); } foreach( int sceneGraphIndex in sceneGraphIndexes ) { SceneManager.SceneGraphObjectData data = SceneManager.Instance.SceneGraphObjects[ sceneGraphIndex ]; //SceneNode SceneNode sceneNode = data.SceneNode; if( sceneNode != null && sceneNode.Visible && sceneNode.IsContainsObjectWithCastsShadowsEnabled() ) { Bounds sceneNodeBounds = sceneNode.GetWorldBounds(); //clip by sphere if( lightSphere.IsIntersectsBounds( sceneNodeBounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( sceneNodeBounds ) ) outSceneNodes.Add( sceneNode ); } } //StaticMeshObject StaticMeshObject staticMeshObject = data.StaticMeshObject; if( staticMeshObject != null && staticMeshObject.Visible && staticMeshObject.CastShadows ) { //clip by sphere if( lightSphere.IsIntersectsBounds( staticMeshObject.Bounds ) ) { //clip volumes if( !IsTotalClipVolumesContainsBounds( staticMeshObject.Bounds ) ) outStaticMeshObjects.Add( staticMeshObject ); } } } }
public override LightShadowMapTexture CreateShadowMapTexture(RenderView renderView, RenderLight renderLight, IDirectLight light, int shadowMapSize) { var shadowMap = shadowMaps.Add(); shadowMap.Initialize(renderView, renderLight, light, light.Shadow, shadowMapSize, this); shadowMap.CascadeCount = 2; // 2 faces return(shadowMap); }
private static bool CanRenderLight(RenderLight renderLight, LightGroupRendererBase.ProcessLightsParameters parameters) { // Just to do some minor fake work, but ensure this is true. return(renderLight.Position == default); }