Ejemplo n.º 1
0
        void WriteBarycentricVertices(Mesh assimpMesh, ModelData.MeshPart meshPart, ModelData.VertexBuffer vertexBuffer, int vertexBufferElementSize)
        {
            //System.Diagnostics.Debugger.Launch();
            int[] indices    = assimpMesh.GetIntIndices();
            int   indexCount = indices.Length;

            // Write all vertices
            meshPart.VertexBufferRange.Count = indexCount;
            vertexBuffer.Count  = indexCount;
            vertexBuffer.Buffer = new byte[vertexBufferElementSize * indexCount];

            // Update the MaximumBufferSizeInBytes needed to load this model
            if (vertexBuffer.Buffer.Length > model.MaximumBufferSizeInBytes)
            {
                model.MaximumBufferSizeInBytes = vertexBuffer.Buffer.Length;
            }

            var vertexStream = DataStream.Create(vertexBuffer.Buffer, true, true);

            boundingPoints = new Vector3[indexCount];
            var newVertices = new VertexPositionNormalTexture[indices.Length];

            for (int i = 0; i < indexCount; i++)
            {
                try
                {
                    int i0 = indices[i];
                    var v0 = assimpMesh.Vertices[i0];
                    var v  = new Vector3(v0.X, v0.Y, v0.Z);

                    var n0 = assimpMesh.Normals[i0];
                    var n  = new Vector3(n0.X, n0.Y, n0.Z);

                    var uv = assimpMesh.GetTextureCoords(0)[i0];
                    var t  = new Vector2(uv.X, uv.Y);

                    // Store bounding points for BoundingSphere pre-calculation
                    boundingPoints[currentBoundingPointIndex++] = v;
                    newVertices[i0] = new VertexPositionNormalTexture(v, n, t);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("!" + ex);
                }
            }
            var barycentricVertices = ModelEditor.ConvertToBarycentricEdgeNormalVertices(newVertices, indices);

            foreach (var vertex in barycentricVertices)
            {
                vertexStream.Write(vertex.Position);
                vertexStream.Write(vertex.Normal);
                vertexStream.Write(vertex.TextureUV);
                vertexStream.Write(vertex.Barycentric);
            }

            vertexStream.Dispose();
        }
