//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);
//if mesh has a material extract the diffuse texture, if present
Material material = scene.Materials[mesh.MaterialIndex];
if (material != null && material.GetMaterialTextureCount(TextureType.Diffuse) > 0)
{
TextureSlot texture;
material.GetMaterialTexture(TextureType.Diffuse, 0, out texture);
//create new texture for mesh
modelMesh.AddTextureDiffuse(device, m_modelPath + "\\" + texture.FilePath);
}
//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.ToArray();
Vector3D[] texCoords = mesh.TextureCoordinateChannels[0].ToArray();
Vector3D[] normals = mesh.Normals.ToArray();
Vector3D[] tangents = mesh.Tangents.ToArray();
Vector3D[] biTangents = mesh.BiTangents.ToArray();
Color4D[] colours = mesh.VertexColorChannels[0].ToArray();
//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.VertexColorChannels[0].ToArray()[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.GetUnsignedIndices();
//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;
}