protected override void DoRender()
        {
            // Calculate elapsed seconds
            var time = clock.ElapsedMilliseconds / 1000.0f;

            // Retrieve device context
            var context = this.DeviceManager.Direct3DContext;

            // Calculate skin matrices for each bone
            ConstantBuffers.PerArmature skinMatrices = new ConstantBuffers.PerArmature();
            if (mesh.Bones != null)
            {
                // Retrieve each bone's local transform
                for (var i = 0; i < mesh.Bones.Count; i++)
                {
                    skinMatrices.Bones[i] = mesh.Bones[i].BoneLocalTransform;
                }

                // Load bone transforms from animation frames
                if (CurrentAnimation.HasValue)
                {
                    // Keep track of the last key-frame used for each bone
                    Mesh.Keyframe?[] lastKeyForBones = new Mesh.Keyframe?[mesh.Bones.Count];
                    // Keep track of whether a bone has been interpolated
                    bool[] lerpedBones = new bool[mesh.Bones.Count];
                    for (var i = 0; i < CurrentAnimation.Value.Keyframes.Count; i++)
                    {
                        // Retrieve current key-frame
                        var frame = CurrentAnimation.Value.Keyframes[i];

                        // If the current frame is not in the future
                        if (frame.Time <= time)
                        {
                            // Keep track of last key-frame for bone
                            lastKeyForBones[frame.BoneIndex] = frame;
                            // Retrieve transform from current key-frame
                            skinMatrices.Bones[frame.BoneIndex] = frame.Transform;
                        }
                        // Frame is in the future, check if we should interpolate
                        else
                        {
                            // Only interpolate a bone's key-frames ONCE
                            if (!lerpedBones[frame.BoneIndex])
                            {
                                // Retrieve the previous key-frame if exists
                                Mesh.Keyframe prevFrame;
                                if (lastKeyForBones[frame.BoneIndex] != null)
                                {
                                    prevFrame = lastKeyForBones[frame.BoneIndex].Value;
                                }
                                else
                                {
                                    continue; // nothing to interpolate
                                }
                                // Make sure we only interpolate with
                                // one future frame for this bone
                                lerpedBones[frame.BoneIndex] = true;

                                // Calculate time difference between frames
                                var frameLength = frame.Time - prevFrame.Time;
                                var timeDiff    = time - prevFrame.Time;
                                var amount      = timeDiff / frameLength;

                                // Interpolation using Lerp on scale and translation, and Slerp on Rotation (Quaternion)
                                Vector3    t1, t2; // Translation
                                Quaternion q1, q2; // Rotation
                                float      s1, s2; // Scale
                                // Decompose the previous key-frame's transform
                                prevFrame.Transform.DecomposeUniformScale(out s1, out q1, out t1);
                                // Decompose the current key-frame's transform
                                frame.Transform.DecomposeUniformScale(out s2, out q2, out t2);

                                // Perform interpolation and reconstitute matrix
                                skinMatrices.Bones[frame.BoneIndex] =
                                    Matrix.Scaling(MathUtil.Lerp(s1, s2, amount)) *
                                    Matrix.RotationQuaternion(Quaternion.Slerp(q1, q2, amount)) *
                                    Matrix.Translation(Vector3.Lerp(t1, t2, amount));
                            }
                        }
                    }
                }

                // Apply parent bone transforms
                // We assume here that the first bone has no parent
                // and that each parent bone appears before children
                for (var i = 1; i < mesh.Bones.Count; i++)
                {
                    var bone = mesh.Bones[i];
                    if (bone.ParentIndex > -1)
                    {
                        var parentTransform = skinMatrices.Bones[bone.ParentIndex];
                        skinMatrices.Bones[i] = (skinMatrices.Bones[i] * parentTransform);
                    }
                }

                // Change the bone transform from rest pose space into bone space (using the inverse of the bind/rest pose)
                for (var i = 0; i < mesh.Bones.Count; i++)
                {
                    skinMatrices.Bones[i] = Matrix.Transpose(mesh.Bones[i].InvBindPose * skinMatrices.Bones[i]);
                }

                // Check need to loop animation
                if (!PlayOnce && CurrentAnimation.HasValue && CurrentAnimation.Value.EndTime <= time)
                {
                    this.Clock.Restart();
                }
            }

            // Update the constant buffer with the skin matrices for each bone
            context.UpdateSubresource(skinMatrices.Bones, PerArmatureBuffer);

            // Draw sub-meshes grouped by material
            for (var mIndx = 0; mIndx < mesh.Materials.Count; mIndx++)
            {
                // Retrieve sub meshes for this material
                var subMeshesForMaterial =
                    (from sm in mesh.SubMeshes
                     where sm.MaterialIndex == mIndx
                     select sm).ToArray();

                // If the material buffer is available and there are submeshes
                // using the material update the PerMaterialBuffer
                if (PerMaterialBuffer != null && subMeshesForMaterial.Length > 0)
                {
                    // update the PerMaterialBuffer constant buffer
                    var material = new ConstantBuffers.PerMaterial()
                    {
                        Ambient       = new Color4(mesh.Materials[mIndx].Ambient),
                        Diffuse       = new Color4(mesh.Materials[mIndx].Diffuse),
                        Emissive      = new Color4(mesh.Materials[mIndx].Emissive),
                        Specular      = new Color4(mesh.Materials[mIndx].Specular),
                        SpecularPower = mesh.Materials[mIndx].SpecularPower,
                        UVTransform   = mesh.Materials[mIndx].UVTransform,
                    };

                    // Bind textures to the pixel shader
                    int texIndxOffset = mIndx * Common.Mesh.MaxTextures;
                    material.HasTexture = (uint)(textureViews[texIndxOffset] != null ? 1 : 0); // 0=false
                    context.PixelShader.SetShaderResources(0, textureViews.GetRange(texIndxOffset, Common.Mesh.MaxTextures).ToArray());

                    // Set texture sampler state
                    context.PixelShader.SetSampler(0, samplerState);

                    // Update material buffer
                    context.UpdateSubresource(ref material, PerMaterialBuffer);
                }

                // For each sub-mesh
                foreach (var subMesh in subMeshesForMaterial)
                {
                    // Ensure the vertex buffer and index buffers are in range
                    if (subMesh.VertexBufferIndex < vertexBuffers.Count && subMesh.IndexBufferIndex < indexBuffers.Count)
                    {
                        // Retrieve and set the vertex and index buffers
                        var vertexBuffer = vertexBuffers[(int)subMesh.VertexBufferIndex];
                        context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, Utilities.SizeOf <Vertex>(), 0));
                        context.InputAssembler.SetIndexBuffer(indexBuffers[(int)subMesh.IndexBufferIndex], Format.R16_UInt, 0);
                        // Set topology
                        context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
                    }

                    // Draw the sub-mesh (includes Primitive count which we multiply by 3)
                    // The submesh also includes a start index into the vertex buffer
                    context.DrawIndexed((int)subMesh.PrimCount * 3, (int)subMesh.StartIndex, 0);
                }
            }
        }