Ejemplo n.º 2
0
        private ModelData.MeshPart Process(ModelData.Mesh mesh, Assimp.Mesh assimpMesh)
        {
            var meshPart = new ModelData.MeshPart()
            {
                MaterialIndex     = assimpMesh.MaterialIndex,
                VertexBufferRange = new ModelData.BufferRange()
                {
                    Slot = mesh.VertexBuffers.Count
                },
                IndexBufferRange = new ModelData.BufferRange()
                {
                    Slot = mesh.IndexBuffers.Count
                }
            };

            var vertexBuffer = new ModelData.VertexBuffer()
            {
                Layout = new List <VertexElement>()
            };

            mesh.VertexBuffers.Add(vertexBuffer);

            var indexBuffer = new ModelData.IndexBuffer();

            mesh.IndexBuffers.Add(indexBuffer);

            var layout = vertexBuffer.Layout;

            int vertexBufferElementSize = 0;

            // Add position
            layout.Add(VertexElement.PositionTransformed(Format.R32G32B32_Float, 0));
            vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector3>();

            // Add normals
            if (assimpMesh.HasNormals)
            {
                layout.Add(VertexElement.Normal(0, Format.R32G32B32_Float, vertexBufferElementSize));
                vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector3>();
            }

            // Add colors
            if (assimpMesh.VertexColorChannelCount > 0)
            {
                for (int localIndex = 0, i = 0; i < assimpMesh.VertexColorChannelCount; i++)
                {
                    if (assimpMesh.HasVertexColors(i))
                    {
                        layout.Add(VertexElement.Color(localIndex, Format.R32G32B32A32_Float, vertexBufferElementSize));
                        vertexBufferElementSize += Utilities.SizeOf <SharpDX.Color4>();
                        localIndex++;
                    }
                }
            }

            // Add textures
            if (assimpMesh.TextureCoordsChannelCount > 0)
            {
                for (int localIndex = 0, i = 0; i < assimpMesh.TextureCoordsChannelCount; i++)
                {
                    if (assimpMesh.HasTextureCoords(i))
                    {
                        var uvCount = assimpMesh.GetUVComponentCount(i);

                        if (uvCount == 2)
                        {
                            layout.Add(VertexElement.TextureCoordinate(localIndex, Format.R32G32_Float, vertexBufferElementSize));
                            vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector2>();
                        }
                        else if (uvCount == 3)
                        {
                            layout.Add(VertexElement.TextureCoordinate(localIndex, Format.R32G32B32_Float, vertexBufferElementSize));
                            vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector3>();
                        }
                        else
                        {
                            throw new InvalidOperationException("Unexpected uv count");
                        }

                        localIndex++;
                    }
                }
            }

            // Add tangent / bitangent
            if (assimpMesh.HasTangentBasis)
            {
                layout.Add(VertexElement.Tangent(Format.R32G32B32_Float, vertexBufferElementSize));
                vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector3>();

                layout.Add(VertexElement.BiTangent(Format.R32G32B32_Float, vertexBufferElementSize));
                vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector3>();
            }

            // Extract Skinning Indices / Weights
            bool hasWeights      = false;
            var  skinningCount   = new int[assimpMesh.VertexCount];
            var  skinningIndices = new Int4[assimpMesh.VertexCount];
            var  skinningWeights = new Vector4[assimpMesh.VertexCount];

            if (assimpMesh.HasBones)
            {
                meshPart.BoneOffsetMatrices = new Matrix[assimpMesh.BoneCount];
                for (int i = 0; i < assimpMesh.Bones.Length; i++)
                {
                    var bone = assimpMesh.Bones[i];
                    meshPart.BoneOffsetMatrices[i] = ConvertMatrix(bone.OffsetMatrix);
                    if (bone.HasVertexWeights)
                    {
                        var boneNode  = scene.RootNode.FindNode(bone.Name);
                        var boneIndex = skinnedBones[boneNode];
                        for (int j = 0; j < bone.VertexWeightCount; j++)
                        {
                            var weights             = bone.VertexWeights[j];
                            var vertexSkinningCount = skinningCount[weights.VertexID];

                            skinningIndices[weights.VertexID][vertexSkinningCount] = boneIndex;

                            skinningWeights[weights.VertexID][vertexSkinningCount] = weights.Weight;

                            skinningCount[weights.VertexID] = ++vertexSkinningCount;
                        }

                        hasWeights = true;
                    }
                }

                if (hasWeights)
                {
                    layout.Add(VertexElement.BlendIndices(Format.R16G16B16A16_SInt, vertexBufferElementSize));
                    vertexBufferElementSize += Utilities.SizeOf <SharpDX.Int4>();

                    layout.Add(VertexElement.BlendWeights(Format.R32G32B32A32_Float, vertexBufferElementSize));
                    vertexBufferElementSize += Utilities.SizeOf <SharpDX.Vector4>();
                }
            }

            // Write all vertices
            meshPart.VertexBufferRange.Count = assimpMesh.VertexCount;
            vertexBuffer.Count  = assimpMesh.VertexCount;
            vertexBuffer.Buffer = new byte[vertexBufferElementSize * assimpMesh.VertexCount];

            // Update the MaximumBufferSizeInBytes needed to load this model
            if (vertexBuffer.Buffer.Length > model.MaximumBufferSizeInBytes)
            {
                model.MaximumBufferSizeInBytes = vertexBuffer.Buffer.Length;
            }

            var vertexStream = DataStream.Create(vertexBuffer.Buffer, true, true);

            for (int i = 0; i < assimpMesh.VertexCount; i++)
            {
                var position = assimpMesh.Vertices[i];
                vertexStream.Write(position);

                // Store bounding points for BoundingSphere pre-calculation
                boundingPoints[currentBoundingPointIndex++] = new Vector3(position.X, position.Y, position.Z);

                // Add normals
                if (assimpMesh.HasNormals)
                {
                    vertexStream.Write(assimpMesh.Normals[i]);
                }

                // Add colors
                if (assimpMesh.VertexColorChannelCount > 0)
                {
                    for (int j = 0; j < assimpMesh.VertexColorChannelCount; j++)
                    {
                        if (assimpMesh.HasVertexColors(j))
                        {
                            vertexStream.Write(assimpMesh.GetVertexColors(j)[i]);
                        }
                    }
                }

                // Add textures
                if (assimpMesh.TextureCoordsChannelCount > 0)
                {
                    for (int j = 0; j < assimpMesh.TextureCoordsChannelCount; j++)
                    {
                        if (assimpMesh.HasTextureCoords(j))
                        {
                            var uvCount = assimpMesh.GetUVComponentCount(j);

                            var uv = assimpMesh.GetTextureCoords(j)[i];

                            if (uvCount == 2)
                            {
                                vertexStream.Write(new Vector2(uv.X, uv.Y));
                            }
                            else
                            {
                                vertexStream.Write(uv);
                            }
                        }
                    }
                }

                // Add tangent / bitangent
                if (assimpMesh.HasTangentBasis)
                {
                    vertexStream.Write(assimpMesh.Tangents[i]);
                    vertexStream.Write(assimpMesh.BiTangents[i]);
                }

                // Add Skinning Indices/Weights
                if (assimpMesh.HasBones && hasWeights)
                {
                    vertexStream.Write(skinningIndices[i]);
                    vertexStream.Write(skinningWeights[i]);
                }
            }
            vertexStream.Dispose();

            // Write all indices
            var indices = assimpMesh.GetIntIndices();

            indexBuffer.Count = indices.Length;
            meshPart.IndexBufferRange.Count = indices.Length;
            if (meshPart.VertexBufferRange.Count < 65536)
            {
                // Write only short indices if count is less than the size of a short
                indexBuffer.Buffer = new byte[indices.Length * 2];
                using (var indexStream = DataStream.Create(indexBuffer.Buffer, true, true))
                    foreach (int index in indices)
                    {
                        indexStream.Write((ushort)index);
                    }
            }
            else
            {
                // Otherwise, use full 32-bit precision to store indices
                indexBuffer.Buffer = new byte[indices.Length * 4];
                using (var indexStream = DataStream.Create(indexBuffer.Buffer, true, true))
                    indexStream.WriteRange(indices);
            }

            // Update the MaximumBufferSizeInBytes needed to load this model
            if (indexBuffer.Buffer.Length > model.MaximumBufferSizeInBytes)
            {
                model.MaximumBufferSizeInBytes = indexBuffer.Buffer.Length;
            }

            return(meshPart);
        }
Ejemplo n.º 3
0
        private void LoadFromNode(Assimp.Scene _scene, Assimp.Node _node, GraphicsDevice _device, SharpDX.Toolkit.Content.ContentManager _content, Matrix _transform)
        {
            // Sum up transformations recursively
            _transform = FromMatrix(_node.Transform) * _transform;
            Matrix transformInvTr = Helpers.CreateInverseTranspose(ref _transform);

            // Recursive load from scene
            if (_node.HasChildren)
            {
                foreach (Assimp.Node node in _node.Children)
                {
                    LoadFromNode(_scene, node, _device, _content, _transform);
                }
            }

            if (_node.HasMeshes)
            {
                foreach (int meshIndex in _node.MeshIndices)
                {
                    Assimp.Mesh mesh      = _scene.Meshes[meshIndex];
                    ModelMesh   modelMesh = new ModelMesh();

                    // if mesh has a diffuse texture extract it
                    Assimp.Material material = _scene.Materials[mesh.MaterialIndex];
                    if (material != null && material.GetTextureCount(TextureType.Diffuse) > 0)
                    {
                        TextureSlot texture = material.GetTexture(TextureType.Diffuse, 0);
                        // Create new texture for mesh
                        var dxtexture = _content.Load <Texture2D>(texture.FilePath);
                        modelMesh.DiffuseTexture = dxtexture;
                    }

                    // Position is mandarory
                    if (!mesh.HasVertices)
                    {
                        throw new Exception("Model::Model(): Model has no vertices.");
                    }

                    // Determine the elements in the vertex
                    bool hasTexCoords  = mesh.HasTextureCoords(0);
                    bool hasColors     = mesh.HasVertexColors(0);
                    bool hasNormals    = mesh.HasNormals;
                    bool hasTangents   = mesh.Tangents != null;
                    bool hasBitangents = mesh.BiTangents != null;
                    int  numElements   = 1 + (hasTexCoords ? 1 : 0) + (hasColors ? 1 : 0) + (hasNormals ? 1 : 0) + (hasTangents ? 1 : 0) + (hasBitangents ? 1 : 0);

                    // Create vertex element list: Here starts the section of creating SharpDX stuff
                    VertexElement[] vertexElements = new VertexElement[numElements];
                    uint            elementIndex   = 0;
                    vertexElements[elementIndex++] = new VertexElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32_Float, 0);
                    int vertexSize = Utilities.SizeOf <Vector3>();

                    if (hasColors)
                    {
                        vertexElements[elementIndex++] = new VertexElement("COLOR", 0, SharpDX.DXGI.Format.R8G8B8A8_UInt, vertexSize);
                        vertexSize += Utilities.SizeOf <Color>();
                    }
                    if (hasNormals)
                    {
                        vertexElements[elementIndex++] = new VertexElement("NORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float, vertexSize);
                        vertexSize += Utilities.SizeOf <Vector3>();
                    }
                    if (hasTangents)
                    {
                        vertexElements[elementIndex++] = new VertexElement("TANGENT", 0, SharpDX.DXGI.Format.R32G32B32_Float, vertexSize);
                        vertexSize += Utilities.SizeOf <Vector3>();
                    }
                    if (hasBitangents)
                    {
                        vertexElements[elementIndex++] = new VertexElement("BITANGENT", 0, SharpDX.DXGI.Format.R32G32B32_Float, vertexSize);
                        vertexSize += Utilities.SizeOf <Vector3>();
                    }
                    if (hasTexCoords)
                    {
                        vertexElements[elementIndex++] = new VertexElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float, vertexSize);
                        vertexSize += Utilities.SizeOf <Vector2>();
                    }

                    // Set the vertex elements and size
                    modelMesh.InputLayout = VertexInputLayout.New(VertexBufferLayout.New(0, vertexElements));
                    modelMesh.VertexSize  = vertexSize;

                    // Determine primitive type
                    switch (mesh.PrimitiveType)
                    {
                    case Assimp.PrimitiveType.Point:    modelMesh.PrimitiveTopology = SharpDX.Toolkit.Graphics.PrimitiveType.PointList;    break;

                    case Assimp.PrimitiveType.Line:     modelMesh.PrimitiveTopology = SharpDX.Toolkit.Graphics.PrimitiveType.LineList;     break;

                    case Assimp.PrimitiveType.Triangle: modelMesh.PrimitiveTopology = SharpDX.Toolkit.Graphics.PrimitiveType.TriangleList; break;

                    default:                            throw new Exception("Model::Model(): Unknown primitive type");
                    }

                    // Create data stream for vertices
                    //System.IO.MemoryStream vertexStream = new System.IO.MemoryStream(mesh.VertexCount * vertexSize);
                    DataStream vertexStream = new DataStream(mesh.VertexCount * vertexSize, true, true);

                    for (int i = 0; i < mesh.VertexCount; i++)
                    {
                        vertexStream.Write <Vector3>(Helpers.Transform(FromVector(mesh.Vertices[i]), ref _transform));
                        if (hasColors)
                        {
                            vertexStream.Write <Color>(FromColor(mesh.GetVertexColors(0)[i]));
                        }
                        if (hasNormals)
                        {
                            vertexStream.Write <Vector3>(Helpers.Transform(FromVector(mesh.Normals[i]), ref transformInvTr));
                        }
                        if (hasTangents)
                        {
                            vertexStream.Write <Vector3>(Helpers.Transform(FromVector(mesh.Tangents[i]), ref transformInvTr));
                        }
                        if (hasBitangents)
                        {
                            vertexStream.Write <Vector3>(Helpers.Transform(FromVector(mesh.BiTangents[i]), ref transformInvTr));
                        }
                        if (hasTexCoords)
                        {
                            vertexStream.Write <Vector2>(new Vector2(mesh.GetTextureCoords(0)[i].X, mesh.GetTextureCoords(0)[i].Y));
                        }
                    }

                    vertexStream.Position = 0;

                    // Create new vertex buffer
                    var vertexBuffer = SharpDX.Toolkit.Graphics.Buffer.Vertex.New(_device, vertexStream);

                    // Add it to the mesh
                    modelMesh.VertexBuffer   = vertexBuffer;
                    modelMesh.VertexCount    = mesh.VertexCount;
                    modelMesh.PrimitiveCount = mesh.FaceCount;

                    // Create new index buffer
                    var indexBuffer = SharpDX.Toolkit.Graphics.Buffer.Index.New(_device, mesh.GetIndices());

                    // Add it to the mesh
                    modelMesh.IndexBuffer = indexBuffer;
                    modelMesh.IndexCount  = mesh.GetIndices().GetLength(0);

                    m_meshes.Add(modelMesh);
                }
            }
        }
Ejemplo n.º 4
0
        private IEnumerable<PosNormalTexTanSkinned> ExtractVertices(Mesh mesh, IReadOnlyDictionary<uint, List<VertexWeight>> vertToBoneWeights, bool flipTexY)
        {
            var verts = new List<PosNormalTexTanSkinned>();
            for (var i = 0; i < mesh.VertexCount; i++) {
                var pos = mesh.HasVertices ? mesh.Vertices[i].ToVector3() : new Vector3();
                _min = Vector3.Minimize(_min, pos);
                _max = Vector3.Maximize(_max, pos);

                var norm = mesh.HasNormals ? mesh.Normals[i] : new Vector3D();

                var tan = mesh.HasTangentBasis ? mesh.Tangents[i] : new Vector3D();
                var texC = new Vector3D();
                if (mesh.HasTextureCoords(0)) {
                    var coord = mesh.GetTextureCoords(0)[i];
                    if (flipTexY) {
                        coord.Y = -coord.Y;
                    }
                    texC = coord;
                }

                var weights = vertToBoneWeights[(uint) i].Select(w => w.Weight).ToArray();
                var boneIndices = vertToBoneWeights[(uint) i].Select(w => (byte) w.VertexID).ToArray();

                var v = new PosNormalTexTanSkinned(pos, norm.ToVector3(), texC.ToVector2(), tan.ToVector3(), weights.First(), boneIndices);
                verts.Add(v);
            }
            return verts;
        }
