コード例 #1
0
        /// <summary>
        /// Calculate mesh only once ... no worry about animation, no accurate bounding box
        /// </summary>
        /// <param name="bones"></param>
        /// <param name="mesh"></param>
        /// <returns></returns>
        /// <remarks>
        /// https://gamedev.stackexchange.com/questions/46332/mesh-manipulation-on-gpu-vs-cpu
        /// https://gamedev.stackexchange.com/questions/43986/calculate-an-aabb-for-bone-animated-model
        /// </remarks>
        AnimationHittableGeometryComponent ConstructMesh(Matrix4x4[] bones, CMOAnimateMeshComponent mesh)
        {
            var pos     = new List <Vector3>();
            var norms   = new List <Vector3>();
            var indeces = new List <int>();

            for (int indx = 0; indx < mesh.VertexBuffers.Count; indx++)
            {
                var vb       = mesh.VertexBuffers[indx];
                var vertices = new Vertex[vb.Length];
                for (var i = 0; i < vb.Length; i++)
                {
                    // Retrieve skinning information for vertex
                    var skin = new SkinningVertex();
                    if (mesh.SkinningVertexBuffers.Count > 0)
                    {
                        skin = mesh.SkinningVertexBuffers[indx][i];
                    }

                    // Create vertex
                    vertices[i] = new Vertex(vb[i].Position, vb[i].Normal, (Vector4)vb[i].Color, vb[i].UV, skin);
                    //the same matrix as in animation.hlsl
                    var skinTransform = Matrix4x4.Transpose(
                        bones[skin.BoneIndex0] * skin.BoneWeight0 +
                        bones[skin.BoneIndex1] * skin.BoneWeight1 +
                        bones[skin.BoneIndex2] * skin.BoneWeight2 +
                        bones[skin.BoneIndex3] * skin.BoneWeight3);

                    pos.Add(Vector3.Transform(vb[i].Position, skinTransform));
                    norms.Add(Vector3.TransformNormal(vb[i].Normal, skinTransform));
                }
            }

            var offset = 0;

            // Initialize index buffers
            for (var i = 0; i < mesh.IndexBuffers.Count; i++)
            {
                var ib = mesh.IndexBuffers[i];
                foreach (var ii in ib)
                {
                    indeces.Add(offset + (int)ii);
                }
                offset += mesh.VertexBuffers[i].Length;
            }

            var geo = new AnimationHittableGeometryComponent();

            geo.Positions  = pos.ToImmutableArray();
            geo.Indices    = indeces.ToImmutableArray();
            geo.Normals    = norms.ToImmutableArray();
            geo.IsModified = true;

            return(geo);
        }
コード例 #2
0
        void RenderMaterial(DeviceContext context, D3DAnimRenderComponent render, CMOAnimateMeshComponent mesh)
        {
            var materialCount = mesh.Materials.Count;

            // If there are no materials
            if (materialCount == 0)
            {
                RenderMeshes(context, render, mesh.SubMeshes);
                return;
            }
            // Draw sub-meshes grouped by material
            for (var mIndx = 0; mIndx < materialCount; mIndx++)
            {
                // Retrieve sub meshes for this material
                var subMeshesForMaterial = mesh.SubMeshes.Where(x => x.MaterialIndex == mIndx).ToList();
                try {
                    // If the material buffer is available and there are submeshes
                    // using the material update the PerMaterialBuffer
                    if (subMeshesForMaterial.Count > 0)
                    {
                        // update the PerMaterialBuffer constant buffer
                        var material = new ConstantBuffers.PerMaterial()
                        {
                            Ambient       = mesh.Materials[mIndx].Ambient,
                            Diffuse       = mesh.Materials[mIndx].Diffuse,
                            Emissive      = mesh.Materials[mIndx].Emissive,
                            Specular      = mesh.Materials[mIndx].Specular,
                            SpecularPower = mesh.Materials[mIndx].SpecularPower,
                            UVTransform   = mesh.Materials[mIndx].UVTransform,
                        };

                        // Bind textures to the pixel shader
                        int texIndxOffset = mIndx * CMOAnimateMeshComponent.MaxTextures;
                        material.HasTexture = (uint)(render.TextureViews.Get()[texIndxOffset] != null ? 1 : 0); // 0=false

                        context.PixelShader.SetShaderResources(0, render.TextureViews.Get().GetRange(texIndxOffset, CMOAnimateMeshComponent.MaxTextures).ToArray());
                        context.PixelShader.SetSampler(0, render.SamplerState.Get());
                        context.UpdateSubresource(ref material, render.PerMaterialBuffer.Get());
                    }
                } catch (Exception ex) {
                    ex.ToString();
                }
                // For each sub-mesh
                RenderMeshes(context, render, subMeshesForMaterial);
            }
        }
