Represents a model vertex with all available data from the model.

Models may store different data in different areas depending on what shader is intended to be used with the model. For example, some models might specify vertex colors, and others might use textures and bump maps.

Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Model"/> class.
        /// </summary>
        /// <param name="availableAnimations">
        /// The available animations.
        /// </param>
        /// <param name="rootBone">
        /// The root bone, or null if there's no skeletal information.
        /// </param>
        /// <param name="vertexes">
        /// The vertexes associated with this model.
        /// </param>
        /// <param name="indices">
        /// The indices associated with the model.
        /// </param>
        public Model(
            IModelRenderConfiguration[] modelRenderConfigurations,
            IRenderBatcher renderBatcher,
            string name,
            IAnimationCollection availableAnimations,
            IMaterial material,
            IModelBone rootBone,
            ModelVertex[] vertexes,
            int[] indices)
        {
            Name = name;
            AvailableAnimations = availableAnimations;
            Root = rootBone;
            Vertexes = vertexes;
            Indices = indices;
            Material = material;

            _cachedVertexBuffers = new Dictionary<object, VertexBuffer>();
            _modelRenderConfigurations = modelRenderConfigurations;
            _renderBatcher = renderBatcher;

            if (Root != null)
            {
                _flattenedBones = Root.Flatten();
                Bones = _flattenedBones.ToDictionary(k => k.Name, v => v);
            }
        }
        /// <summary>
        /// Serializes an array of model vertexes to a binary stream.
        /// </summary>
        /// <param name="writer">
        /// The binary writer to which the model vertexes will be serialized.
        /// </param>
        /// <param name="vertexes">
        /// The vertexes to serialize.
        /// </param>
        private void SerializeVertexes(BinaryWriter writer, ModelVertex[] vertexes)
        {
            writer.Write(vertexes.Length);

            for (var i = 0; i < vertexes.Length; i++)
            {
                var v = vertexes[i];

                if (v.Position != null)
                {
                    writer.Write(true);
                    this.SerializeVector3(writer, v.Position.Value);
                }
                else
                {
                    writer.Write(false);
                }

                if (v.Normal != null)
                {
                    writer.Write(true);
                    this.SerializeVector3(writer, v.Normal.Value);
                }
                else
                {
                    writer.Write(false);
                }

                if (v.Tangent != null && v.BiTangent != null)
                {
                    writer.Write(true);
                    this.SerializeVector3(writer, v.Tangent.Value);
                    this.SerializeVector3(writer, v.BiTangent.Value);
                }
                else
                {
                    writer.Write(false);
                }

                writer.Write(v.Colors.Length);
                for (var c = 0; c < v.Colors.Length; c++)
                {
                    this.SerializeColor(writer, v.Colors[c]);
                }

                writer.Write(v.TexCoordsUV.Length);
                for (var c = 0; c < v.TexCoordsUV.Length; c++)
                {
                    this.SerializeVector2(writer, v.TexCoordsUV[c]);
                }

                writer.Write(v.TexCoordsUVW.Length);
                for (var c = 0; c < v.TexCoordsUVW.Length; c++)
                {
                    this.SerializeVector3(writer, v.TexCoordsUVW[c]);
                }

                if (v.BoneIndices != null)
                {
                    writer.Write(true);
                    this.SerializeVector4(writer, v.BoneIndices.Value.ToVector4());
                }
                else
                {
                    writer.Write(false);
                }

                if (v.BoneWeights != null)
                {
                    writer.Write(true);
                    this.SerializeVector4(writer, v.BoneWeights.Value);
                }
                else
                {
                    writer.Write(false);
                }
            }
        }