Ejemplo n.º 5
0
        void WriteVertices(Mesh assimpMesh, ModelData.MeshPart meshPart, ModelData.VertexBuffer vertexBuffer, int vertexBufferElementSize)
        {
            // Write all vertices
            meshPart.VertexBufferRange.Count = assimpMesh.VertexCount;
            vertexBuffer.Count  = assimpMesh.VertexCount;
            vertexBuffer.Buffer = new byte[vertexBufferElementSize * assimpMesh.VertexCount];

            // Update the MaximumBufferSizeInBytes needed to load this model
            if (vertexBuffer.Buffer.Length > model.MaximumBufferSizeInBytes)
            {
                model.MaximumBufferSizeInBytes = vertexBuffer.Buffer.Length;
            }

            var vertexStream = DataStream.Create(vertexBuffer.Buffer, true, true);

            for (int i = 0; i < assimpMesh.VertexCount; i++)
            {
                var position = assimpMesh.Vertices[i];
                vertexStream.Write(position);

                // Store bounding points for BoundingSphere pre-calculation
                boundingPoints[currentBoundingPointIndex++] = new Vector3(position.X, position.Y, position.Z);

                // Add normals
                if (assimpMesh.HasNormals)
                {
                    vertexStream.Write(assimpMesh.Normals[i]);
                }

                // Add colors
                if (assimpMesh.VertexColorChannelCount > 0)
                {
                    for (int j = 0; j < assimpMesh.VertexColorChannelCount; j++)
                    {
                        if (assimpMesh.HasVertexColors(j))
                        {
                            vertexStream.Write(assimpMesh.GetVertexColors(j)[i]);
                        }
                    }
                }

                // Add textures
                if (assimpMesh.TextureCoordsChannelCount > 0)
                {
                    for (int j = 0; j < assimpMesh.TextureCoordsChannelCount; j++)
                    {
                        if (assimpMesh.HasTextureCoords(j))
                        {
                            var uvCount = assimpMesh.GetUVComponentCount(j);

                            var uv = assimpMesh.GetTextureCoords(j)[i];

                            if (uvCount == 2)
                            {
                                vertexStream.Write(new Vector2(uv.X, uv.Y));
                            }
                            else
                            {
                                vertexStream.Write(uv);
                            }
                        }
                    }
                }

                // Add tangent / bitangent
                if (assimpMesh.HasTangentBasis)
                {
                    if (!options.ExcludeElements.Contains("Tangent"))
                    {
                        double w = Vector3D.Dot(assimpMesh.Normals[i],
                                                Vector3D.Cross(assimpMesh.Tangents[i], assimpMesh.Tangents[i]));
                        Vector3D t   = assimpMesh.Tangents[i];
                        Vector4  t4D = new Vector4(t.X, t.Y, t.Z, (float)w);
                        vertexStream.Write(t4D);
                    }
                    if (!options.ExcludeElements.Contains("BiTangent"))
                    {
                        vertexStream.Write(assimpMesh.BiTangents[i]);
                    }
                }
            }
            vertexStream.Dispose();
        }