Example #2
0
        public override void Render()
        {
            if (!ResourcesLoaded)
            {
                return;
            }

            var context = this.DeviceManager.Direct3DContext;

            var vs = this.vertexShader;

            // OutputMerger targets must be set for every frame in Windows Store apps
            context.OutputMerger.SetTargets(this.DepthStencilView, this.RenderTargetView);

            context.ClearDepthStencilView(this.DepthStencilView, SharpDX.Direct3D11.DepthStencilClearFlags.Depth | SharpDX.Direct3D11.DepthStencilClearFlags.Stencil, 1.0f, 0);
            context.ClearRenderTargetView(this.RenderTargetView, new SharpDX.Color(Color.R, Color.G, Color.B, 1));

            // Set the context pipeline state
            SetContextState(context);

            ViewMatrix = Matrix.LookAtRH(Camera.Position, Camera.Position + Camera.LookAtDir, Vector3.UnitY);

            var viewProjection = ViewMatrix * ProjectionMatrix;
            // Extract camera position from view
            var camPosition = Matrix.Transpose(Matrix.Invert(ViewMatrix)).Column4;

            Camera.Position = new Vector3(camPosition.X, camPosition.Y, camPosition.Z);

            var perFrame = new ConstantBuffers.PerFrame();

            perFrame.CameraPosition = Camera.Position;
            perFrame.Light.Color    = new Color(0.8f, 0.8f, 0.8f, 1.0f);
            var lightDir = Vector3.Transform(new Vector3(1f, -1f, -1f), WorldMatrix);

            perFrame.Light.Direction = new Vector3(lightDir.X, lightDir.Y, lightDir.Z);
            context.UpdateSubresource(ref perFrame, perFrameBuffer);

            var perMaterial = new ConstantBuffers.PerMaterial();

            perMaterial.Ambient       = new Color4(0.2f);
            perMaterial.Diffuse       = SharpDX.Color.White;
            perMaterial.Emissive      = new Color4(0);
            perMaterial.Specular      = SharpDX.Color.White;
            perMaterial.SpecularPower = 20f;
            context.UpdateSubresource(ref perMaterial, perMaterialBuffer);

            //var scale = this.SwapChainPanel.CompositionScaleX;
            foreach (var m in meshRenderers)
            {
                var worldRotation = Matrix.Identity;// *Matrix.RotationAxis(Vector3.UnitY, clock.ElapsedMilliseconds / 1000.0f);
                var perObject     = new ConstantBuffers.PerObject();
                perObject.World = m.World * WorldMatrix * worldRotation;
                perObject.WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(perObject.World));
                perObject.WorldViewProjection   = perObject.World * viewProjection;
                perObject.Transpose();
                context.UpdateSubresource(ref perObject, perObjectBuffer);

                m.Render();
            }

            //textRenderer.Text = "Async resource loading";
            //textRenderer.Render();

            fpsRenderer.Render();

            //// Draw a circle.
            //var d2dContext = DeviceManager.Direct2DContext;
            //float radiusX = this.RenderTargetSize.Width / 3.0f;
            //float radiusY = this.RenderTargetSize.Height / 3.0f;

            //float strokeWidth = 10.0f *this.SwapChainPanel.CompositionScaleX;
            //var brush = new SharpDX.Direct2D1.SolidColorBrush(d2dContext, SharpDX.Color.Black);
            //d2dContext.BeginDraw();
            //using (var sc2 = SwapChain.QueryInterface<SwapChain2>())
            //{
            //    d2dContext.Transform = sc2.MatrixTransform;
            //}
            //d2dContext.DrawEllipse(new SharpDX.Direct2D1.Ellipse(new Vector2(this.RenderTargetSize.Width / 2.0f, this.RenderTargetSize.Height / 2.0f), radiusX, radiusY), brush, strokeWidth );
            //d2dContext.EndDraw();

            // Present the render result
            Present();
        }
        public override void Render()
        {
            if (!ResourcesLoaded)
                return;

            var context = this.DeviceManager.Direct3DContext;

            var vs = this.vertexShader;

            // OutputMerger targets must be set for every frame in Windows Store apps
            context.OutputMerger.SetTargets(this.DepthStencilView, this.RenderTargetView);

            context.ClearDepthStencilView(this.DepthStencilView, SharpDX.Direct3D11.DepthStencilClearFlags.Depth | SharpDX.Direct3D11.DepthStencilClearFlags.Stencil, 1.0f, 0);
            context.ClearRenderTargetView(this.RenderTargetView, new SharpDX.Color(Color.R, Color.G, Color.B, 1));

            // Set the context pipeline state
            SetContextState(context);

            ViewMatrix = Matrix.LookAtRH(Camera.Position, Camera.Position + Camera.LookAtDir, Vector3.UnitY);

            var viewProjection = ViewMatrix * ProjectionMatrix;
            // Extract camera position from view
            var camPosition = Matrix.Transpose(Matrix.Invert(ViewMatrix)).Column4;
            Camera.Position = new Vector3(camPosition.X, camPosition.Y, camPosition.Z);

            var perFrame = new ConstantBuffers.PerFrame();
            perFrame.CameraPosition = Camera.Position;
            perFrame.Light.Color = new Color(0.8f, 0.8f, 0.8f, 1.0f);
            var lightDir = Vector3.Transform(new Vector3(1f, -1f, -1f), WorldMatrix);
            perFrame.Light.Direction = new Vector3(lightDir.X, lightDir.Y, lightDir.Z);
            context.UpdateSubresource(ref perFrame, perFrameBuffer);

            var perMaterial = new ConstantBuffers.PerMaterial();
            perMaterial.Ambient = new Color4(0.2f);
            perMaterial.Diffuse = SharpDX.Color.White;
            perMaterial.Emissive = new Color4(0);
            perMaterial.Specular = SharpDX.Color.White;
            perMaterial.SpecularPower = 20f;
            context.UpdateSubresource(ref perMaterial, perMaterialBuffer);

            //var scale = this.SwapChainPanel.CompositionScaleX;
            foreach (var m in meshRenderers)
            {
                var worldRotation = Matrix.Identity;// *Matrix.RotationAxis(Vector3.UnitY, clock.ElapsedMilliseconds / 1000.0f);
                var perObject = new ConstantBuffers.PerObject();
                perObject.World = m.World * WorldMatrix * worldRotation;
                perObject.WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(perObject.World));
                perObject.WorldViewProjection = perObject.World * viewProjection;
                perObject.Transpose();
                context.UpdateSubresource(ref perObject, perObjectBuffer);

                m.Render();
            }

            //textRenderer.Text = "Async resource loading";
            //textRenderer.Render();

            fpsRenderer.Render();

            //// Draw a circle.
            //var d2dContext = DeviceManager.Direct2DContext;
            //float radiusX = this.RenderTargetSize.Width / 3.0f;
            //float radiusY = this.RenderTargetSize.Height / 3.0f;

            //float strokeWidth = 10.0f *this.SwapChainPanel.CompositionScaleX;
            //var brush = new SharpDX.Direct2D1.SolidColorBrush(d2dContext, SharpDX.Color.Black);
            //d2dContext.BeginDraw();
            //using (var sc2 = SwapChain.QueryInterface<SwapChain2>())
            //{
            //    d2dContext.Transform = sc2.MatrixTransform;
            //}
            //d2dContext.DrawEllipse(new SharpDX.Direct2D1.Ellipse(new Vector2(this.RenderTargetSize.Width / 2.0f, this.RenderTargetSize.Height / 2.0f), radiusX, radiusY), brush, strokeWidth );
            //d2dContext.EndDraw();

            // Present the render result
            Present();
        }