Example #3
0
        /// <summary>
        /// Load an FBX file from a file on disk.
        /// </summary>
        /// <param name="filename">
        /// The filename of the FBX file to load.
        /// </param>
        /// <param name="additionalAnimationFiles">
        /// A dictionary mapping of animation names to filenames for additional FBX files to load.
        /// </param>
        /// <param name="options">Additional options for the import.</param>
        /// <returns>
        /// The loaded <see cref="IModel"/>.
        /// </returns>
        public IModel Load(string filename, string name, Dictionary <string, string> additionalAnimationFiles, string[] options)
        {
            this.LoadAssimpLibrary();

            // Import the scene via AssImp.
            var importer = new AssimpContext();
            PostProcessSteps ProcessFlags = 0;

            if (options == null)
            {
                ProcessFlags |= PostProcessSteps.FlipUVs | PostProcessSteps.Triangulate |
                                PostProcessSteps.FlipWindingOrder;
            }
            else
            {
                foreach (var v in options)
                {
                    PostProcessSteps flag;
                    if (Enum.TryParse(v, true, out flag))
                    {
                        ProcessFlags |= flag;
                        Console.Write("(on: " + flag + ") ");
                    }
                }
            }

            var scene = importer.ImportFile(filename, ProcessFlags);

            ModelVertex[] vertexes;
            int[]         indices;
            IModelBone    boneHierarchy;
            Material      material = null;

            if (scene.MeshCount >= 1)
            {
                var boneWeightingMap   = this.BuildBoneWeightingMap(scene);
                var staticTransformMap = this.BuildStaticTransformMap(scene);

                if (options?.Contains("!NoBoneHierarchy") ?? false)
                {
                    boneHierarchy = null;
                }
                else
                {
                    boneHierarchy = this.ImportBoneHierarchy(scene.RootNode, scene.Meshes[0]);
                }

                vertexes = this.ImportVertexes(scene, boneWeightingMap, staticTransformMap);
                indices  = this.ImportIndices(scene);
            }
            else
            {
                boneHierarchy = this.ImportBoneHierarchy(scene.RootNode, null);
                vertexes      = new ModelVertex[0];
                indices       = new int[0];
            }

            // If the scene has materials associated with it, and the mesh has
            // a material associated with it, read in the material information.
            if (scene.MeshCount >= 1 && scene.MaterialCount > scene.Meshes[0].MaterialIndex)
            {
                var assimpMaterial = scene.Materials[scene.Meshes[0].MaterialIndex];

                material = ConvertMaterial(assimpMaterial);
            }

            // Create the list of animations, including the null animation.
            var animations = new List <IAnimation>();

            // Import the basic animation.
            if (scene.AnimationCount > 0)
            {
                animations.AddRange(
                    scene.Animations.Select(
                        assimpAnimation => this.ImportAnimation(assimpAnimation.Name, assimpAnimation)));
            }

            // For each additional animation file, import that and add the animation to the existing scene.
            animations.AddRange(
                from kv in additionalAnimationFiles
                let animationImporter = new AssimpContext()
                                        let additionalScene = animationImporter.ImportFile(kv.Value, ProcessFlags)
                                                              where additionalScene.AnimationCount == 1
                                                              select this.ImportAnimation(kv.Key, additionalScene.Animations[0]));

            // Return the resulting model.
            return(new Model(
                       _modelRenderConfigurations,
                       _renderBatcher,
                       name,
                       new AnimationCollection(animations),
                       material,
                       boneHierarchy,
                       vertexes,
                       indices));
        }
        /// <summary>
        /// Serializes an array of model vertexes to a binary stream.
        /// </summary>
        /// <param name="writer">
        /// The binary writer to which the model vertexes will be serialized.
        /// </param>
        /// <param name="vertexes">
        /// The vertexes to serialize.
        /// </param>
        private void SerializeVertexes(BinaryWriter writer, ModelVertex[] vertexes)
        {
            writer.Write(vertexes.Length);

            for (var i = 0; i < vertexes.Length; i++)
            {
                this.SerializeVector3(writer, vertexes[i].Position ?? Vector3.Zero);
                this.SerializeVector3(writer, vertexes[i].Normal ?? Vector3.Zero);
                this.SerializeVector2(writer, vertexes[i].TexCoordsUV[0]);
                this.SerializeVector4(writer, vertexes[i].BoneWeights ?? Vector4.Zero);
                this.SerializeVector4(writer, (vertexes[i].BoneIndices ?? new Byte4()).ToVector4());
            }
        }