Ejemplo n.º 6
0
        //Create meshes and add vertex and index buffers
        private void AddVertexData(Model model, Scene scene, Node node, Device device, ref Matrix transform)
        {
            Matrix previousTransform = transform;

            transform = Matrix.Multiply(previousTransform, FromMatrix(node.Transform));

            //also calculate inverse transpose matrix for normal/tangent/bitagent transformation
            Matrix invTranspose = transform;

            invTranspose.Invert();
            invTranspose.Transpose();

            if (node.HasMeshes)
            {
                foreach (int index in node.MeshIndices)
                {
                    //get a mesh from the scene
                    Assimp.Mesh mesh = scene.Meshes[index];

                    //create new mesh to add to model
                    ModelMesh modelMesh = new ModelMesh();
                    model.AddMesh(ref modelMesh);

                    //determine the elements in the vertex
                    bool hasTexCoords  = mesh.HasTextureCoords(0);
                    bool hasColors     = mesh.HasVertexColors(0);
                    bool hasNormals    = mesh.HasNormals;
                    bool hasTangents   = mesh.Tangents != null;
                    bool hasBitangents = mesh.BiTangents != null;

                    //create vertex element list
                    InputElement[] vertexElements = new InputElement[GetNoofInputElements(mesh)];
                    uint           elementIndex   = 0;
                    vertexElements[elementIndex++] = new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0);
                    short vertexSize = (short)Utilities.SizeOf <Vector3>();

                    if (hasColors)
                    {
                        vertexElements[elementIndex++] = new InputElement("COLOR", 0, Format.R8G8B8A8_UInt, vertexSize, 0);
                        vertexSize += (short)Utilities.SizeOf <Color>();
                    }
                    if (hasNormals)
                    {
                        vertexElements[elementIndex++] = new InputElement("NORMAL", 0, Format.R32G32B32_Float, vertexSize, 0);
                        vertexSize += (short)Utilities.SizeOf <Vector3>();
                    }
                    if (hasTangents)
                    {
                        vertexElements[elementIndex++] = new InputElement("TANGENT", 0, Format.R32G32B32_Float, vertexSize, 0);
                        vertexSize += (short)Utilities.SizeOf <Vector3>();
                    }
                    if (hasBitangents)
                    {
                        vertexElements[elementIndex++] = new InputElement("BITANGENT", 0, Format.R32G32B32_Float, vertexSize, 0);
                        vertexSize += (short)Utilities.SizeOf <Vector3>();
                    }
                    if (hasTexCoords)
                    {
                        vertexElements[elementIndex++] = new InputElement("TEXCOORD", 0, Format.R32G32_Float, vertexSize, 0);
                        vertexSize += (short)Utilities.SizeOf <Vector2>();
                    }

                    //set the vertex elements and size
                    modelMesh.InputElements = vertexElements;
                    modelMesh.VertexSize    = vertexSize;

                    //get pointers to vertex data
                    Vector3D[] positions  = mesh.Vertices;
                    Vector3D[] texCoords  = mesh.GetTextureCoords(0);
                    Vector3D[] normals    = mesh.Normals;
                    Vector3D[] tangents   = mesh.Tangents;
                    Vector3D[] biTangents = mesh.BiTangents;
                    Color4D[]  colours    = mesh.GetVertexColors(0);

                    //also determine primitive type
                    switch (mesh.PrimitiveType)
                    {
                    case Assimp.PrimitiveType.Point:
                        modelMesh.PrimitiveTopology = PrimitiveTopology.PointList;
                        break;

                    case Assimp.PrimitiveType.Line:
                        modelMesh.PrimitiveTopology = PrimitiveTopology.LineList;
                        break;

                    case Assimp.PrimitiveType.Triangle:
                        modelMesh.PrimitiveTopology = PrimitiveTopology.TriangleList;
                        break;

                    default:
                        throw new Exception("ModelLoader::AddVertexData(): Unknown primitive type");
                    }

                    //create data stream for vertices
                    DataStream vertexStream = new DataStream(mesh.VertexCount * vertexSize, true, true);

                    for (int i = 0; i < mesh.VertexCount; i++)
                    {
                        //add position, after transforming it with accumulated node transform
                        {
                            Vector4 result;
                            Vector3 pos = FromVector(positions[i]);
                            Vector3.Transform(ref pos, ref transform, out result);
                            vertexStream.Write <Vector3>(new Vector3(result.X, result.Y, result.Z));
                        }

                        if (hasColors)
                        {
                            Color vertColor = FromColor(mesh.GetVertexColors(0)[i]);
                            vertexStream.Write <Color>(vertColor);
                        }
                        if (hasNormals)
                        {
                            Vector4 result;
                            Vector3 normal = FromVector(normals[i]);
                            Vector3.Transform(ref normal, ref invTranspose, out result);
                            vertexStream.Write <Vector3>(new Vector3(result.X, result.Y, result.Z));
                        }
                        if (hasTangents)
                        {
                            Vector4 result;
                            Vector3 tangent = FromVector(tangents[i]);
                            Vector3.Transform(ref tangent, ref invTranspose, out result);
                            vertexStream.Write <Vector3>(new Vector3(result.X, result.Y, result.Z));
                        }
                        if (hasBitangents)
                        {
                            Vector4 result;
                            Vector3 biTangent = FromVector(biTangents[i]);
                            Vector3.Transform(ref biTangent, ref invTranspose, out result);
                            vertexStream.Write <Vector3>(new Vector3(result.X, result.Y, result.Z));
                        }
                        if (hasTexCoords)
                        {
                            vertexStream.Write <Vector2>(new Vector2(texCoords[i].X, 1 - texCoords[i].Y));
                        }
                    }

                    vertexStream.Position = 0;

                    //create new vertex buffer
                    var vertexBuffer = new Buffer(device,
                                                  vertexStream,
                                                  new BufferDescription()
                    {
                        BindFlags      = BindFlags.VertexBuffer,
                        CpuAccessFlags = CpuAccessFlags.None,
                        OptionFlags    = ResourceOptionFlags.None,
                        SizeInBytes    = mesh.VertexCount * vertexSize,
                        Usage          = ResourceUsage.Default
                    }
                                                  );

                    //add it to the mesh
                    modelMesh.VertexBuffer   = vertexBuffer;
                    modelMesh.VertexCount    = mesh.VertexCount;
                    modelMesh.PrimitiveCount = mesh.FaceCount;

                    //get pointer to indices data
                    uint[] indices = mesh.GetIndices();

                    //create data stream for indices
                    DataStream indexStream = new DataStream(indices.GetLength(0) * sizeof(uint), true, true);

                    for (int i = 0; i < indices.GetLength(0); i++)
                    {
                        indexStream.Write <uint>(indices[i]);
                    }

                    indexStream.Position = 0;

                    //create new index buffer
                    var indexBuffer = new Buffer(device,
                                                 indexStream,
                                                 new BufferDescription()
                    {
                        BindFlags      = BindFlags.IndexBuffer,
                        CpuAccessFlags = CpuAccessFlags.None,
                        OptionFlags    = ResourceOptionFlags.None,
                        SizeInBytes    = indices.GetLength(0) * sizeof(uint),
                        Usage          = ResourceUsage.Default
                    }
                                                 );

                    //add it to the mesh
                    modelMesh.IndexBuffer = indexBuffer;
                    modelMesh.IndexCount  = indices.GetLength(0);
                }
            }

            //if node has more children process them as well
            for (int i = 0; i < node.ChildCount; i++)
            {
                AddVertexData(model, scene, node.Children[i], device, ref transform);
            }

            transform = previousTransform;
        }