コード例 #3
0
        /// <summary>
        /// calculate bones matrix each render frame
        /// </summary>
        /// <param name="AnimatedMesh"></param>
        /// <param name="currentAnimation"></param>
        /// <returns></returns>
        Matrix4x4[] CalculateBonesMatrix(CMOAnimateMeshComponent AnimatedMesh, CMOAnimateMeshComponent.Animation currentAnimation)
        {
            Matrix4x4[] bones = new Matrix4x4[MaxBones];
            // Retrieve each bone's local transform
            for (var i = 0; i < AnimatedMesh.Bones.Count; i++)
            {
                bones[i] = AnimatedMesh.Bones[i].BoneLocalTransform;
            }

            // Keep track of the last key-frame used for each bone
            CMOAnimateMeshComponent.Keyframe?[] lastKeyForBones = new CMOAnimateMeshComponent.Keyframe?[AnimatedMesh.Bones.Count];
            // Keep track of whether a bone has been interpolated
            bool[] lerpedBones = new bool[AnimatedMesh.Bones.Count];
            for (var i = 0; i < currentAnimation.Keyframes.Count; i++)
            {
                // Retrieve current key-frame
                var frame = currentAnimation.Keyframes[i];

                // If the current frame is not in the future
                if (frame.Time <= CurrentAnimationTime)
                {
                    // Keep track of last key-frame for bone
                    lastKeyForBones[frame.BoneIndex] = frame;
                    // Retrieve transform from current key-frame
                    bones[frame.BoneIndex] = frame.Transform;
                }
                else    // Frame is in the future, check if we should interpolate
                // Only interpolate a bone's key-frames ONCE
                {
                    if (!lerpedBones[frame.BoneIndex])
                    {
                        // Retrieve the previous key-frame if exists
                        CMOAnimateMeshComponent.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    = CurrentAnimationTime - prevFrame.Time;
                        float amount      = (float)timeDiff / frameLength;

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

                        //SharpDX.Matrix.DecomposeUniformScale(out s1, out q1, out t1);
                        Matrix4x4.Decompose(prevFrame.Transform, out s1, out q1, out t1);

                        // Decompose the current key-frame's transform
                        //frame.Transform.DecomposeUniformScale(out s2, out q2, out t2);
                        Matrix4x4.Decompose(frame.Transform, out s2, out q2, out t2);

                        // Perform interpolation and reconstitute matrix
                        bones[frame.BoneIndex] =
                            Matrix4x4.CreateScale((float)MathUtil.Lerp(s1.X, s2.X, amount)) *
                            Matrix4x4.CreateFromQuaternion(Quaternion.Slerp(q1, q2, amount)) *
                            Matrix4x4.CreateTranslation(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 < AnimatedMesh.Bones.Count; i++)
            {
                var bone = AnimatedMesh.Bones[i];
                if (bone.ParentIndex > -1)
                {
                    var parentTransform = bones[bone.ParentIndex];
                    bones[i] = (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 < AnimatedMesh.Bones.Count; i++)
            {
                bones[i] = Matrix4x4.Transpose(AnimatedMesh.Bones[i].InvBindPose * bones[i]);
            }

            // Check need to loop animation
            if (currentAnimation.EndTime <= CurrentAnimationTime)
            {
                CurrentAnimationTime = 0;
            }

            return(bones);
        }
コード例 #4
0
        void UpdateRenderComponent(Device device, D3DAnimRenderComponent render, CMOAnimateMeshComponent mesh)
        {
            render.ClearIndexBuffer();
            render.ClearVertexBuffer();
            render.TextureViews.Set(new List <ShaderResourceView>());

            try {
                // Initialize vertex buffers
                for (int indx = 0; indx < mesh.VertexBuffers.Count; indx++)
                {
                    var      vb       = mesh.VertexBuffers[indx];
                    Vertex[] vertices = new Vertex[vb.Length];
                    for (var i = 0; i < vb.Length; i++)
                    {
                        // Retrieve skinning information for vertex
                        var skin = new SkinningVertex();
                        if (mesh.SkinningVertexBuffers.Count > 0)
                        {
                            skin = mesh.SkinningVertexBuffers[indx][i];
                        }

                        // Create vertex
                        vertices[i] = new Vertex(vb[i].Position, vb[i].Normal, (Vector4)vb[i].Color, vb[i].UV, skin);
                    }
                    render
                    .AddVertexBuffer(Buffer.Create(device, BindFlags.VertexBuffer, vertices))
                    .DebugName = "VertexBuffer_" + indx.ToString();
                }

                // Initialize index buffers
                for (var i = 0; i < mesh.IndexBuffers.Count; i++)
                {
                    var ib = mesh.IndexBuffers[i];
                    render
                    .AddIndexBuffer(Buffer.Create(device, BindFlags.IndexBuffer, ib))
                    .DebugName = "IndexBuffer_" + i.ToString();
                }

                var tloader = new TextureLoader(device);
                //Load textures if a material has any.
                foreach (var mat in mesh.Materials)
                {
                    for (var i = 0; i < mat.Textures.Length; i++)
                    {
                        if (System.IO.File.Exists(mat.Textures[i]))
                        {
                            render.TextureViews.Get().Add(tloader.LoadShaderResource(new FileInfo(mat.Textures[i])));
                        }
                        else
                        {
                            render.TextureViews.Get().Add(null);
                        }
                    }
                }
            } catch (Exception ex) {
                ex.ToString();
            }

            render.PerMaterialBuffer.Set(new Buffer(device, Unsafe.SizeOf <ConstantBuffers.PerMaterial>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
            render.PerObjectBuffer.Set(new Buffer(device, Unsafe.SizeOf <ConstantBuffers.PerObject>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
            render.PerArmatureBuffer.Set(new Buffer(device, ConstantBuffers.PerArmature.Size(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
        }