- fbx: implement mesh splitting for meshes with multiple materials.
parent
cfb05376d2
commit
61c6c37e30
|
@ -182,12 +182,12 @@ private:
|
||||||
|
|
||||||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
|
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
|
||||||
if(mesh) {
|
if(mesh) {
|
||||||
const unsigned int index = ConvertMesh(*mesh, model);
|
std::vector<unsigned int>& indices = ConvertMesh(*mesh, model);
|
||||||
if(index == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
meshes.push_back(index-1);
|
// mesh indices are shifted by 1 and 0 entries are failed conversions -
|
||||||
|
// XXX maybe log how many conversions went wrong?
|
||||||
|
std::remove(indices.begin(),indices.end(),0);
|
||||||
|
std::transform(indices.begin(),indices.end(),std::back_inserter(meshes), std::bind2nd(std::minus<unsigned int>(),1) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name());
|
FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name());
|
||||||
|
@ -205,18 +205,21 @@ private:
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
||||||
unsigned int ConvertMesh(const MeshGeometry& mesh, const Model& model)
|
std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model)
|
||||||
{
|
{
|
||||||
|
std::vector<unsigned int> temp;
|
||||||
|
|
||||||
MeshMap::const_iterator it = meshes_converted.find(&mesh);
|
MeshMap::const_iterator it = meshes_converted.find(&mesh);
|
||||||
if (it != meshes_converted.end()) {
|
if (it != meshes_converted.end()) {
|
||||||
return (*it).second + 1;
|
temp.push_back((*it).second + 1);
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||||
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||||
if(vertices.empty() || faces.empty()) {
|
if(vertices.empty() || faces.empty()) {
|
||||||
FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name());
|
FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name());
|
||||||
return 0;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
aiMesh* out_mesh = new aiMesh();
|
aiMesh* out_mesh = new aiMesh();
|
||||||
|
@ -224,13 +227,37 @@ private:
|
||||||
|
|
||||||
meshes_converted[&mesh] = static_cast<unsigned int>(meshes.size()-1);
|
meshes_converted[&mesh] = static_cast<unsigned int>(meshes.size()-1);
|
||||||
|
|
||||||
|
// one material per mesh maps easily to aiMesh. Multiple material
|
||||||
|
// meshes need to be split.
|
||||||
|
const std::vector<unsigned int>& mindices = mesh.GetMaterialIndices();
|
||||||
|
if (!mindices.empty()) {
|
||||||
|
const unsigned int base = mindices[0];
|
||||||
|
BOOST_FOREACH(unsigned int index, mindices) {
|
||||||
|
if(index != base) {
|
||||||
|
return ConvertMeshMultiMaterial(out_mesh, mesh, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// faster codepath, just copy the data
|
||||||
|
temp.push_back(ConvertMeshSingleMaterial(out_mesh, mesh, model));
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
unsigned int ConvertMeshSingleMaterial(aiMesh* out_mesh, const MeshGeometry& mesh, const Model& model)
|
||||||
|
{
|
||||||
|
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||||
|
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||||
|
|
||||||
// copy vertices
|
// copy vertices
|
||||||
out_mesh->mNumVertices = static_cast<size_t>(vertices.size());
|
out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
|
||||||
out_mesh->mVertices = new aiVector3D[vertices.size()];
|
out_mesh->mVertices = new aiVector3D[vertices.size()];
|
||||||
std::copy(vertices.begin(),vertices.end(),out_mesh->mVertices);
|
std::copy(vertices.begin(),vertices.end(),out_mesh->mVertices);
|
||||||
|
|
||||||
// generate dummy faces
|
// generate dummy faces
|
||||||
out_mesh->mNumFaces = static_cast<size_t>(faces.size());
|
out_mesh->mNumFaces = static_cast<unsigned int>(faces.size());
|
||||||
aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()]();
|
aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()]();
|
||||||
|
|
||||||
unsigned int cursor = 0;
|
unsigned int cursor = 0;
|
||||||
|
@ -333,6 +360,182 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<unsigned int> ConvertMeshMultiMaterial(aiMesh* out_mesh, const MeshGeometry& mesh, const Model& model)
|
||||||
|
{
|
||||||
|
const std::vector<unsigned int>& mindices = mesh.GetMaterialIndices();
|
||||||
|
ai_assert(mindices.size());
|
||||||
|
|
||||||
|
std::set<unsigned int> had;
|
||||||
|
std::vector<unsigned int> indices;
|
||||||
|
|
||||||
|
BOOST_FOREACH(unsigned int index, mindices) {
|
||||||
|
if(had.find(index) != had.end()) {
|
||||||
|
|
||||||
|
indices.push_back(ConvertMeshMultiMaterial(out_mesh, mesh, model, index));
|
||||||
|
had.insert(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
unsigned int ConvertMeshMultiMaterial(aiMesh* out_mesh, const MeshGeometry& mesh, const Model& model, unsigned int index)
|
||||||
|
{
|
||||||
|
const std::vector<unsigned int>& mindices = mesh.GetMaterialIndices();
|
||||||
|
ai_assert(mindices.size());
|
||||||
|
|
||||||
|
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||||
|
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||||
|
|
||||||
|
unsigned int count_faces = 0;
|
||||||
|
unsigned int count_vertices = 0;
|
||||||
|
|
||||||
|
// count faces
|
||||||
|
for(std::vector<unsigned int>::const_iterator it = mindices.begin(),
|
||||||
|
end = mindices.end(), itf = faces.begin(); it != end; ++it, ++itf)
|
||||||
|
{
|
||||||
|
if ((*it) != index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++count_faces;
|
||||||
|
count_vertices += *itf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert(count_faces);
|
||||||
|
|
||||||
|
|
||||||
|
// allocate output data arrays, but don't fill them yet
|
||||||
|
out_mesh->mNumVertices = count_vertices;
|
||||||
|
out_mesh->mVertices = new aiVector3D[count_vertices];
|
||||||
|
|
||||||
|
out_mesh->mNumFaces = count_faces;
|
||||||
|
aiFace* fac = out_mesh->mFaces = new aiFace[count_faces]();
|
||||||
|
|
||||||
|
|
||||||
|
// allocate normals
|
||||||
|
const std::vector<aiVector3D>& normals = mesh.GetNormals();
|
||||||
|
if(normals.size()) {
|
||||||
|
ai_assert(normals.size() == vertices.size());
|
||||||
|
out_mesh->mNormals = new aiVector3D[vertices.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate tangents, binormals.
|
||||||
|
const std::vector<aiVector3D>& tangents = mesh.GetTangents();
|
||||||
|
const std::vector<aiVector3D>* binormals = &mesh.GetBinormals();
|
||||||
|
|
||||||
|
if(tangents.size()) {
|
||||||
|
std::vector<aiVector3D> tempBinormals;
|
||||||
|
if (!binormals->size()) {
|
||||||
|
if (normals.size()) {
|
||||||
|
// XXX this computes the binormals for the entire mesh, not only
|
||||||
|
// the part for which we need them.
|
||||||
|
tempBinormals.resize(normals.size());
|
||||||
|
for (unsigned int i = 0; i < tangents.size(); ++i) {
|
||||||
|
tempBinormals[i] = normals[i] ^ tangents[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
binormals = &tempBinormals;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
binormals = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(binormals) {
|
||||||
|
ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size());
|
||||||
|
|
||||||
|
out_mesh->mTangents = new aiVector3D[vertices.size()];
|
||||||
|
out_mesh->mBitangents = new aiVector3D[vertices.size()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate texture coords
|
||||||
|
unsigned int num_uvs = 0;
|
||||||
|
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) {
|
||||||
|
const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i);
|
||||||
|
if(uvs.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
|
||||||
|
out_mesh->mNumUVComponents[i] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate vertex colors
|
||||||
|
unsigned int num_vcs = 0;
|
||||||
|
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) {
|
||||||
|
const std::vector<aiColor4D>& colors = mesh.GetVertexColors(i);
|
||||||
|
if(colors.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_mesh->mColors[i] = new aiColor4D[vertices.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cursor = 0, in_cursor = 0;
|
||||||
|
|
||||||
|
for(std::vector<unsigned int>::const_iterator it = mindices.begin(),
|
||||||
|
end = mindices.end(), itf = faces.begin(); it != end; ++it, ++itf)
|
||||||
|
{
|
||||||
|
const unsigned int pcount = *itf;
|
||||||
|
if ((*it) != index) {
|
||||||
|
in_cursor += pcount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
aiFace& f = *fac++;
|
||||||
|
|
||||||
|
f.mNumIndices = pcount;
|
||||||
|
f.mIndices = new unsigned int[pcount];
|
||||||
|
switch(pcount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) {
|
||||||
|
f.mIndices[i] = cursor;
|
||||||
|
|
||||||
|
out_mesh->mVertices[cursor] = vertices[in_cursor];
|
||||||
|
|
||||||
|
if(out_mesh->mNormals) {
|
||||||
|
out_mesh->mNormals[cursor] = normals[in_cursor];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(out_mesh->mTangents) {
|
||||||
|
out_mesh->mTangents[cursor] = tangents[in_cursor];
|
||||||
|
out_mesh->mBitangents[cursor] = (*binormals)[in_cursor];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_uvs; ++i) {
|
||||||
|
const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i);
|
||||||
|
out_mesh->mTextureCoords[i][cursor] = aiVector3D(uvs[in_cursor].x,uvs[in_cursor].y, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_vcs; ++i) {
|
||||||
|
const std::vector<aiColor4D>& cols = mesh.GetVertexColors(i);
|
||||||
|
out_mesh->mColors[i][cursor] = cols[in_cursor];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertMaterialForMesh(out_mesh,model,mesh,index);
|
||||||
|
return static_cast<unsigned int>(meshes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, unsigned int materialIndex)
|
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, unsigned int materialIndex)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue