示例#1
0
        public override void Update(GameTime gameTime)
        {
            if (_avatarPose == null)
            {
                if (_avatarRenderer.State == AvatarRendererState.Ready)
                {
                    _avatarPose = new AvatarPose(_avatarRenderer);

                    // Start the first animation.
                    var wrappedAnimation = WrapAnimation(_currentAvatarAnimationPreset);
                    AnimationService.StartAnimation(wrappedAnimation, _avatarPose).AutoRecycle();

                    _debugRenderer.Clear();
                    _debugRenderer.DrawText("\n\nCurrent Animation: " + _currentAvatarAnimationPreset);
                }
            }
            else
            {
                if (InputService.IsPressed(Buttons.A, false, LogicalPlayerIndex.One))
                {
                    // Switch to next preset.
                    _currentAvatarAnimationPreset++;
                    if (!Enum.IsDefined(typeof(AvatarAnimationPreset), _currentAvatarAnimationPreset))
                    {
                        _currentAvatarAnimationPreset = 0;
                    }

                    // Cross-fade to new animation.
                    var wrappedAnimation = WrapAnimation(_currentAvatarAnimationPreset);
                    AnimationService.StartAnimation(wrappedAnimation,
                                                    _avatarPose,
                                                    AnimationTransitions.Replace(TimeSpan.FromSeconds(0.5))
                                                    ).AutoRecycle();

                    _debugRenderer.Clear();
                    _debugRenderer.DrawText("\n\nCurrent Animation: " + _currentAvatarAnimationPreset);
                }

                if (InputService.IsPressed(Buttons.B, false, LogicalPlayerIndex.One))
                {
                    // Switch to previous preset.
                    _currentAvatarAnimationPreset--;
                    if (!Enum.IsDefined(typeof(AvatarAnimationPreset), _currentAvatarAnimationPreset))
                    {
                        _currentAvatarAnimationPreset = (AvatarAnimationPreset)EnumHelper.GetValues(typeof(AvatarAnimationPreset)).Length - 1;
                    }

                    // Cross-fade to new animation.
                    var wrappedAnimation = WrapAnimation(_currentAvatarAnimationPreset);
                    AnimationService.StartAnimation(wrappedAnimation,
                                                    _avatarPose,
                                                    AnimationTransitions.Replace(TimeSpan.FromSeconds(0.5))
                                                    ).AutoRecycle();

                    _debugRenderer.Clear();
                    _debugRenderer.DrawText("\n\nCurrent Animation: " + _currentAvatarAnimationPreset);
                }
            }
        }
        public override void Update(GameTime gameTime)
        {
            _debugRenderer.Clear();

            if (_avatarPose == null)
            {
                // Must wait till renderer is ready. Before that we do not get skeleton info.
                if (_avatarRenderer.State == AvatarRendererState.Ready)
                {
                    // Create AvatarPose.
                    _avatarPose = new AvatarPose(_avatarRenderer);

                    // A 'bone transform' is the transformation of a bone relative to its bind pose.
                    // Bone transforms define the pose of a skeleton.

                    // Rotate arm of avatar.
                    SkeletonPose skeletonPose  = _avatarPose.SkeletonPose;
                    int          shoulderIndex = skeletonPose.Skeleton.GetIndex("ShoulderLeft");
                    skeletonPose.SetBoneTransform(shoulderIndex, new SrtTransform(QuaternionF.CreateRotationZ(-0.9f)));

                    // The class SkeletonHelper provides some useful extension methods.
                    // One is SetBoneRotationAbsolute() which sets the orientation of a bone relative
                    // to model space.
                    // Rotate elbow to make the lower arm point forward.
                    int elbowIndex = skeletonPose.Skeleton.GetIndex("ElbowLeft");
                    SkeletonHelper.SetBoneRotationAbsolute(skeletonPose, elbowIndex, QuaternionF.CreateRotationY(ConstantsF.PiOver2));

                    // Draw avatar skeleton for debugging.
                    _debugRenderer.DrawSkeleton(skeletonPose, _pose, Vector3F.One, 0.02f, Color.Orange, true);
                }
            }
        }
示例#3
0
        /// <inheritdoc/>
        protected override void OnRender(RenderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            _numberOfDraws++;

            var graphicsDevice = GraphicsService.GraphicsDevice;

            context.CameraNode = CameraNode;

            DebugRenderer.Render(context);
            DrawTitleSafeArea(graphicsDevice);

            // Draw FPS text.
            _internalDebugRenderer.Clear();
            _internalDebugRenderer.DrawText(
                _stringBuilder,
                new Vector2F((int)(context.Viewport.Width - _textWidth - 5), 0),
                Color.Yellow);
            _internalDebugRenderer.Render(context);

            context.CameraNode = null;
        }
示例#4
0
        public override void Update(GameTime gameTime)
        {
            Scene.Update(gameTime.ElapsedGameTime);

            DebugRenderer.Clear();

            base.Update(gameTime);
        }
示例#5
0
        private void RenderDebugInfo(RenderContext context)
        {
            _debugRenderer.Clear();
            _debugRenderer.DrawAxes(Pose.Identity, 0.5f, true);

            //_debugRenderer.DrawTexture(_cloudLayerNode._renderTarget, new Rectangle(1280-512, 0, 512, 512));

#if XBOX
            _debugRenderer.DrawText(_ephemeris.Time.DateTime.ToString());
#else
            _debugRenderer.DrawText(_ephemeris.Time.ToString());
#endif

            _debugRenderer.PointSize = 10;

            var extraterrestrialSunlight = Ephemeris.ExtraterrestrialSunlight;

            Vector3F sun;
            Vector3F ambient;
            Ephemeris.GetSunlight(_scatteringSky.ObserverAltitude, 2.2f, _scatteringSky.SunDirection, out sun, out ambient);

            var scatterSun     = _scatteringSky.GetSunlight() / _scatteringSky.SunIntensity * extraterrestrialSunlight;
            var scatterAmbient = _scatteringSky.GetAmbientLight(1024);
            scatterAmbient = scatterAmbient / _scatteringSky.SunIntensity * extraterrestrialSunlight;

            var scatterFog = _scatteringSky.GetFogColor(128) / _scatteringSky.SunIntensity * extraterrestrialSunlight;
            var luminance  = Vector3F.Dot(GraphicsHelper.LuminanceWeights, scatterFog);
            scatterFog = InterpolationHelper.Lerp(scatterFog, new Vector3F(luminance), 0.7f);

            _debugRenderer.DrawText("Extraterrestrial sun intensity:" + extraterrestrialSunlight.Length);
            _debugRenderer.DrawText("Spectrum sun intensity:" + sun.Length);
            _debugRenderer.DrawText("Scatter sun intensity:" + scatterSun.Length);

            _debugRenderer.DrawText("\nSpectrum ambient intensity:" + ambient.Length);
            _debugRenderer.DrawText("Scatter ambient intensity:" + scatterAmbient.Length);

            _debugRenderer.DrawText("\nScatter fog intensity:" + scatterFog.Length);

            _debugRenderer.DrawPoint(new Vector3F(-0.5f, 0, 0), new Color((Vector3)extraterrestrialSunlight.Normalized), true);

            sun.TryNormalize();
            ambient /= ambient.Length;
            _debugRenderer.DrawPoint(new Vector3F(0, 0, 0), new Color((Vector3)sun), true);
            _debugRenderer.DrawPoint(new Vector3F(0, -0.5f, 0), new Color((Vector3)ambient), true);

            scatterSun.TryNormalize();
            scatterAmbient.TryNormalize();
            _debugRenderer.DrawPoint(new Vector3F(0.5f, 0, 0), new Color((Vector3)scatterSun), true);
            _debugRenderer.DrawPoint(new Vector3F(0.5f, -0.5f, 0), new Color((Vector3)scatterAmbient), true);

            scatterFog.TryNormalize();
            _debugRenderer.DrawPoint(new Vector3F(0, 0.5f, 0), new Color((Vector3)scatterFog), true);

            _debugRenderer.PointSize = 40f;
            _debugRenderer.Render(context);
        }
示例#6
0
        public override void Update(GameTime gameTime)
        {
            if (_avatarPose == null)
            {
                if (_avatarRenderer.State == AvatarRendererState.Ready)
                {
                    _avatarPose = new AvatarPose(_avatarRenderer);

                    // Create a ragdoll for the avatar.
                    _ragdoll = Ragdoll.CreateAvatarRagdoll(_avatarPose, Simulation);

                    // Set the world space pose of the whole ragdoll. And copy the bone poses of the
                    // current skeleton pose.
                    _ragdoll.Pose = _pose;
                    _ragdoll.UpdateBodiesFromSkeleton(_avatarPose.SkeletonPose);

                    // In this sample we use a passive ragdoll where we need joints to hold the
                    // limbs together and limits to control the angular movement.
                    _ragdoll.EnableJoints();
                    _ragdoll.EnableLimits();

                    // Set all motors to constraint motors that only use damping. This adds a damping
                    // effect to all ragdoll limbs.
                    foreach (RagdollMotor motor in _ragdoll.Motors)
                    {
                        if (motor != null)
                        {
                            motor.Mode = RagdollMotorMode.Constraint;
                            motor.ConstraintDamping = 5;
                            motor.ConstraintSpring  = 0;
                        }
                    }
                    _ragdoll.EnableMotors();

                    // Add rigid bodies and the constraints of the ragdoll to the simulation.
                    _ragdoll.AddToSimulation(Simulation);
                }
            }
            else
            {
                // Copy skeleton pose from ragdoll.
                _ragdoll.UpdateSkeletonFromBodies(_avatarPose.SkeletonPose);
            }

            // Render rigid bodies.
            _debugRenderer.Clear();
            foreach (var body in Simulation.RigidBodies)
            {
                if (!(body.Shape is EmptyShape)) // Do not draw dummy bodies which might be used by the ragdoll.
                {
                    _debugRenderer.DrawObject(body, Color.Black, true, false);
                }
            }
        }
示例#7
0
        public override void Update(GameTime gameTime)
        {
            // Just for debugging: Draw coordinate axes at (0, 0, 0).
            _debugRenderer.Clear();
            _debugRenderer.DrawAxes(Pose.Identity, 0.5f, true);

            // Update the scene - this must be called once per frame.
            _scene.Update(gameTime.ElapsedGameTime);

            base.Update(gameTime);
        }
示例#8
0
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            Scene.Update(deltaTime);

            _frameCount++;

            // At regular intervals reset the debug output and write the current FPS.
            if (_stopwatch.Elapsed.TotalSeconds > 1)
            {
                _debugRenderer.Clear();
                _debugRenderer.DrawText("FPS: " + _frameCount / (float)_stopwatch.Elapsed.TotalSeconds);
                _stopwatch.Restart();
                _frameCount = 0;
            }
        }
示例#9
0
        public override void Update(GameTime gameTime)
        {
            _scene.Update(gameTime.ElapsedGameTime);

            _debugRenderer.Clear();
            foreach (var sceneNode in _scene.GetDescendants())
            {
                _debugRenderer.DrawText(sceneNode.Name ?? sceneNode.GetType().Name, sceneNode.PoseWorld.Position, Color.Green, true);
                _debugRenderer.DrawAxes(sceneNode.PoseWorld, 1, false);
            }

            _debugRenderer.DrawAxes(Pose.Identity, 1, false);

            base.Update(gameTime);
        }
        private void UpdateMatcapTexture()
        {
            // Load texture.
            var texture = _contentManager.Load <Texture2D>(string.Format(MatcapTexturePath, _matcapTextureIndex));

            // Replace texture in all materials.
            var meshNode = (MeshNode)_model.Children[0];

            foreach (var material in meshNode.Mesh.Materials)
            {
                material["Default"].Set("MatcapTexture", texture);
            }

            // Visualize texture for debuggging.
            _debugRenderer.Clear();
            _debugRenderer.DrawTexture(texture, new Rectangle(20, 120, 200, 200));
        }
示例#11
0
        public override void Update(GameTime gameTime)
        {
            // Move models in circles.
            _angle += (float)gameTime.ElapsedGameTime.TotalSeconds * 0.6f;

            // Set SceneNode.LastPoseWorld to the current pose. This is only required
            // when advanced effects are used, like post-process motion blur. Since this
            // is not the case in this sample, we could skip this step. However, it is a
            // good practice to always update SceneNode.LastPoseWorld and LastScaleWorld
            // before the pose or scale is changed.
            _model0.SetLastPose(true);
            _model1.SetLastPose(true);

            // Update the position and orientation of the models.
            _model0.PoseWorld = new Pose(new Vector3F(2, 0, 0))
                                * new Pose(Matrix33F.CreateRotationY(_angle))
                                * new Pose(new Vector3F(2, 0, 0));
            _model1.PoseWorld = new Pose(new Vector3F(-2, 0, 0))
                                * new Pose(Matrix33F.CreateRotationY(-_angle + 0.5f))
                                * new Pose(new Vector3F(-2, 0, 0));

            // Draw the bounding shapes of the meshes.
            //
            // Note - Bounding shapes of skinned models:
            // The model description file (dude.drmdl) specifies a custom bounding shape
            // (see the attributes AabbMinimum and AabbMaximum in this file). For
            // skinned models this bounding shape must be chosen manually. It must be big
            // enough to contain all poses of the model. - In future DigitalRune Graphics
            // versions we will automatically compute suitable bounding shapes for
            // animated models.
            _debugRenderer.Clear();
            foreach (var sceneNode in _scene.GetSubtree().OfType <MeshNode>())
            {
                _debugRenderer.DrawObject(sceneNode, Color.Orange, true, false);
            }

            // Draw a coordinate cross at the world space origin.
            _debugRenderer.DrawAxes(Pose.Identity, 1, false);

            // Update the scene - this must be called once per frame.
            // The scene will compute internal collision information for camera frustum
            // culling or light culling (which lights overlap with which mesh nodes).
            _scene.Update(gameTime.ElapsedGameTime);

            base.Update(gameTime);
        }
示例#12
0
        protected override void OnRender(RenderContext context)
        {
            _frameCount++;

            // At regular intervals reset the debug output and write the current FPS.
            if (_stopwatch.Elapsed.TotalSeconds > 1)
            {
                _debugRenderer.Clear();
                _debugRenderer.DrawText("FPS: " + _frameCount / (float)_stopwatch.Elapsed.TotalSeconds);
                _stopwatch.Restart();
                _frameCount = 0;
            }

            context.Scene      = Scene;
            context.CameraNode = CameraNode;

            var graphicsDevice = GraphicsService.GraphicsDevice;

            // Clear background.
            graphicsDevice.Clear(Color.Transparent);

            // Frustum culling: Get all scene nodes that intersect the camera frustum.
            var query = Scene.Query <CameraFrustumQuery>(context.CameraNode, context);

            // Set render state.
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.Opaque;
            graphicsDevice.SamplerStates[0]  = SamplerState.AnisotropicWrap;

            // Use a MeshRenderer to render all MeshNodes that are in the camera frustum.
            // We use the shader effects and effect parameters for the render pass named
            // "Default" (see the material (.drmat files) of the assets).
            context.RenderPass = "******";
            _meshRenderer.Render(query.SceneNodes, context);
            context.RenderPass = null;

            // Render debug info.
            _debugRenderer.Render(context);

            context.CameraNode = null;
            context.Scene      = null;
        }
示例#13
0
        public override void Update(GameTime gameTime)
        {
            // Move the directional light in a circle.
            float deltaTimeF = (float)gameTime.ElapsedGameTime.TotalSeconds;

            _lightAngle += 0.3f * deltaTimeF;
            var position = QuaternionF.CreateRotationY(_lightAngle).Rotate(new Vector3F(6, 6, 0));

            // Make the light look at the world space origin.
            var lightTarget  = Vector3F.Zero;
            var lookAtMatrix = Matrix44F.CreateLookAt(position, lightTarget, Vector3F.Up);

            // A look-at matrix is the inverse of a normal world or pose matrix.
            _mainDirectionalLightNode.PoseWorld =
                new Pose(lookAtMatrix.Translation, lookAtMatrix.Minor).Inverse;

            // Update the light position of the renderer.
            // To create a local light shadow (light rays are not parallel), we have to set the light
            // position and a 4th component of 1.
            //_projectedShadowRenderer.LightPosition = new Vector4F(position, 1);
            // To create a directional light shadow (light rays are parallel), we have to set the inverse
            // light direction and 0.
            var lightRayDirection = (lightTarget - position);

            _projectedShadowRenderer.LightPosition = new Vector4F(-lightRayDirection, 0);

            // For debugging: Draw coordinate axes at (0, 0, 0).
            _debugRenderer.Clear();
            _debugRenderer.DrawAxes(Pose.Identity, 1, true);

            // Draw light node. (Will be drawn as a coordinate cross.)
            _debugRenderer.DrawObject(_mainDirectionalLightNode, Color.Yellow, false, true);

            // Update the scene - this must be called once per frame.
            _scene.Update(gameTime.ElapsedGameTime);

            base.Update(gameTime);
        }
        public override void Update(GameTime gameTime)
        {
            Random random = new Random(1234567);

            // The debug renderer stores all draw commands. In this sample we recreate
            // the draw jobs each frame. --> Clear draw jobs of last frame.
            _debugRenderer.Clear();

            // The DebugRenderer can draw stuff "in" the scene (enabled z test) or "over"
            // the scene (disabled z test).

            // Draw some points and line "in" and "over" the scene.
            for (int i = 0; i < 10; i++)
            {
                var position = new Vector3F(-6, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawPoint(position, Color.Green, false);
            }

            for (int i = 0; i < 10; i++)
            {
                var position = new Vector3F(-4, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawPoint(position, Color.Yellow, true);
            }

            for (int i = 0; i < 10; i++)
            {
                var start = new Vector3F(-2, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                var end   = new Vector3F(-2, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawLine(start, end, Color.Green, false);
            }

            for (int i = 0; i < 10; i++)
            {
                var start = new Vector3F(0, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                var end   = new Vector3F(0, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawLine(start, end, Color.Yellow, true);
            }

            // Text without a specified position is drawn at a default position.
            _debugRenderer.DefaultTextPosition = new Vector2F(10, 100);
            _debugRenderer.DrawText("White objects are positioned in screen space.");
            _debugRenderer.DrawText("Yellow objects are positioned in world space. Depth test disabled.");
            _debugRenderer.DrawText("Other objects are positioned in world space. Depth test enabled.");

            // Text can also be drawn in world space coordinates or in screen space coordinates.
            _debugRenderer.DrawText("WorldSpacePosition (0, 0, 0)", new Vector3F(0, 0, 0), Color.Green, false);
            _debugRenderer.DrawText("WorldSpacePosition (0, 0, -1)", new Vector3F(0, 0, -1), Color.Yellow, true);
            _debugRenderer.DrawText("ScreenPosition (600, 40)", new Vector2F(600, 40), Color.White);
            _debugRenderer.DrawText("ScreenPosition (640, 360)", new Vector2F(640, 360), Color.White);

            // It is often useful to copy textures to the screen for debugging.
            _debugRenderer.DrawTexture(NoiseHelper.GetGrainTexture(GraphicsService, 128), new Rectangle(1000, 10, 128, 128));

            // Axes can be drawn to display poses (positions and orientations).
            _debugRenderer.DrawAxes(new Pose(new Vector3F(0, 0, 0)), 1, true);

            // Axis-aligned bounding boxes (AABB)
            _debugRenderer.DrawAabb(new Aabb(new Vector3F(-0.5f), new Vector3F(0.5f)), new Pose(new Vector3F(2, 0, -3)), Color.Green, false);
            _debugRenderer.DrawAabb(new Aabb(new Vector3F(-0.5f), new Vector3F(0.5f)), new Pose(new Vector3F(4, 0, -3)), Color.Yellow, true);

            // Box shapes
            var orientation = random.NextQuaternionF();

            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-6, 0, -5), orientation), new Color(255, 0, 0, 100), false, false);
            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-6, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-4, 0, -5), orientation), Color.Yellow, true, true);

            // View volumes (frustums)
            var viewVolume = new PerspectiveViewVolume(1, 2, 0.1f, 1f);

            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(-2, 0, -5), orientation), new Color(0, 255, 0, 100), false, false);
            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(-2, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(0, 0, -5), orientation), Color.Yellow, true, true);

            // Spheres
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(2, 0, -5), orientation), new Color(0, 0, 255, 100), false, false);
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(2, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(4, 0, -5), orientation), Color.Yellow, true, true);

            // Capsules
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-6, 0, -7), orientation), new Color(255, 255, 0, 100), false, false);
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-6, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-4, 0, -7), orientation), Color.Yellow, true, true);

            // Cylinders
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(-2, 0, -7), orientation), new Color(255, 0, 255, 100), false, false);
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(-2, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(0, 0, -7), orientation), Color.Yellow, true, true);

            // Cones
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(2, 0, -7), orientation), new Color(0, 255, 255, 100), false, false);
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(2, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(4, 0, -7), orientation), Color.Yellow, true, true);

            // The debug renderer can draw any IGeometricObjects, like SceneNodes, RigidBodies, etc.
            _debugRenderer.DrawObject(_geometricObject, Color.Brown, false, false);
            _debugRenderer.DrawObject(_geometricObject, Color.Yellow, true, true);

            // The debug renderer can also an XNA model (without materials).
            _debugRenderer.DrawModel(_xnaModel, new Pose(new Vector3F(0, 2, -2), orientation), new Vector3F(1, 2, 1), new Color(128, 255, 64, 100), false, false);
            _debugRenderer.DrawModel(_xnaModel, new Pose(new Vector3F(0, 2, -2), orientation), new Vector3F(1, 2, 1), Color.LightCyan, true, false);

            // Draw a DigitalRune model.
            _debugRenderer.DrawModel(_modelNode, Color.Peru, true, false);

            // Draw the bounding shapes of the meshes in this model.
            foreach (var node in _modelNode.GetSubtree())
            {
                _debugRenderer.DrawObject(node, Color.PeachPuff, true, false);
            }
        }
示例#15
0
        // Renders the graphics screen. - This method is called in GraphicsManager.Render().
        protected override void OnRender(RenderContext context)
        {
            // Abort if no active camera is set.
            if (ActiveCameraNode == null)
            {
                return;
            }

            var renderTargetPool   = GraphicsService.RenderTargetPool;
            var graphicsDevice     = GraphicsService.GraphicsDevice;
            var screenRenderTarget = context.RenderTarget;
            var viewport           = context.Viewport;

            // All intermediate render targets have the size of the target viewport.
            int width  = context.Viewport.Width;
            int height = context.Viewport.Height;

            context.Viewport = new Viewport(0, 0, width, height);

            // Our scene and the camera must be set in the render context. This info is
            // required by many renderers.
            context.Scene      = Scene;
            context.CameraNode = ActiveCameraNode;

            // LOD (level of detail) settings are also specified in the context.
            context.LodCameraNode      = ActiveCameraNode;
            context.LodHysteresis      = 0.5f;
            context.LodBias            = EnableLod ? 1.0f : 0.0f;
            context.LodBlendingEnabled = false;

            // Get all scene nodes which overlap the camera frustum.
            CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(ActiveCameraNode, context);

            // Generate cloud maps.
            // (Note: Only necessary if LayeredCloudMaps are used. If the cloud maps are
            // static and the settings do not change, it is not necessary to generate the
            // cloud maps in every frame. But in this example we use animated cloud maps.)
            _cloudMapRenderer.Render(sceneQuery.SkyNodes, context);

            // ----- G-Buffer Pass
            // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1.
            _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

            // ----- Shadow Pass
            // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes.
            context.RenderPass = "******";
            _shadowMapRenderer.Render(sceneQuery.Lights, context);
            context.RenderPass = null;

            // The ShadowMaskRenderer renders the shadows and stores them in one or more render
            // targets ("shadows masks").
            _shadowMaskRenderer.Render(sceneQuery.Lights, context);

            // In this render pipeline we do not need most shadow maps anymore and can
            // recycle them. The exception is the DirectionalLight shadow map which
            // might still be needed for forward rendering of alpha-blended objects.
            foreach (var node in sceneQuery.Lights)
            {
                var lightNode = (LightNode)node;
                if (lightNode.Shadow != null && !(lightNode.Light is DirectionalLight))
                {
                    renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                    lightNode.Shadow.ShadowMap = null;
                }
            }

            // ----- Light Buffer Pass
            // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and
            // context.LightBuffer1 (specular light).
            LightBufferRenderer.Render(sceneQuery.Lights, context);

            // ----- Material Pass
            // In the material pass we render all meshes and decals into a single full-screen
            // render target. The shaders combine the material properties (diffuse texture, etc.)
            // with the light buffer info.
            context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8));
            graphicsDevice.SetRenderTarget(context.RenderTarget);
            context.Viewport = graphicsDevice.Viewport;
            graphicsDevice.Clear(Color.Black);
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.Opaque;
            context.RenderPass = "******";
            _meshRenderer.Render(sceneQuery.RenderableNodes, context);
            _decalRenderer.Render(sceneQuery.DecalNodes, context);
            context.RenderPass = null;

            // The meshes rendered in the last step might use additional floating-point
            // textures (e.g. the light buffers) in the different graphics texture stages.
            // We reset the texture stages (setting all GraphicsDevice.Textures to null),
            // otherwise XNA might throw exceptions.
            graphicsDevice.ResetTextures();

            // ----- Occlusion Queries
            _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context);

            // ----- Sky
            _skyRenderer.Render(sceneQuery.SkyNodes, context);

            // ----- Fog
            _fogRenderer.Render(sceneQuery.FogNodes, context);

            // ----- Forward Rendering of Alpha-Blended Meshes and Particles
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.AlphaBlend;
            context.RenderPass = "******";
            AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
            context.RenderPass = null;
            graphicsDevice.ResetTextures();

            // The shadow maps could be used by some shaders of the alpha-blended
            // objects - but now, we can recycle all shadow maps.
            foreach (var node in sceneQuery.Lights)
            {
                var lightNode = (LightNode)node;
                if (lightNode.Shadow != null)
                {
                    renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                    lightNode.Shadow.ShadowMap = null;
                }
            }

            // ----- Post Processors
            // The post-processors modify the scene image and the result is written into
            // the final render target - which is usually the back  buffer (but this could
            // also be another off-screen render target used in another graphics screen).
            context.SourceTexture = context.RenderTarget;
            context.RenderTarget  = screenRenderTarget;
            context.Viewport      = viewport;
            PostProcessors.Process(context);

            renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture);
            context.SourceTexture = null;

            // ----- Lens Flares
            _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context);

            // ----- Optional: Restore the Z-Buffer
            // Currently, the hardware depth buffer is not initialized with useful data because
            // every time we change the render target, XNA deletes the depth buffer. If we want
            // the debug rendering to use correct depth buffer, we can restore the depth buffer
            // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer
            // graphics will overlay the whole 3D scene.
            _rebuildZBufferRenderer.Render(context, true);

            // ----- Debug Output
            // Render debug info added by game objects.
            DebugRenderer.Render(context);

            // ----- Draw Reticle
            if (DrawReticle)
            {
                _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                _spriteBatch.Draw(
                    _reticle,
                    new Vector2(viewport.Width / 2 - _reticle.Width / 2, viewport.Height / 2 - _reticle.Height / 2),
                    Color.Black);
                _spriteBatch.End();
            }

            // Render intermediate render targets for debugging.
            // We do not use the public DebugRenderer here because the public DebugRenderer
            // might not be cleared every frame (the game logic can choose how it wants to
            // use the public renderer).
            if (VisualizeIntermediateRenderTargets)
            {
                _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200));
                _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200));
                _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200));
                _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200));
                for (int i = 0; i < _shadowMaskRenderer.ShadowMasks.Count; i++)
                {
                    var shadowMask = _shadowMaskRenderer.ShadowMasks[i];
                    if (shadowMask != null)
                    {
                        _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200));
                    }
                }

                _internalDebugRenderer.Render(context);
                _internalDebugRenderer.Clear();
            }

            // ----- Clean-up
            // It is very important to give every intermediate render target back to the
            // render target pool!
            renderTargetPool.Recycle(context.GBuffer0);
            context.GBuffer0 = null;
            renderTargetPool.Recycle(context.GBuffer1);
            context.GBuffer1 = null;
            renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]);
            context.Data.Remove(RenderContextKeys.DepthBufferHalf);
            renderTargetPool.Recycle(context.LightBuffer0);
            context.LightBuffer0 = null;
            renderTargetPool.Recycle(context.LightBuffer1);
            context.LightBuffer1 = null;
            _shadowMaskRenderer.RecycleShadowMasks();
            context.Scene         = null;
            context.CameraNode    = null;
            context.LodHysteresis = 0;
            context.LodCameraNode = null;
            context.RenderPass    = null;
        }
示例#16
0
        protected override void OnRender(RenderContext context)
        {
            if (ActiveCameraNode == null)
            {
                return;
            }

            context.Scene         = Scene;
            context.CameraNode    = ActiveCameraNode;
            context.LodCameraNode = ActiveCameraNode;

            // Copy all scene nodes into a list.
            CopyNodesToList(Scene, _sceneNodes);

            // ----- Occlusion Culling
            // Usually, we would make a scene query to get all scene nodes within the
            // viewing frustum. But in this example we will use the new OcclusionBuffer.
            if (EnableCulling)
            {
                // Render all occluders into the occlusion buffer.
                // - "_sceneNodes" is a list of all scene nodes. The OcclusionBuffer will
                //   go through the list and render all occluders.
                // - "LightNode" is the main directional light that casts a cascaded shadow.
                //   Passing the light node to the OcclusionBuffer activates shadow caster
                //   culling.
                // - A custom scene node renderer can be passed to the OcclusionBuffer. In
                //   this example, the ground mesh "Gravel/Gravel.fbx" has a material with an
                //   "Occluder" render pass. When we pass the "MeshRenderer" to the OcclusionBuffer
                //   the ground mesh will be rendered directly into the occlusion buffer.
                Profiler.Start("Occlusion.Render");
                context.RenderPass = "******";
                OcclusionBuffer.Render(_sceneNodes, LightNode, MeshRenderer, context);
                context.RenderPass = null;
                Profiler.Stop("Occlusion.Render");

                // Perform occlusion culling on the specified list of scene nodes.
                // - The scene nodes will be tested against the occluders. If a scene node
                //   is hidden, it will be replaced with a null entry in the list.
                // - When shadow caster culling is active, shadow casting scene nodes will
                //   also be tested against the occluders. If the shadow is not visible,
                //   the shadow caster will internally be marked as occluded. The ShadowMapRenderer
                //   will automatically skip occluded scene nodes.
                Profiler.Start("Occlusion.Query");
                OcclusionBuffer.Query(_sceneNodes, context);
                Profiler.Stop("Occlusion.Query");
            }

            // The base DeferredGraphicsScreen expects a CustomSceneQuery.
            // --> Copy the occlusion culling results to a CustomSceneQuery.
            _sceneQuery.Set(ActiveCameraNode, _sceneNodes, context);

            var renderTargetPool     = GraphicsService.RenderTargetPool;
            var graphicsDevice       = GraphicsService.GraphicsDevice;
            var originalRenderTarget = context.RenderTarget;
            var fullViewport         = context.Viewport;

            RenderTarget2D topDownRenderTarget = null;
            const int      topDownViewSize     = 384;

            if (ShowTopDownView)
            {
                // Render top-down scene into an offscreen render target.
                var format = new RenderTargetFormat(context.RenderTarget)
                {
                    Width  = topDownViewSize,
                    Height = topDownViewSize,
                };
                topDownRenderTarget = renderTargetPool.Obtain2D(format);

                context.Scene        = Scene;
                context.CameraNode   = _topDownCameraNode;
                context.Viewport     = new Viewport(0, 0, topDownViewSize, topDownViewSize);
                context.RenderTarget = topDownRenderTarget;
                RenderScene(_sceneQuery, context, true, false, false, false);

                _debugRenderer.Clear();
                _debugRenderer.DrawObject(ActiveCameraNode, Color.Red, true, true);
                _debugRenderer.Render(context);

                context.RenderTarget = originalRenderTarget;
                context.Viewport     = fullViewport;
            }

            // Render regular 3D scene.
            context.Scene      = Scene;
            context.CameraNode = ActiveCameraNode;
            RenderScene(_sceneQuery, context, true, false, true, false);

            // Render debug visualization on top of scene.
            bool renderObject = false;

            switch (DebugVisualization)
            {
            case DebugVisualization.CameraHzb:
                OcclusionBuffer.VisualizeCameraBuffer(DebugLevel, context);
                break;

            case DebugVisualization.LightHzb:
                OcclusionBuffer.VisualizeLightBuffer(DebugLevel, context);
                break;

            case DebugVisualization.Object:
                OcclusionBuffer.VisualizeObject(DebugObject, context);
                renderObject = true;
                break;

            case DebugVisualization.ShadowCaster:
                OcclusionBuffer.VisualizeShadowCaster(DebugObject, context);
                break;

            case DebugVisualization.ShadowVolume:
                OcclusionBuffer.VisualizeShadowVolume(DebugObject, context);
                renderObject = true;
                break;
            }

            if (renderObject)
            {
                _debugRenderer.Clear();
                _debugRenderer.DrawObject(DebugObject, Color.Yellow, true, true);
                _debugRenderer.Render(context);
            }

            if (ShowTopDownView)
            {
                // Copy offscreen buffer to screen.
                context.Viewport        = fullViewport;
                graphicsDevice.Viewport = fullViewport;

                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
                SpriteBatch.Draw(
                    topDownRenderTarget,
                    new Rectangle(fullViewport.Width - topDownViewSize, fullViewport.Height - topDownViewSize, topDownViewSize, topDownViewSize),
                    Color.White);
                SpriteBatch.End();

                renderTargetPool.Recycle(topDownRenderTarget);
            }

            // Clean-up
            _sceneNodes.Clear();
            _sceneQuery.Reset();

            context.Scene         = null;
            context.CameraNode    = null;
            context.LodCameraNode = null;
        }
        protected internal void RenderScene(CustomSceneQuery sceneQuery, RenderContext context,
                                            bool doPostProcessing, bool renderLensFlares, bool renderDebugOutput, bool renderReticle)
        {
            var renderTargetPool      = GraphicsService.RenderTargetPool;
            var graphicsDevice        = GraphicsService.GraphicsDevice;
            var originalRenderTarget  = context.RenderTarget;
            var originalViewport      = context.Viewport;
            var originalSourceTexture = context.SourceTexture;

            // All intermediate render targets have the size of the target viewport.
            int width  = context.Viewport.Width;
            int height = context.Viewport.Height;

            context.Viewport = new Viewport(0, 0, width, height);

            // The render context can be used to share any data, for example:
            // Store a shared RebuildZBufferRenderer in the context.
            context.Data[RenderContextKeys.RebuildZBufferRenderer] = _rebuildZBufferRenderer;

            // ----- G-Buffer Pass
            // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1.
            _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

            // ----- Shadow Pass
            // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes.
            context.RenderPass = "******";
            ShadowMapRenderer.Render(sceneQuery.Lights, context);
            context.RenderPass = null;

            // The ShadowMaskRenderer renders the shadows and stores them in one or more render
            // targets ("shadows masks").
            ShadowMaskRenderer.Render(sceneQuery.Lights, context);

            RecycleShadowMaps(sceneQuery.Lights);

            // ----- Light Buffer Pass
            // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and
            // context.LightBuffer1 (specular light).
            LightBufferRenderer.Render(sceneQuery.Lights, context);

            // Normally, we do not need the shadow masks anymore - except if we want to
            // display them for debugging.
            if (!VisualizeIntermediateRenderTargets)
            {
                ShadowMaskRenderer.RecycleShadowMasks();
            }

            // ----- Material Pass
            if (DebugMode == DeferredGraphicsDebugMode.None)
            {
                // In the material pass we render all meshes and decals into a single full-screen
                // render target. The shaders combine the material properties (diffuse texture, etc.)
                // with the light buffer info.
                context.RenderTarget =
                    renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable,
                                                                     DepthFormat.Depth24Stencil8));
                graphicsDevice.SetRenderTarget(context.RenderTarget);
                context.Viewport = graphicsDevice.Viewport;
                graphicsDevice.Clear(new Color(3, 3, 3, 255));
                graphicsDevice.DepthStencilState = DepthStencilState.Default;
                graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
                graphicsDevice.BlendState        = BlendState.Opaque;
                context.RenderPass = "******";
                _opaqueMeshSceneRenderer.Render(sceneQuery.RenderableNodes, context);
                _decalRenderer.Render(sceneQuery.DecalNodes, context);
                context.RenderPass = null;
            }
            else
            {
                // For debugging:
                // Ignore the material pass. Keep rendering into one of the light buffers
                // to visualize only the lighting results.
                if (DebugMode == DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
                {
                    context.RenderTarget = context.LightBuffer0;
                }
                else
                {
                    context.RenderTarget = context.LightBuffer1;
                }
            }

            // The meshes rendered in the last step might use additional floating-point
            // textures (e.g. the light buffers) in the different graphics texture stages.
            // We reset the texture stages (setting all GraphicsDevice.Textures to null),
            // otherwise XNA might throw exceptions.
            graphicsDevice.ResetTextures();

            // ----- Occlusion Queries
            if (renderLensFlares)
            {
                _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context);
            }

            // ----- Sky
            _skyRenderer.Render(sceneQuery.SkyNodes, context);

            // ----- Fog
            _fogRenderer.Render(sceneQuery.FogNodes, context);

            // ----- Forward Rendering of Alpha-Blended Meshes and Particles
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.AlphaBlend;
            context.RenderPass = "******";
            AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
            context.RenderPass = null;
            graphicsDevice.ResetTextures();

            renderTargetPool.Recycle(context.SourceTexture);
            context.SourceTexture = null;

            _underwaterPostProcessor.Enabled = IsCameraUnderwater(sceneQuery, context.CameraNode);

            // ----- Post Processors
            context.SourceTexture = context.RenderTarget;
            context.RenderTarget  = originalRenderTarget;
            context.Viewport      = originalViewport;
            if (doPostProcessing)
            {
                // The post-processors modify the scene image and the result is written into
                // the final render target - which is usually the back  buffer (but this could
                // also be another off-screen render target used in another graphics screen).
                PostProcessors.Process(context);
            }
            else
            {
                // Only copy the current render target to the final render target without post-processing.
                graphicsDevice.SetRenderTarget(originalRenderTarget);
                graphicsDevice.Viewport = originalViewport;
                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
                SpriteBatch.Draw(context.SourceTexture, new Rectangle(0, 0, originalViewport.Width, originalViewport.Height), Color.White);
                SpriteBatch.End();
            }
            renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture);
            context.SourceTexture = null;

            // ----- Lens Flares
            if (renderLensFlares)
            {
                _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context);
            }

            // ----- Debug Output
            if (renderDebugOutput)
            {
                // ----- Optional: Restore the Z-Buffer
                // Currently, the hardware depth buffer is not initialized with useful data because
                // every time we change the render target, XNA deletes the depth buffer. If we want
                // the debug rendering to use correct depth buffer, we can restore the depth buffer
                // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer
                // graphics will overlay the whole 3D scene.
                _rebuildZBufferRenderer.Render(context, true);

                // Render debug info added by game objects.
                DebugRenderer.Render(context);

                // Render intermediate render targets for debugging.
                // We do not use the public DebugRenderer here because the public DebugRenderer
                // might not be cleared every frame (the game logic can choose how it wants to
                // use the public renderer).
                if (VisualizeIntermediateRenderTargets)
                {
                    _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200));
                    for (int i = 0; i < ShadowMaskRenderer.ShadowMasks.Count; i++)
                    {
                        var shadowMask = ShadowMaskRenderer.ShadowMasks[i];
                        if (shadowMask != null)
                        {
                            _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200));
                        }
                    }

                    _internalDebugRenderer.Render(context);
                    _internalDebugRenderer.Clear();
                }
            }

            // ----- Draw Reticle
            if (renderReticle && _sampleFramework.IsGuiVisible)
            {
                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                SpriteBatch.Draw(
                    _reticle,
                    new Vector2(originalViewport.Width / 2 - _reticle.Width / 2, originalViewport.Height / 2 - _reticle.Height / 2),
                    Color.Black);
                SpriteBatch.End();
            }

            // ----- Clean-up
            // It is very important to give every intermediate render target back to the
            // render target pool!
            renderTargetPool.Recycle(context.GBuffer0);
            context.GBuffer0 = null;
            renderTargetPool.Recycle(context.GBuffer1);
            context.GBuffer1 = null;
            renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]);
            context.Data.Remove(RenderContextKeys.DepthBufferHalf);
            if (DebugMode != DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
            {
                renderTargetPool.Recycle(context.LightBuffer0);
            }
            context.LightBuffer0 = null;
            if (DebugMode != DeferredGraphicsDebugMode.VisualizeSpecularLightBuffer)
            {
                renderTargetPool.Recycle(context.LightBuffer1);
            }
            context.LightBuffer1 = null;
            ShadowMaskRenderer.RecycleShadowMasks();
            context.Data.Remove(RenderContextKeys.RebuildZBufferRenderer);
            context.SourceTexture = originalSourceTexture;
        }
        public override void Update(GameTime gameTime)
        {
            if (_avatarPose == null)
            {
                if (_avatarRenderer.State == AvatarRendererState.Ready)
                {
                    _avatarPose = new AvatarPose(_avatarRenderer);
                    _targetPose = SkeletonPose.Create(_avatarPose.SkeletonPose.Skeleton);

                    // Create a ragdoll for the avatar.
                    _ragdoll = Ragdoll.CreateAvatarRagdoll(_avatarPose, Simulation);

                    // Set the world space pose of the whole ragdoll. And copy the bone poses
                    // of the current skeleton pose.
                    _ragdoll.Pose = _pose;
                    _ragdoll.UpdateBodiesFromSkeleton(_avatarPose.SkeletonPose);

                    // To simplify collision checks, we need a simple way to determine whether
                    // a rigid body belongs to the ragdoll.
                    // --> Set RigidBody.UserData = _ragdoll.
                    // (Alternatively we could also set specific names for the rigid bodies,
                    // or we could assign the collision objects to a certain collision group.)
                    foreach (var body in _ragdoll.Bodies)
                    {
                        if (body != null)
                        {
                            body.UserData = _ragdoll;
                        }
                    }

                    // Add rigid bodies and constraints to the simulation.
                    _ragdoll.AddToSimulation(Simulation);

                    // Start by playing the key frame animation.
                    SwitchMode(RagdollMode.Mode1);

                    // The facial expression can be applied directly to the _avatarPose.
                    _animationController0 = AnimationService.StartAnimation(_expressionAnimation, _avatarPose);

                    // The skeletal animation is applied to the _targetPose. The _targetPose
                    // is used to drive the ragdoll. (See end of method.)
                    _animationController1 = AnimationService.StartAnimation(_skeletonAnimation, (IAnimatableProperty <SkeletonPose>)_targetPose);
                }

                return;
            }

            if (InputService.IsPressed(Buttons.A, false, LogicalPlayerIndex.One))
            {
                SwitchMode(RagdollMode.Mode1);
            }
            else if (InputService.IsPressed(Buttons.B, false, LogicalPlayerIndex.One))
            {
                SwitchMode(RagdollMode.Mode2);
            }
            else if (InputService.IsPressed(Buttons.X, false, LogicalPlayerIndex.One))
            {
                SwitchMode(RagdollMode.Mode3);
            }
            else if (InputService.IsPressed(Buttons.Y, false, LogicalPlayerIndex.One))
            {
                SwitchMode(RagdollMode.Mode4);
            }

            if (_mode == RagdollMode.Mode1 || _mode == RagdollMode.Mode2)
            {
                // The ragdoll plays a certain animation. Check whether the character was
                // hit by a ball.
                foreach (var contactConstraint in Simulation.ContactConstraints)
                {
                    if (contactConstraint.BodyA.UserData == _ragdoll && contactConstraint.BodyB.Name.StartsWith("Ball") ||
                        contactConstraint.BodyB.UserData == _ragdoll && contactConstraint.BodyA.Name.StartsWith("Ball"))
                    {
                        // Switch to the "Passive Ragdoll" mode and let the character collapse.
                        SwitchMode(RagdollMode.Mode3);

                        // Hint: You can read contactConstraint.LinearConstraintImpulse.Length to
                        // determine the strength of the impact.
                    }
                }
            }

            switch (_mode)
            {
            case RagdollMode.Mode1:
                // In mode 1 we update the rigid bodies directly.
                _ragdoll.UpdateBodiesFromSkeleton(_targetPose);
                break;

            case RagdollMode.Mode2:
                // Compute how much time the simulation will advance in the next Update().
                TimeSpan nextSimulationTimeStep;
                int      numberOfSubTimeSteps;
                Simulation.GetNextTimeStep(gameTime.ElapsedGameTime, out nextSimulationTimeStep, out numberOfSubTimeSteps);

                // In mode 2 velocity motors update the rigid bodies.
                _ragdoll.DriveToPose(_targetPose, (float)nextSimulationTimeStep.TotalSeconds);
                break;

            case RagdollMode.Mode3:
                // In mode 3 we don't have to update the rigid bodies.
                break;

            case RagdollMode.Mode4:
                // In mode 4 constraint motors control the joints of the ragdoll.
                // (The second parameter is only required for velocity motors.)
                _ragdoll.DriveToPose(_targetPose, 0);
                break;
            }

            // Copy the skeleton pose. (_avatarPose stores the skeleton pose which is
            // being rendered.)
            _ragdoll.UpdateSkeletonFromBodies(_avatarPose.SkeletonPose);

            _debugRenderer.Clear();
            _debugRenderer.DrawText("\n");
            _debugRenderer.DrawText(_statusMessage);

            // Render rigid bodies.
            foreach (var body in Simulation.RigidBodies)
            {
                if (!(body.Shape is EmptyShape)) // Do not draw dummy bodies which might be used by the ragdoll.
                {
                    _debugRenderer.DrawObject(body, Color.Black, true, false);
                }
            }
        }