Example #5
0
        /// <summary>
        /// Load an FBX file from a file on disk.
        /// </summary>
        /// <param name="filename">
        /// The filename of the FBX file to load.
        /// </param>
        /// <param name="additionalAnimationFiles">
        /// A dictionary mapping of animation names to filenames for additional FBX files to load.
        /// </param>
        /// <param name="options">Additional options for the import.</param>
        /// <returns>
        /// The loaded <see cref="IModel"/>.
        /// </returns>
        public IModel Load(string filename, string name, Dictionary<string, string> additionalAnimationFiles, string[] options)
        {
            this.LoadAssimpLibrary();

            // Import the scene via AssImp.
            var importer = new AssimpContext();
            PostProcessSteps ProcessFlags = 0;
            if (options == null)
            {
                ProcessFlags |= PostProcessSteps.FlipUVs | PostProcessSteps.Triangulate |
                                PostProcessSteps.FlipWindingOrder;
            }
            else
            {
                foreach (var v in options)
                {
                    PostProcessSteps flag;
                    if (Enum.TryParse(v, true, out flag))
                    {
                        ProcessFlags |= flag;
                        Console.Write("(on: " + flag + ") ");
                    }
                }
            }
            
            var scene = importer.ImportFile(filename, ProcessFlags);

            ModelVertex[] vertexes;
            int[] indices;
            IModelBone boneHierarchy;
            Material material = null;

            if (scene.MeshCount >= 1)
            {
                var boneWeightingMap = this.BuildBoneWeightingMap(scene);
                var staticTransformMap = this.BuildStaticTransformMap(scene);
                
                if (options?.Contains("!NoBoneHierarchy") ?? false)
                {
                    boneHierarchy = null;
                }
                else
                {
                    boneHierarchy = this.ImportBoneHierarchy(scene.RootNode, scene.Meshes[0]);
                }

                vertexes = this.ImportVertexes(scene, boneWeightingMap, staticTransformMap);
                indices = this.ImportIndices(scene);
            }
            else
            {
                boneHierarchy = this.ImportBoneHierarchy(scene.RootNode, null);
                vertexes = new ModelVertex[0];
                indices = new int[0];
            }
            
            // If the scene has materials associated with it, and the mesh has
            // a material associated with it, read in the material information.
            if (scene.MeshCount >= 1 && scene.MaterialCount > scene.Meshes[0].MaterialIndex)
            {
                var assimpMaterial = scene.Materials[scene.Meshes[0].MaterialIndex];

                material = ConvertMaterial(assimpMaterial);
            }

            // Create the list of animations, including the null animation.
            var animations = new List<IAnimation>();

            // Import the basic animation.
            if (scene.AnimationCount > 0)
            {
                animations.AddRange(
                    scene.Animations.Select(
                        assimpAnimation => this.ImportAnimation(assimpAnimation.Name, assimpAnimation)));
            }

            // For each additional animation file, import that and add the animation to the existing scene.
            animations.AddRange(
                from kv in additionalAnimationFiles
                let animationImporter = new AssimpContext()
                let additionalScene = animationImporter.ImportFile(kv.Value, ProcessFlags)
                where additionalScene.AnimationCount == 1
                select this.ImportAnimation(kv.Key, additionalScene.Animations[0]));

            // Return the resulting model.
            return new Model(
                _modelRenderConfigurations,
                _renderBatcher,
                name,
                new AnimationCollection(animations),
                material,
                boneHierarchy, 
                vertexes,
                indices);
        }