Пример #1
0
        /// <summary>
        /// Recursively creates a bone tree based on the scenegraph returned by the importer
        /// </summary>
        /// <param name="node"> The node that is referenced to create the bone </param>
        /// <param name="parent"> The parent of the bone to be created </param>
        /// <returns> the bone that is created </returns>
        private ClientBone CreateBoneTree(Node node, ClientBone parent)
        {
            ClientBone internalNode = new ClientBone(node.Name)
            {
                Parent = parent
            };

            _allBoneLookup[internalNode.BoneName] = internalNode;

            internalNode.LocalTransform        = node.Transform.ToMatrix();
            internalNode.OriginalLocalTranform = node.Transform.ToMatrix();

            internalNode.GlobalBindPoseTransform = CalculateBoneToWorldTransform(internalNode);
            internalNode.GlobalAnimatedTransform = CalculateBoneToWorldTransform(internalNode);

            internalNode.MeshIndices = node.MeshIndices.ToList();

            for (int i = 0; i < node.ChildCount; i++)
            {
                ClientBone child = CreateBoneTree(node.Children[i], internalNode);
                if (child != null)
                {
                    internalNode.Children.Add(child);
                }
            }

            return(internalNode);
        }
Пример #2
0
        /// <summary>
        /// Calculate the current bone's global transform based on its
        /// local transform and the parent's global transform
        /// </summary>
        /// <param name="bone"> The bone whose global transform is to be calculated </param>
        /// <returns> global transformation matrix of the node </returns>
        private Matrix CalculateBoneToWorldTransform(ClientBone bone)
        {
            Matrix     global = bone.LocalTransform.Clone();
            ClientBone parent = bone.Parent;

            global = parent == null ? global : global * parent.GlobalAnimatedTransform;
            return(global);
        }
Пример #3
0
        /// <summary>
        /// Use this to recusively update the animation transform values
        /// </summary>
        /// <param name="bone"> The bone whose, and whose children's, global transformation matrices are to be calculated </param>
        private void UpdateTransforms(ClientBone bone)
        {
            bone.GlobalAnimatedTransform = CalculateBoneToWorldTransform(bone);

            foreach (var child in bone.Children)
            {
                UpdateTransforms(child);
            }
        }
