in MiniEngine/ModelConverter/ModelAssimp.cpp [93:387]
bool AssimpModel::LoadAssimp(const string& filename)
{
Assimp::Importer importer;
// remove unused data
importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
aiComponent_COLORS | aiComponent_LIGHTS | aiComponent_CAMERAS);
// max triangles and vertices per mesh, splits above this threshold
importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, INT_MAX);
importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, 0xfffe); // avoid the primitive restart index
// remove points and lines
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
const aiScene *scene = importer.ReadFile(filename,
aiProcess_CalcTangentSpace |
aiProcess_JoinIdenticalVertices |
aiProcess_Triangulate |
aiProcess_RemoveComponent |
aiProcess_GenSmoothNormals |
aiProcess_SplitLargeMeshes |
aiProcess_ValidateDataStructure |
//aiProcess_ImproveCacheLocality | // handled by optimizePostTransform()
aiProcess_RemoveRedundantMaterials |
aiProcess_SortByPType |
aiProcess_FindInvalidData |
aiProcess_GenUVCoords |
aiProcess_TransformUVCoords |
aiProcess_OptimizeMeshes |
aiProcess_OptimizeGraph);
if (scene == nullptr)
return false;
if (scene->HasTextures())
{
// embedded textures...
}
if (scene->HasAnimations())
{
// todo
}
m_Header.materialCount = scene->mNumMaterials;
m_pMaterial = new Material [m_Header.materialCount];
memset(m_pMaterial, 0, sizeof(Material) * m_Header.materialCount);
for (unsigned int materialIndex = 0; materialIndex < scene->mNumMaterials; materialIndex++)
{
const aiMaterial *srcMat = scene->mMaterials[materialIndex];
Material *dstMat = m_pMaterial + materialIndex;
aiColor3D diffuse(1.0f, 1.0f, 1.0f);
aiColor3D specular(1.0f, 1.0f, 1.0f);
aiColor3D ambient(1.0f, 1.0f, 1.0f);
aiColor3D emissive(0.0f, 0.0f, 0.0f);
aiColor3D transparent(1.0f, 1.0f, 1.0f);
float opacity = 1.0f;
float shininess = 0.0f;
float specularStrength = 1.0f;
aiString texDiffusePath;
aiString texSpecularPath;
aiString texEmissivePath;
aiString texNormalPath;
aiString texLightmapPath;
aiString texReflectionPath;
srcMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
srcMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
srcMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
srcMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
srcMat->Get(AI_MATKEY_COLOR_TRANSPARENT, transparent);
srcMat->Get(AI_MATKEY_OPACITY, opacity);
srcMat->Get(AI_MATKEY_SHININESS, shininess);
srcMat->Get(AI_MATKEY_SHININESS_STRENGTH, specularStrength);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), texDiffusePath);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), texSpecularPath);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSIVE, 0), texEmissivePath);
//srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), texNormalPath);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_AMBIENT, 0), texNormalPath);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0), texLightmapPath);
srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_REFLECTION, 0), texReflectionPath);
dstMat->diffuse = Color(diffuse.r, diffuse.g, diffuse.b);
dstMat->specular = Color(specular.r, specular.g, specular.b);
dstMat->ambient = Color(ambient.r, ambient.g, ambient.b);
dstMat->emissive = Color(emissive.r, emissive.g, emissive.b);
dstMat->transparent = Color(transparent.r, transparent.g, transparent.b);
dstMat->opacity = opacity;
dstMat->shininess = shininess;
dstMat->specularStrength = specularStrength;
char *pRem = nullptr;
strncpy_s(dstMat->texDiffusePath, texDiffusePath.C_Str(), Material::maxTexPath - 1);
strncpy_s(dstMat->texSpecularPath, texSpecularPath.C_Str(), Material::maxTexPath - 1);
strncpy_s(dstMat->texEmissivePath, texEmissivePath.C_Str(), Material::maxTexPath - 1);
strncpy_s(dstMat->texNormalPath, texNormalPath.C_Str(), Material::maxTexPath - 1);
strncpy_s(dstMat->texLightmapPath, texLightmapPath.C_Str(), Material::maxTexPath - 1);
strncpy_s(dstMat->texReflectionPath, texReflectionPath.C_Str(), Material::maxTexPath - 1);
aiString matName;
srcMat->Get(AI_MATKEY_NAME, matName);
strncpy_s(dstMat->name, matName.C_Str(), Material::maxMaterialName - 1);
}
m_Header.meshCount = scene->mNumMeshes;
m_pMesh = new Mesh [m_Header.meshCount];
memset(m_pMesh, 0, sizeof(Mesh) * m_Header.meshCount);
// first pass, count everything
for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++)
{
const aiMesh *srcMesh = scene->mMeshes[meshIndex];
Mesh *dstMesh = m_pMesh + meshIndex;
assert(srcMesh->mPrimitiveTypes == aiPrimitiveType_TRIANGLE);
dstMesh->materialIndex = srcMesh->mMaterialIndex;
// just store everything as float. Can quantize in Model::optimize()
dstMesh->attribsEnabled |= attrib_mask_position;
dstMesh->attrib[attrib_position].offset = dstMesh->vertexStride;
dstMesh->attrib[attrib_position].normalized = 0;
dstMesh->attrib[attrib_position].components = 3;
dstMesh->attrib[attrib_position].format = attrib_format_float;
dstMesh->vertexStride += sizeof(float) * 3;
dstMesh->attribsEnabled |= attrib_mask_texcoord0;
dstMesh->attrib[attrib_texcoord0].offset = dstMesh->vertexStride;
dstMesh->attrib[attrib_texcoord0].normalized = 0;
dstMesh->attrib[attrib_texcoord0].components = 2;
dstMesh->attrib[attrib_texcoord0].format = attrib_format_float;
dstMesh->vertexStride += sizeof(float) * 2;
dstMesh->attribsEnabled |= attrib_mask_normal;
dstMesh->attrib[attrib_normal].offset = dstMesh->vertexStride;
dstMesh->attrib[attrib_normal].normalized = 0;
dstMesh->attrib[attrib_normal].components = 3;
dstMesh->attrib[attrib_normal].format = attrib_format_float;
dstMesh->vertexStride += sizeof(float) * 3;
dstMesh->attribsEnabled |= attrib_mask_tangent;
dstMesh->attrib[attrib_tangent].offset = dstMesh->vertexStride;
dstMesh->attrib[attrib_tangent].normalized = 0;
dstMesh->attrib[attrib_tangent].components = 3;
dstMesh->attrib[attrib_tangent].format = attrib_format_float;
dstMesh->vertexStride += sizeof(float) * 3;
dstMesh->attribsEnabled |= attrib_mask_bitangent;
dstMesh->attrib[attrib_bitangent].offset = dstMesh->vertexStride;
dstMesh->attrib[attrib_bitangent].normalized = 0;
dstMesh->attrib[attrib_bitangent].components = 3;
dstMesh->attrib[attrib_bitangent].format = attrib_format_float;
dstMesh->vertexStride += sizeof(float) * 3;
// depth-only
dstMesh->attribsEnabledDepth |= attrib_mask_position;
dstMesh->attribDepth[attrib_position].offset = dstMesh->vertexStrideDepth;
dstMesh->attribDepth[attrib_position].normalized = 0;
dstMesh->attribDepth[attrib_position].components = 3;
dstMesh->attribDepth[attrib_position].format = attrib_format_float;
dstMesh->vertexStrideDepth += sizeof(float) * 3;
// color rendering
dstMesh->vertexDataByteOffset = m_Header.vertexDataByteSize;
dstMesh->vertexCount = srcMesh->mNumVertices;
dstMesh->indexDataByteOffset = m_Header.indexDataByteSize;
dstMesh->indexCount = srcMesh->mNumFaces * 3;
m_Header.vertexDataByteSize += dstMesh->vertexStride * dstMesh->vertexCount;
m_Header.indexDataByteSize += sizeof(uint16_t) * dstMesh->indexCount;
// depth-only rendering
dstMesh->vertexDataByteOffsetDepth = m_Header.vertexDataByteSizeDepth;
dstMesh->vertexCountDepth = srcMesh->mNumVertices;
m_Header.vertexDataByteSizeDepth += dstMesh->vertexStrideDepth * dstMesh->vertexCountDepth;
}
// allocate storage
m_pVertexData = new unsigned char [m_Header.vertexDataByteSize];
m_pIndexData = new unsigned char [m_Header.indexDataByteSize];
m_pVertexDataDepth = new unsigned char [m_Header.vertexDataByteSizeDepth];
m_pIndexDataDepth = new unsigned char [m_Header.indexDataByteSize];
// second pass, fill in vertex and index data
for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++)
{
const aiMesh *srcMesh = scene->mMeshes[meshIndex];
Mesh *dstMesh = m_pMesh + meshIndex;
float *dstPos = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_position].offset);
float *dstTexcoord0 = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_texcoord0].offset);
float *dstNormal = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_normal].offset);
float *dstTangent = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_tangent].offset);
float *dstBitangent = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_bitangent].offset);
float *dstPosDepth = (float*)(m_pVertexDataDepth + dstMesh->vertexDataByteOffsetDepth + dstMesh->attribDepth[attrib_position].offset);
for (unsigned int v = 0; v < dstMesh->vertexCount; v++)
{
if (srcMesh->mVertices)
{
dstPos[0] = srcMesh->mVertices[v].x;
dstPos[1] = srcMesh->mVertices[v].y;
dstPos[2] = srcMesh->mVertices[v].z;
dstPosDepth[0] = srcMesh->mVertices[v].x;
dstPosDepth[1] = srcMesh->mVertices[v].y;
dstPosDepth[2] = srcMesh->mVertices[v].z;
}
else
{
// no position? That's kind of bad.
assert(0);
}
dstPos = (float*)((unsigned char*)dstPos + dstMesh->vertexStride);
dstPosDepth = (float*)((unsigned char*)dstPosDepth + dstMesh->vertexStrideDepth);
if (srcMesh->mTextureCoords[0])
{
dstTexcoord0[0] = srcMesh->mTextureCoords[0][v].x;
dstTexcoord0[1] = srcMesh->mTextureCoords[0][v].y;
}
else
{
dstTexcoord0[0] = 0.0f;
dstTexcoord0[1] = 0.0f;
}
dstTexcoord0 = (float*)((unsigned char*)dstTexcoord0 + dstMesh->vertexStride);
if (srcMesh->mNormals)
{
dstNormal[0] = srcMesh->mNormals[v].x;
dstNormal[1] = srcMesh->mNormals[v].y;
dstNormal[2] = srcMesh->mNormals[v].z;
}
else
{
// Assimp should generate normals if they are missing, according to the postprocessing flag specified on load,
// so we should never get here.
assert(0);
}
dstNormal = (float*)((unsigned char*)dstNormal + dstMesh->vertexStride);
if (srcMesh->mTangents)
{
dstTangent[0] = srcMesh->mTangents[v].x;
dstTangent[1] = srcMesh->mTangents[v].y;
dstTangent[2] = srcMesh->mTangents[v].z;
}
else
{
// TODO: generate tangents/bitangents if missing
dstTangent[0] = 1.0f;
dstTangent[1] = 0.0f;
dstTangent[2] = 0.0f;
}
dstTangent = (float*)((unsigned char*)dstTangent + dstMesh->vertexStride);
if (srcMesh->mBitangents)
{
dstBitangent[0] = srcMesh->mBitangents[v].x;
dstBitangent[1] = srcMesh->mBitangents[v].y;
dstBitangent[2] = srcMesh->mBitangents[v].z;
}
else
{
// TODO: generate tangents/bitangents if missing
dstBitangent[0] = 0.0f;
dstBitangent[1] = 1.0f;
dstBitangent[2] = 0.0f;
}
dstBitangent = (float*)((unsigned char*)dstBitangent + dstMesh->vertexStride);
}
uint16_t *dstIndex = (uint16_t*)(m_pIndexData + dstMesh->indexDataByteOffset);
uint16_t *dstIndexDepth = (uint16_t*)(m_pIndexDataDepth + dstMesh->indexDataByteOffset);
for (unsigned int f = 0; f < srcMesh->mNumFaces; f++)
{
assert(srcMesh->mFaces[f].mNumIndices == 3);
*dstIndex++ = srcMesh->mFaces[f].mIndices[0];
*dstIndex++ = srcMesh->mFaces[f].mIndices[1];
*dstIndex++ = srcMesh->mFaces[f].mIndices[2];
*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[0];
*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[1];
*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[2];
}
}
ComputeAllBoundingBoxes();
return true;
}