public override Matrix[] GetBoneTransforms() { Matrix[] child1Transforms = child1.GetBoneTransforms(); Matrix[] child2Transforms = child2.GetBoneTransforms(); return(SpaceUtils.LerpSkeletalPose(child1Transforms, child2Transforms, BlendFactor)); }
public Matrix[] GetSkinTransforms() { Matrix[] blendStartPose; if (blendFromCancelledTransitionPose) { blendStartPose = cancelledPose; } else { blendStartPose = CurrentState.GetBoneTransforms(); } if (ActiveTransition == null) { return(CreateSkinTransforms(blendStartPose)); } else { Matrix[] nextStatePose = nextState.GetBoneTransforms(); float pctComplete = (float)(transitionTime.TotalSeconds / ActiveTransition.DurationInSeconds); float blendFactor = ActiveTransition.UseSmoothStep ? MathHelper.SmoothStep(0.0f, 1.0f, pctComplete) : pctComplete; Matrix[] blendedPose = SpaceUtils.LerpSkeletalPose(blendStartPose, nextStatePose, blendFactor); // Store the blended pose in case we have to cancel the transition next frame. if (!blendFromCancelledTransitionPose) { cancelledPose = blendedPose; } return(CreateSkinTransforms(blendedPose)); } }
public override Matrix[] GetBoneTransforms() { // Pick an arbitrary node to 'prime' the refinement loop float lowerBoundPosition = ChildrenByPosition.Keys.Min(); float upperBoundPosition = ChildrenByPosition.Keys.Max(); foreach (float position in ChildrenByPosition.Keys) { if (position > lowerBoundPosition && position <= BlendPosition) { lowerBoundPosition = position; } if (position < upperBoundPosition && position >= BlendPosition) { upperBoundPosition = position; } } Matrix[] lowerBoundTransforms = ChildrenByPosition[lowerBoundPosition].GetBoneTransforms(); if (lowerBoundPosition == upperBoundPosition) { return(lowerBoundTransforms); } Matrix[] upperBoundTransforms = ChildrenByPosition[upperBoundPosition].GetBoneTransforms(); float blendFactor = (BlendPosition - lowerBoundPosition) / (upperBoundPosition - lowerBoundPosition); return(SpaceUtils.LerpSkeletalPose(lowerBoundTransforms, upperBoundTransforms, blendFactor)); }
public override Matrix[] GetBoneTransforms() { Matrix[] child1Transforms = child1.GetBoneTransforms(); Matrix[] child2Transforms = child2.GetBoneTransforms(); Matrix[] child3Transforms = child2.GetBoneTransforms(); Matrix[] blendedTransforms = new Matrix[child1Transforms.Length]; Vector3 scale1; Quaternion rot1; Vector3 pos1; Vector3 scale2; Quaternion rot2; Vector3 pos2; Vector3 scale3; Quaternion rot3; Vector3 pos3; Vector3 bc = SpaceUtils.GetBarycentricCoords(Child1Position, Child2Position, Child3Position, BlendPosition); for (int p = 0; p < child1Transforms.Length; p++) { child1Transforms[p].Decompose(out scale1, out rot1, out pos1); child2Transforms[p].Decompose(out scale2, out rot2, out pos2); child3Transforms[p].Decompose(out scale3, out rot3, out pos3); blendedTransforms[p] = Matrix.CreateScale(scale1 * bc.X + scale2 * bc.Y + scale3 * bc.Z) * Matrix.CreateFromQuaternion(Quaternion.Normalize(rot1 * bc.X + rot2 * bc.Y + rot3 * bc.Z)) * Matrix.CreateTranslation(pos1 * bc.X + pos2 * bc.Y + pos3 * bc.Z); } return(blendedTransforms); }
private void ControlBiped(InputManager input, float dTimeMs) { // If input is in line with avatar orientation, you get all movement, otherwise, some of the movement is dulled to get reorientation Vector3 moveInput = Vector3.Zero; if (ActiveInputMap.FullIntervalMap.ContainsKey(FullIntervalControlActions.MoveLeftRightRate)) { moveInput.X += input.GetFullIntervalControlValue(ActiveInputMap.FullIntervalMap[FullIntervalControlActions.MoveLeftRightRate], InputIndex); } if (ActiveInputMap.FullIntervalMap.ContainsKey(FullIntervalControlActions.MoveDownUpRate)) { moveInput.Z -= input.GetFullIntervalControlValue(ActiveInputMap.FullIntervalMap[FullIntervalControlActions.MoveDownUpRate], InputIndex); } float moveAmount = moveInput.Length(); if (moveAmount > 0.0f) { // Transform (rotation only) the input from view space into world space Matrix cameraRotation = mReferenceCam.Transform; cameraRotation.Translation = Vector3.Zero; moveInput = Vector3.Transform(moveInput, cameraRotation); if (moveInput.X != 0.0f || moveInput.Z != 0.0f) { moveInput.Y = 0.0f; Quaternion directionDiff = SpaceUtils.GetSweptQuaternion(BepuConverter.Convert(mBipedControl.Controller.HorizontalViewDirection), moveInput); mBipedControl.OrientationChange = directionDiff; } } mBipedControl.HorizontalMovement = Vector2.UnitY * moveAmount; // Crouching: if (input.CheckForBinaryInput(ActiveInputMap, BinaryControlActions.Crouch, InputIndex)) { mBipedControl.DesiredMovementActions |= BipedControllerComponent.MovementActions.Crouching; } else { mBipedControl.DesiredMovementActions &= ~BipedControllerComponent.MovementActions.Crouching; } // Jumping: if (input.CheckForNewBinaryInput(ActiveInputMap, BinaryControlActions.Jump, InputIndex)) { mBipedControl.DesiredMovementActions |= BipedControllerComponent.MovementActions.Jumping; } else { mBipedControl.DesiredMovementActions &= ~BipedControllerComponent.MovementActions.Jumping; } }
public override Matrix[] GetBoneTransforms() { foreach (TernaryLerpBlendNode tri in Triangulation) { Vector3 bc = SpaceUtils.GetBarycentricCoords(tri.Child1Position, tri.Child2Position, tri.Child3Position, BlendPosition); if (bc.X >= 0.0f && bc.Y >= 0.0f && bc.Z >= 0.0f) { return(tri.GetBoneTransforms()); } } throw new InvalidOperationException("The triangulation does not contain the BlendPosition point"); }
public override void Fire() { const float ATTACK_RADIUS = 3.0f; const float ATTACK_LENGTH = 4.0f; // Play 'thwack' sound Actor owner = GameResources.ActorManager.GetActorById(OwnerActorId); BipedControllerComponent bipedControl = owner.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control); RigidTransform alignCapsule = new RigidTransform(BepuVec3.Forward * ATTACK_LENGTH * 0.5f + BepuConverter.Convert(MuzzleOffset), BepuQuaternion.CreateFromAxisAngle(BepuVec3.Right, MathHelper.PiOver2)); Vector3 aim = (bipedControl.WorldAim.HasValue ? bipedControl.WorldAim.Value : BepuConverter.Convert(bipedControl.Controller.ViewDirection)); RigidTransform positionAndAim = new RigidTransform(bipedControl.Controller.Body.Position, BepuConverter.Convert( SpaceUtils.GetOrientation(aim, Vector3.Up))); RigidTransform attackTransform; RigidTransform.Transform(ref alignCapsule, ref positionAndAim, out attackTransform); ConvexShape bashShape = new CapsuleShape(ATTACK_LENGTH, ATTACK_RADIUS); BepuVec3 noSweep = BepuVec3.Zero; List <RayCastResult> dudesBashed = new List <RayCastResult>(); AttackFilter filter = new AttackFilter(GameResources.ActorManager.IsMob(OwnerActorId)); GameResources.ActorManager.SimSpace.ConvexCast(bashShape, ref attackTransform, ref noSweep, filter.Test, dudesBashed); foreach (RayCastResult dude in dudesBashed) { EntityCollidable otherEntityCollidable = dude.HitObject as EntityCollidable; Terrain otherTerrain = dude.HitObject as Terrain; if (otherEntityCollidable != null && otherEntityCollidable.Entity != null && otherEntityCollidable.Entity.Tag != null) { Actor actorHit = GameResources.ActorManager.GetActorById((int)(otherEntityCollidable.Entity.Tag)); IDamagable damage = actorHit.GetBehaviorThatImplementsType <IDamagable>(); if (damage != null) { damage.TakeDamage(Damage); // TODO: P2: Query hit actor for appropiate damage effect e.g. blood and create it; } BashDust(dude.HitData.Location); } else if (otherTerrain != null) { BashDust(dude.HitData.Location); } } }
private void CommitOrientationAndMovement() { if (mState == ControllerState.InputDisabled) { Controller.HorizontalMotionConstraint.SpeedScale = 0.0f; Controller.HorizontalMotionConstraint.MovementDirection = BEPUutilities.Vector2.UnitY; return; } float diffAngle = (float)(SpaceUtils.GetQuaternionAngle(OrientationChange)); if (diffAngle > MaxTurnAnglePerTick) { OrientationChange = Quaternion.Slerp(Quaternion.Identity, OrientationChange, MaxTurnAnglePerTick / diffAngle); HorizontalMovement = Vector2.Zero; // We spent our movement turning (but this won't affect boosting.) } Controller.ViewDirection = BEPUutilities.Quaternion.Transform(Controller.ViewDirection, BepuConverter.Convert(OrientationChange)); OrientationChange = Quaternion.Identity; if (mState == ControllerState.Boosting) { Controller.HorizontalMotionConstraint.SpeedScale = 1.0f; Controller.HorizontalMotionConstraint.MovementDirection = BEPUutilities.Vector2.UnitY; } else { if (AimCheck()) { Controller.HorizontalMotionConstraint.SpeedScale = 0.375f * Math.Min(1.0f, HorizontalMovement.Length()); Controller.HorizontalMotionConstraint.MovementDirection = BepuConverter.Convert(HorizontalMovement); } else { SetHorizontalMovementAloof(); } } }
private void PreAnimationUpdateHandler(object sender, UpdateStepEventArgs e) { float elapsedTime = (float)(e.GameTime.ElapsedGameTime.TotalSeconds); Actor avatar = GameResources.ActorManager.GetActorById(ActorId); BipedControllerComponent bipedControl = avatar.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control); // Update the camera. Vector3 desiredCameraPosition; if (mInputMode == InputMode.Aloof) { Matrix cameraRotation = Matrix.CreateFromYawPitchRoll(mMmoCameraDesc.Yaw, mMmoCameraDesc.Pitch, 0.0f); BepuRay boomRay = new BepuRay(mAvatarBepuEntity.Position, BepuConverter.Convert(cameraRotation.Backward)); RayCastResult result; GameResources.ActorManager.SimSpace.RayCast(boomRay, mMmoCameraDesc.Distance, CameraClipFilter, out result); desiredCameraPosition = result.HitObject != null? BepuConverter.Convert(BEPUutilities.Vector3.Lerp(result.HitData.Location, mAvatarBepuEntity.Position, 0.05f)) : BepuConverter.Convert(mAvatarBepuEntity.Position) + mMmoCameraDesc.Distance * cameraRotation.Backward; } else if (mInputMode == InputMode.Aiming) { Matrix viewRotation = Matrix.CreateWorld(Vector3.Zero, BepuConverter.Convert( bipedControl.Controller.ViewDirection), Vector3.Up); desiredCameraPosition = BepuConverter.Convert(mAvatarBepuEntity.Position) + Vector3.Transform( mAimingCameraOffset, viewRotation); } else { desiredCameraPosition = mCamera.Transform.Translation; } Vector3 newCameraPosition = desiredCameraPosition; Vector3 desiredCameraDirection; if (mInputMode == InputMode.Aloof) { desiredCameraDirection = BepuConverter.Convert(mAvatarBepuEntity.Position) - newCameraPosition; } else if (mInputMode == InputMode.Aiming) { desiredCameraDirection = BepuConverter.Convert(bipedControl.Controller.ViewDirection); } else { desiredCameraDirection = mCamera.Transform.Forward; } desiredCameraDirection.Normalize(); Vector3 newCameraDirection = desiredCameraDirection; if (mCameraSmoothingEngaged) { Vector3 positionDelta = desiredCameraPosition - mCamera.Transform.Translation; Quaternion directionDelta = SpaceUtils.GetSweptQuaternion(mCamera.Transform.Forward, desiredCameraDirection); const float POSITION_DELTA_THRESHHOLD = 4.0f; const float DIRECTION_DELTA_THRESHHOLD = MathHelper.Pi / 16.0f; float positionDeltaLength = positionDelta.Length(); float directionDeltaAngle = (float)(SpaceUtils.GetQuaternionAngle(directionDelta)); float fractionComplete = Math.Min(POSITION_DELTA_THRESHHOLD / positionDeltaLength, DIRECTION_DELTA_THRESHHOLD / directionDeltaAngle); if (fractionComplete < 1.0f) { newCameraPosition = Vector3.Lerp(mCamera.Transform.Translation, desiredCameraPosition, fractionComplete); Quaternion smoothedCamRotation = Quaternion.Slerp(Quaternion.Identity, directionDelta, fractionComplete); newCameraDirection = Vector3.Transform(mCamera.Transform.Forward, smoothedCamRotation); } } else { mCameraSmoothingEngaged = true; } mCamera.Transform = Matrix.CreateWorld(newCameraPosition, newCameraDirection, Vector3.Up); }
private void ProcessAIStepHandler(object sender, UpdateStepEventArgs e) { // Check FOV, add any new foes to memory. And update existing ones. We may also have gained new memories by other means. // Get players and mobs in field of vision: List <RayCastResult> actorsInView = new List <RayCastResult>(); ConeShape visionCone = new ConeShape(VisionDistance, VisionDistance); BipedControllerComponent bcc = Owner.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control); RigidTransform tipOverCone = new RigidTransform(BepuVec3.Forward * VisionDistance * 0.75f, BepuQuaternion.CreateFromAxisAngle(BepuVec3.Right, MathHelper.PiOver2)); RigidTransform eyeLevelAndFacing = new RigidTransform(bcc.Controller.Body.Position - bcc.Controller.Down * bcc.Controller.Body.Height * 0.45f, BepuConverter.Convert(SpaceUtils.GetOrientation(BepuConverter.Convert(bcc.Controller.ViewDirection), Vector3.Up))); RigidTransform visionConeTransform; RigidTransform.Transform(ref tipOverCone, ref eyeLevelAndFacing, out visionConeTransform); BepuVec3 noSweep = BepuVec3.Zero; ViewInterestFilter filter = new ViewInterestFilter(bcc.Controller.Body.CollisionInformation); GameResources.ActorManager.SimSpace.ConvexCast(visionCone, ref visionConeTransform, ref noSweep, filter.Test, actorsInView); for (int a = 0; a < actorsInView.Count; ++a) { // Does this actor warrant an addition to be made to our memory? // If so, check for LOS and recheck range. If those tests pass, modify the memory. EntityCollidable otherEntityCollidable = actorsInView[a].HitObject as EntityCollidable; // We can jump to the Id in the Tag property because we know the filter has validated this. int actorId = (int)(otherEntityCollidable.Entity.Tag); Actor viewedActor = GameResources.ActorManager.GetActorById(actorId); BipedControllerComponent viewedActorBcc = viewedActor.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control); BepuVec3 toSubject = viewedActorBcc.Controller.Body.Position - eyeLevelAndFacing.Position; // Check range: if (toSubject.LengthSquared() <= VisionDistance * VisionDistance) { BepuRay losRay = new BepuRay(eyeLevelAndFacing.Position, toSubject); RayCastResult losResult; LOSFilter losFilter = new LOSFilter(bcc.Controller.Body.CollisionInformation, otherEntityCollidable); GameResources.ActorManager.SimSpace.RayCast(losRay, VisionDistance, losFilter.Test, out losResult); EntityCollidable losEC = losResult.HitObject as EntityCollidable; // Test for LOS: if (losEC != null && losEC.Entity != null && losEC.Entity.Tag != null && (int)(losEC.Entity.Tag) == actorId) { // The viewed actor is either a player(foe) or a mob(ally). if (GameResources.ActorManager.IsPlayer(actorId)) { mMemory.SpotFoe(actorId); } else { IAgentStateManager agent = viewedActor.GetBehaviorThatImplementsType <IAgentStateManager>(); if (agent != null && agent.HasProperty(AgentPropertyName.ActiveOpponent)) { int mobFoe = agent.GetProperty <int>(AgentPropertyName.ActiveOpponent); mMemory.SenseFoe(mobFoe); } } } } } // Evaluate current threats and select one to engage: int enemyId = mMemory.GetLargestThreat(); if (enemyId != Actor.INVALID_ACTOR_ID) { if (mAgentProperties.ContainsKey(AgentPropertyName.ActiveOpponent)) { if ((int)(mAgentProperties[AgentPropertyName.ActiveOpponent]) != enemyId) { mAgentProperties[AgentPropertyName.ActiveOpponent] = enemyId; } } else { mAgentProperties.Add(AgentPropertyName.ActiveOpponent, enemyId); } } else { if (mAgentProperties.ContainsKey(AgentPropertyName.ActiveOpponent)) { mAgentProperties.Remove(AgentPropertyName.ActiveOpponent); } } TimeInState += e.GameTime.ElapsedGameTime; CurrentState.Update(mSteering, Owner, this); Vector2 locomotion = mSteering.ComputeForce(Owner); if (locomotion.LengthSquared() == 0.0f) { bcc.OrientationChange = Quaternion.Identity; bcc.HorizontalMovement = Vector2.Zero; } else { bcc.OrientationChange = Quaternion.CreateFromAxisAngle(Vector3.Up, (float)(Math.Atan2(-locomotion.X, locomotion.Y))); bcc.HorizontalMovement = locomotion.Length() * Vector2.UnitY; } mMemory.Fade(e.GameTime); }
// Steer away from obstacles in the way. This method returns a zero vector if no correction is required. // It should be high priority and the steering from other behaviors should blend into the remaining space. // So if this returns a length 1.0f vector, avoiding the obstacle is most urgent and there is no room for other // steering. private Vector2 AvoidObstacles(Actor owner) { BipedControllerComponent bcc = owner.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control); // Conditions where we do not want to use this steering force. if (GetAngleFromVertical(bcc.Controller.Body.LinearVelocity) < MathHelper.PiOver4 || // We're probably falling... !bcc.Controller.SupportFinder.HasSupport || !bcc.Controller.SupportFinder.HasTraction) { return(Vector2.Zero); } // Sphere cast ahead along facing. List <RayCastResult> obstacles = new List <RayCastResult>(); SphereShape probe = new SphereShape(bcc.Controller.BodyRadius * 1.1f); RigidTransform probeStartPosition = new RigidTransform(bcc.Controller.Body.Position); // Add a small constant to the probe length because we want a minimum amount of forward probing, even if we are not moving. float probeLength = Math.Max(BepuVec3.Dot(bcc.Controller.Body.LinearVelocity, bcc.Controller.ViewDirection), 0.0f) + 1.0f; BepuVec3 probeSweep = bcc.Controller.ViewDirection * probeLength; ObstacleFilter filter = new ObstacleFilter(bcc.Controller.Body.CollisionInformation); GameResources.ActorManager.SimSpace.ConvexCast(probe, ref probeStartPosition, ref probeSweep, filter.Test, obstacles); RayCastDistanceComparer rcdc = new RayCastDistanceComparer(); obstacles.Sort(rcdc); BEPUutilities.Vector3 cross = BEPUutilities.Vector3.Zero; int obstacleIndex = 0; do { if (obstacles.Count == obstacleIndex) { return(Vector2.Zero); } cross = BEPUutilities.Vector3.Cross(bcc.Controller.ViewDirection, -obstacles[obstacleIndex++].HitData.Normal); }while (cross.X > 0.7f); // if cross.X > 0.7f, the obstacle is some kind of gentle ramp; ignore it. // dot will typically be negative and magnitude indicates how directly ahead the obstacle is. float dot = BEPUutilities.Vector3.Dot(bcc.Controller.ViewDirection, -obstacles[0].HitData.Normal); if (dot >= 0.0f) // The obstacle won't hinder us if we touch it. { return(Vector2.Zero); } // When cross.Y is positive, the object is generally to the right, so veer left (and vice versa). float directionSign = cross.Y >= 0.0f ? -1.0f : 1.0f; BEPUutilities.Vector2 result = BEPUutilities.Vector2.UnitX * directionSign * -dot; // Also scale response by how close the obstacle is. float distance = (obstacles[0].HitData.Location - bcc.Controller.Body.Position).Length(); result *= MathHelper.Clamp((1.0f - distance / probeLength), 0.0f, 1.0f); // / Math.Abs(dot); // So far the result is in terms of 'velocity space'. Rotate it to align with the controller facing. float velocityTheta = (float)(Math.Atan2(-probeSweep.X, -probeSweep.Z)); BEPUutilities.Matrix2x2 velocityWorld = SpaceUtils.Create2x2RotationMatrix(velocityTheta); float facingTheta = (float)(Math.Atan2(-bcc.Controller.HorizontalViewDirection.X, -bcc.Controller.HorizontalViewDirection.Z)); BEPUutilities.Matrix2x2 facingWorldInv = SpaceUtils.Create2x2RotationMatrix(facingTheta); facingWorldInv.Transpose(); // We want the transpose/inverse of the facing transform because we want to transform the movement into 'facing space'. return(BepuConverter.Convert(SpaceUtils.TransformVec2(SpaceUtils.TransformVec2(result, velocityWorld), facingWorldInv))); }
private void DrawShadowMap(ICamera camera, Actor castingActor) { TransformComponent shadowCasterTransform = castingActor.GetComponent <TransformComponent>(ActorComponent.ComponentType.Transform); Matrix casterView = Matrix.Invert(shadowCasterTransform.Transform); // Find the front half of the frustum corners in world space. Matrix invCamFrustum = Matrix.Invert(camera.Frustum.Matrix); Vector3[] halfCamCorners = new Vector3[] { new Vector3(-1.0f, -1.0f, 0.0f), new Vector3(1.0f, -1.0f, 0.0f), new Vector3(1.0f, 1.0f, 0.0f), new Vector3(-1.0f, 1.0f, 0.0f), new Vector3(-1.0f, -1.0f, 1.0f), new Vector3(1.0f, -1.0f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), new Vector3(-1.0f, 1.0f, 1.0f), }; for (int c = 0; c < 8; ++c) { Vector4 transformedCorner = Vector4.Transform(halfCamCorners[c], invCamFrustum); transformedCorner /= transformedCorner.W; halfCamCorners[c].X = transformedCorner.X; halfCamCorners[c].Y = transformedCorner.Y; halfCamCorners[c].Z = transformedCorner.Z; } for (int c = 0; c < 4; ++c) { halfCamCorners[c + 4] = halfCamCorners[c] + 0.05f * (halfCamCorners[c + 4] - halfCamCorners[c]); } Vector3[] camCorners = camera.Frustum.GetCorners(); // Transform those corners into to caster space, and form a bounding box around them, which will become our caster projection. Vector3 shadowMapFrustumMinHalfCorner = Vector3.Transform(halfCamCorners[0], casterView); Vector3 shadowMapFrustumMaxHalfCorner = shadowMapFrustumMinHalfCorner; Vector3 shadowMapFrustumMinCorner = Vector3.Transform(camCorners[0], casterView); Vector3 shadowMapFrustumMaxCorner = shadowMapFrustumMinHalfCorner; for (int fc = 1; fc < 8; ++fc) { Vector3 currTranslatedCorner = Vector3.Transform(halfCamCorners[fc], casterView); shadowMapFrustumMinHalfCorner = Vector3.Min(currTranslatedCorner, shadowMapFrustumMinHalfCorner); shadowMapFrustumMaxHalfCorner = Vector3.Max(currTranslatedCorner, shadowMapFrustumMaxHalfCorner); currTranslatedCorner = Vector3.Transform(camCorners[fc], casterView); shadowMapFrustumMinCorner = Vector3.Min(currTranslatedCorner, shadowMapFrustumMinCorner); shadowMapFrustumMaxCorner = Vector3.Max(currTranslatedCorner, shadowMapFrustumMaxCorner); } Matrix shadowMapProj = SpaceUtils.CreateOrthographicOffCenter( shadowMapFrustumMinHalfCorner.X, shadowMapFrustumMaxHalfCorner.X, shadowMapFrustumMinHalfCorner.Y, shadowMapFrustumMaxHalfCorner.Y, shadowMapFrustumMaxHalfCorner.Z + 1000.0f, // Extra room to include shadow casting objects. shadowMapFrustumMinHalfCorner.Z); SceneGraph.ResetTraversal(); SceneGraph.VisibilityFrustum = new BoundingFrustum(casterView * shadowMapProj); Resources.ShadowTransform = SceneGraph.VisibilityFrustum.Matrix * sShadowTextureShift; SceneGraph.ExternalMaterialFlags = TraversalContext.MaterialFlags.ShadowMap; SharedResources.Game.GraphicsDevice.SetRenderTarget(Resources.ShadowMap); SharedResources.Game.GraphicsDevice.Clear(Color.White); SceneGraph.Draw(); }