Пример #4
0
        /// <summary>
        /// Create a new geometry given filename
        /// </summary>
        /// <param name="fileName"> filepath to the 3D model file </param>
        public Geometry(string fileName, bool enableRigging = false)
        {
            RiggingEnabled = enableRigging;
            sourceFileName = fileName;

            //Create new importer.
            importer = new AssimpContext();

            //import the file
            scene = importer.ImportFile(fileName,
                                        PostProcessSteps.CalculateTangentSpace | PostProcessSteps.Triangulate |
                                        PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.SortByPrimitiveType |
                                        PostProcessSteps.GenerateUVCoords | PostProcessSteps.FlipUVs |
                                        PostProcessSteps.LimitBoneWeights | PostProcessSteps.ValidateDataStructure);

            //make sure scene not null
            if (scene == null)
            {
                throw new FileNotFoundException();
            }

            //loop through sizes and count them.
            allMeshes = new List <ClientMesh>(scene.MeshCount);

            //loop through and store sizes
            for (int idx = 0; idx < scene.MeshCount; idx++)
            {
                ClientMesh mesh = new ClientMesh();
                allMeshes.Add(mesh);

                mesh.CountVertices = scene.Meshes[idx].VertexCount;

                mesh.vertSize = scene.Meshes[idx].VertexCount * Vector3.SizeInBytes;
                mesh.normSize = scene.Meshes[idx].Normals.Count * Vector3.SizeInBytes;
                mesh.faceSize = scene.Meshes[idx].FaceCount * scene.Meshes[idx].Faces[0].IndexCount * sizeof(int);
                if (scene.Meshes[idx].HasTextureCoords(0))
                {
                    mesh.texSize = scene.Meshes[idx].TextureCoordinateChannels[0].Count * Vector3.SizeInBytes;
                }
            }

            diffuseTextureSRV = new Dictionary <string, ShaderResourceView>();

            // do all the processing that rigging is required to have
            if (enableRigging)
            {
                _allBones        = new List <ClientBone>();
                _allBoneMappings = new Dictionary <string, int>();
                _allBoneLookup   = new Dictionary <string, ClientBone>();

                // set the animation related lookup tables
                AnimationIndices = new Dictionary <string, int>();
                _animationNodes  = new List <Dictionary <string, ClientAnimationNode> >(scene.AnimationCount);
                for (int i = 0; i < scene.AnimationCount; i++)
                {
                    AnimationIndices[scene.Animations[i].Name] = i;
                    _animationNodes.Add(new Dictionary <string, ClientAnimationNode>());

                    for (int j = 0; j < scene.Animations[i].NodeAnimationChannelCount; j++)
                    {
                        NodeAnimationChannel ch     = scene.Animations[i].NodeAnimationChannels[j];
                        ClientAnimationNode  myNode = new ClientAnimationNode(ch.NodeName);

                        _animationNodes[i][ch.NodeName] = myNode;
                        myNode.Translations             = new List <Vector3>();
                        myNode.TranslationTime          = new List <double>();
                        myNode.Rotations    = new List <Quaternion>();
                        myNode.RotationTime = new List <double>();
                        myNode.Scalings     = new List <Vector3>();
                        myNode.ScalingTime  = new List <double>();

                        // copy over all the necessary information in the animation channels
                        for (int k = 0; k < ch.PositionKeyCount; k++)
                        {
                            myNode.Translations.Add(ch.PositionKeys[k].Value.ToVector3());
                            myNode.TranslationTime.Add(ch.PositionKeys[k].Time);
                        }

                        for (int k = 0; k < ch.RotationKeyCount; k++)
                        {
                            myNode.Rotations.Add(ch.RotationKeys[k].Value.ToQuaternion());
                            myNode.RotationTime.Add(ch.RotationKeys[k].Time);
                        }

                        for (int k = 0; k < ch.ScalingKeyCount; k++)
                        {
                            myNode.Scalings.Add(ch.ScalingKeys[k].Value.ToVector3());
                            myNode.ScalingTime.Add(ch.ScalingKeys[k].Time);
                        }
                    }
                }

                // create and store the big scene tree
                _rootBone = CreateBoneTree(scene.RootNode, null);

                // set each bone offset
                foreach (var sceneMesh in scene.Meshes)
                {
                    foreach (var rawBone in sceneMesh.Bones)
                    {
                        ClientBone found;
                        if (!_allBoneLookup.TryGetValue(rawBone.Name, out found))
                        {
                            Console.WriteLine("Cannot find bone: " + rawBone.Name);
                            continue;
                        }

                        found.BoneOffset = rawBone.OffsetMatrix.ToMatrix();
                        _allBones.Add(found);
                        _allBoneMappings[found.BoneName] = _allBones.IndexOf(found);
                    }
                }

                // for bones not inside the meshes...? jasdkl;fja;lskdjkfl
                foreach (var boneName in _allBoneLookup.Keys.Where(b =>
                                                                   _allBones.All(b1 => b1.BoneName != b) && b.StartsWith("Bone")))
                {
                    _allBoneLookup[boneName].BoneOffset = _allBoneLookup[boneName].Parent.BoneOffset.Clone();
                    _allBones.Add(_allBoneLookup[boneName]);
                    _allBoneMappings[boneName] = _allBones.IndexOf(_allBoneLookup[boneName]);
                }

                // load the bone weights
                for (int idx = 0; idx < scene.MeshCount; idx++)
                {
                    LoadBoneWeights(scene.Meshes[idx], allMeshes[idx]);
                }

                //_boneTransformStream = new DataStream(MAX_BONES_PER_GEO * sizeof(float) * 16, true, true);
                _boneTransformList = new List <Matrix>(MAX_BONES_PER_GEO);
                for (int i = 0; i < MAX_BONES_PER_GEO; i++)
                {
                    _boneTransformList.Add(Matrix.Identity);
                }
            }

            // main loading loop; copy cover the scene content into the datastreams and then to the buffers
            for (int idx = 0; idx < scene.MeshCount; idx++)
            {
                ClientMesh mesh = allMeshes[idx];

                //create new datastreams.
                mesh.Vertices = new DataStream(mesh.vertSize, true, true);
                mesh.Normals  = new DataStream(mesh.normSize, true, true);
                mesh.Faces    = new DataStream(mesh.faceSize, true, true);

                // create a new material
                mesh.Materials = new ClientMaterial();

                //min and max bounds
                var min = new Vector3(float.MaxValue);
                var max = new Vector3(float.MinValue);
                // copy the buffers
                scene.Meshes[idx].Vertices.ForEach(vertex =>
                {
                    mesh.Vertices.Write(vertex.ToVector3());

                    //keep track of min and max for obj boundaries.
                    min = Vector3.Minimize(min, vertex.ToVector3());
                    max = Vector3.Maximize(max, vertex.ToVector3());
                });
                BoundingBoxes.Add(new BoundingBox(min, max));


                scene.Meshes[idx].Normals.ForEach(normal =>
                {
                    mesh.Normals.Write(normal.ToVector3());
                });
                scene.Meshes[idx].Faces.ForEach(face =>
                {
                    mesh.Faces.WriteRange(face.Indices.ToArray());
                });

                // check if the mesh has texture coordinates
                if (scene.Meshes[idx].HasTextureCoords(0))
                {
                    mesh.TexCoords = new DataStream(mesh.texSize, true, true);
                    scene.Meshes[idx].TextureCoordinateChannels[0].ForEach(texture => {
                        mesh.TexCoords.Write(texture);
                    });

                    mesh.TexCoords.Position = 0;
                }

                // Parse material properties
                ApplyMaterial(scene.Materials[scene.Meshes[idx].MaterialIndex], mesh.Materials);

                // reset datastream positions
                mesh.Vertices.Position = 0;
                mesh.Normals.Position  = 0;
                mesh.Faces.Position    = 0;

                //create vertex vbo and faces ebo.
                mesh.VBOPositions = new Buffer(GraphicsRenderer.Device, mesh.Vertices, mesh.vertSize, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
                mesh.VBONormals   = new Buffer(GraphicsRenderer.Device, mesh.Normals, mesh.normSize, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
                if (scene.Meshes[idx].HasTextureCoords(0))
                {
                    mesh.VBOTexCoords = new Buffer(GraphicsRenderer.Device, mesh.TexCoords, mesh.texSize, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
                }

                // buffer creation flags
                var ibd = new BufferDescription(
                    mesh.faceSize,
                    ResourceUsage.Immutable,
                    BindFlags.IndexBuffer,
                    CpuAccessFlags.None,
                    ResourceOptionFlags.None,
                    0);

                mesh.EBO = new Buffer(GraphicsRenderer.Device, mesh.Faces, ibd);
            }

            _inverseGlobalTransform = Matrix.Invert(scene.RootNode.Transform.ToMatrix());
        }