[FBX] Allow export multi materials per node (#5888)
* [FBX] Allow export multi materials per node Previously it was assumed that each node would export a single material. This removes that assumption, and also allows for exporting multiple meshes with a single node. Previously they would each be seprated into their own node. * Support for animations with multiple meshes too --------- Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
This commit is contained in:
@@ -1065,21 +1065,28 @@ void FBXExporter::WriteObjects () {
|
||||
object_node.BeginChildren(outstream, binary, indent);
|
||||
|
||||
bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
|
||||
std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later
|
||||
// save vertex_indices as it is needed later
|
||||
std::vector<std::vector<int32_t>> vVertexIndice(mScene->mNumMeshes);
|
||||
|
||||
std::vector<uint32_t> uniq_v_before_mi;
|
||||
|
||||
const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false);
|
||||
|
||||
// geometry (aiMesh)
|
||||
mesh_uids.clear();
|
||||
indent = 1;
|
||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
||||
// it's all about this mesh
|
||||
aiMesh* m = mScene->mMeshes[mi];
|
||||
std::function<void(const aiNode*)> visit_node_geo = [&](const aiNode *node) {
|
||||
if (node->mNumMeshes == 0) {
|
||||
for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
|
||||
visit_node_geo(node->mChildren[ni]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// start the node record
|
||||
FBX::Node n("Geometry");
|
||||
int64_t uid = generate_uid();
|
||||
mesh_uids.push_back(uid);
|
||||
mesh_uids[node] = uid;
|
||||
n.AddProperty(uid);
|
||||
n.AddProperty(FBX::SEPARATOR + "Geometry");
|
||||
n.AddProperty("Mesh");
|
||||
@@ -1087,158 +1094,112 @@ void FBXExporter::WriteObjects () {
|
||||
n.DumpProperties(outstream, binary, indent);
|
||||
n.EndProperties(outstream, binary, indent);
|
||||
n.BeginChildren(outstream, binary, indent);
|
||||
indent = 2;
|
||||
|
||||
// output vertex data - each vertex should be unique (probably)
|
||||
std::vector<double> flattened_vertices;
|
||||
// index of original vertex in vertex data vector
|
||||
std::vector<int32_t> vertex_indices;
|
||||
// map of vertex value to its index in the data vector
|
||||
std::map<aiVector3D,size_t> index_by_vertex_value;
|
||||
if(bJoinIdenticalVertices){
|
||||
int32_t index = 0;
|
||||
for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
|
||||
aiVector3D vtx = m->mVertices[vi];
|
||||
auto elem = index_by_vertex_value.find(vtx);
|
||||
if (elem == index_by_vertex_value.end()) {
|
||||
vertex_indices.push_back(index);
|
||||
index_by_vertex_value[vtx] = index;
|
||||
flattened_vertices.push_back(vtx[0]);
|
||||
flattened_vertices.push_back(vtx[1]);
|
||||
flattened_vertices.push_back(vtx[2]);
|
||||
++index;
|
||||
} else {
|
||||
vertex_indices.push_back(int32_t(elem->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // do not join vertex, respect the export flag
|
||||
vertex_indices.resize(m->mNumVertices);
|
||||
std::iota(vertex_indices.begin(), vertex_indices.end(), 0);
|
||||
for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
|
||||
aiVector3D vtx = m->mVertices[v];
|
||||
flattened_vertices.push_back(vtx.x);
|
||||
flattened_vertices.push_back(vtx.y);
|
||||
flattened_vertices.push_back(vtx.z);
|
||||
}
|
||||
}
|
||||
vVertexIndice.push_back(vertex_indices);
|
||||
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Vertices", flattened_vertices, outstream, binary, indent
|
||||
);
|
||||
std::vector<double> normal_data;
|
||||
std::vector<double> color_data;
|
||||
|
||||
std::vector<int32_t> polygon_data;
|
||||
|
||||
std::vector<std::vector<double>> uv_data;
|
||||
std::vector<std::vector<int32_t>> uv_indices;
|
||||
std::map<aiVector3D, int32_t> index_by_uv;
|
||||
|
||||
std::vector<int32_t> offsets = { 0 };
|
||||
|
||||
indent = 2;
|
||||
|
||||
for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) {
|
||||
const auto mi = node->mMeshes[n_mi];
|
||||
const aiMesh *m = mScene->mMeshes[mi];
|
||||
|
||||
size_t v_offset = vertex_indices.size();
|
||||
size_t uniq_v_before = flattened_vertices.size() / 3;
|
||||
|
||||
// map of vertex value to its index in the data vector
|
||||
std::map<aiVector3D,size_t> index_by_vertex_value;
|
||||
if(bJoinIdenticalVertices){
|
||||
int32_t index = 0;
|
||||
for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
|
||||
aiVector3D vtx = m->mVertices[vi];
|
||||
auto elem = index_by_vertex_value.find(vtx);
|
||||
if (elem == index_by_vertex_value.end()) {
|
||||
vertex_indices.push_back(index);
|
||||
index_by_vertex_value[vtx] = index;
|
||||
flattened_vertices.insert(flattened_vertices.end(), { vtx.x, vtx.y, vtx.z });
|
||||
++index;
|
||||
} else {
|
||||
vertex_indices.push_back(int32_t(elem->second));
|
||||
}
|
||||
}
|
||||
} else { // do not join vertex, respect the export flag
|
||||
vertex_indices.resize(v_offset + m->mNumVertices);
|
||||
std::iota(vertex_indices.begin() + v_offset, vertex_indices.end(), (int)v_offset);
|
||||
for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
|
||||
aiVector3D vtx = m->mVertices[v];
|
||||
flattened_vertices.insert(flattened_vertices.end(), {vtx.x, vtx.y, vtx.z});
|
||||
}
|
||||
}
|
||||
vVertexIndice[mi].insert(
|
||||
// TODO test whether this can be end or not
|
||||
vVertexIndice[mi].begin(),
|
||||
vertex_indices.begin(),
|
||||
vertex_indices.end()
|
||||
);
|
||||
|
||||
// here could be edges but they're insane.
|
||||
// it's optional anyway, so let's ignore it.
|
||||
|
||||
// output polygon data as a flattened array of vertex indices.
|
||||
// the last vertex index of each polygon is negated and - 1
|
||||
std::vector<int32_t> polygon_data;
|
||||
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
|
||||
for (size_t fi = 0; fi < m->mNumFaces; fi++) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices - 1; ++pvi) {
|
||||
polygon_data.push_back(vertex_indices[f.mIndices[pvi]]);
|
||||
size_t pvi = 0;
|
||||
for (; pvi < f.mNumIndices - 1; pvi++) {
|
||||
polygon_data.push_back(
|
||||
static_cast<int32_t>(uniq_v_before + vertex_indices[v_offset + f.mIndices[pvi]])
|
||||
);
|
||||
}
|
||||
polygon_data.push_back(
|
||||
-1 - vertex_indices[f.mIndices[f.mNumIndices-1]]
|
||||
static_cast<int32_t>(-1 - (uniq_v_before + vertex_indices[v_offset+f.mIndices[pvi]]))
|
||||
);
|
||||
}
|
||||
FBX::Node::WritePropertyNode(
|
||||
"PolygonVertexIndex", polygon_data, outstream, binary, indent
|
||||
);
|
||||
}
|
||||
|
||||
// here could be edges but they're insane.
|
||||
// it's optional anyway, so let's ignore it.
|
||||
uniq_v_before_mi.push_back(static_cast<uint32_t>(uniq_v_before));
|
||||
|
||||
FBX::Node::WritePropertyNode(
|
||||
"GeometryVersion", int32_t(124), outstream, binary, indent
|
||||
);
|
||||
|
||||
// normals, if any
|
||||
if (m->HasNormals()) {
|
||||
FBX::Node normals("LayerElementNormal", int32_t(0));
|
||||
normals.Begin(outstream, binary, indent);
|
||||
normals.DumpProperties(outstream, binary, indent);
|
||||
normals.EndProperties(outstream, binary, indent);
|
||||
normals.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Version", int32_t(101), outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Name", "", outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"MappingInformationType", "ByPolygonVertex",
|
||||
outstream, binary, indent
|
||||
);
|
||||
// TODO: vertex-normals or indexed normals when appropriate
|
||||
FBX::Node::WritePropertyNode(
|
||||
"ReferenceInformationType", "Direct",
|
||||
outstream, binary, indent
|
||||
);
|
||||
std::vector<double> normal_data;
|
||||
if (m->HasNormals()) {
|
||||
normal_data.reserve(3 * polygon_data.size());
|
||||
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
|
||||
const aiVector3D &curN = m->mNormals[f.mIndices[pvi]];
|
||||
normal_data.push_back(curN.x);
|
||||
normal_data.push_back(curN.y);
|
||||
normal_data.push_back(curN.z);
|
||||
}
|
||||
for (size_t fi = 0; fi < m->mNumFaces; fi++) {
|
||||
const aiFace & f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
|
||||
const aiVector3D &curN = m->mNormals[f.mIndices[pvi]];
|
||||
normal_data.insert(normal_data.end(), { curN.x, curN.y, curN.z });
|
||||
}
|
||||
}
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Normals", normal_data, outstream, binary, indent
|
||||
);
|
||||
// note: version 102 has a NormalsW also... not sure what it is,
|
||||
// so we can stick with version 101 for now.
|
||||
indent = 2;
|
||||
normals.End(outstream, binary, indent, true);
|
||||
}
|
||||
}
|
||||
|
||||
// colors, if any
|
||||
for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) {
|
||||
FBX::Node vertexcolors("LayerElementColor", int32_t(ci));
|
||||
vertexcolors.Begin(outstream, binary, indent);
|
||||
vertexcolors.DumpProperties(outstream, binary, indent);
|
||||
vertexcolors.EndProperties(outstream, binary, indent);
|
||||
vertexcolors.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Version", int32_t(101), outstream, binary, indent
|
||||
);
|
||||
char layerName[8];
|
||||
snprintf(layerName, sizeof(layerName), "COLOR_%d", int32_t(ci));
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Name", (const char*)layerName, outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"MappingInformationType", "ByPolygonVertex",
|
||||
outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"ReferenceInformationType", "Direct",
|
||||
outstream, binary, indent
|
||||
);
|
||||
std::vector<double> color_data;
|
||||
const int32_t colorChannelIndex = 0;
|
||||
if (m->HasVertexColors(colorChannelIndex)) {
|
||||
color_data.reserve(4 * polygon_data.size());
|
||||
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
|
||||
const aiColor4D &c = m->mColors[ci][f.mIndices[pvi]];
|
||||
color_data.push_back(c.r);
|
||||
color_data.push_back(c.g);
|
||||
color_data.push_back(c.b);
|
||||
color_data.push_back(c.a);
|
||||
}
|
||||
for (size_t fi = 0; fi < m->mNumFaces; fi++) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
|
||||
const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
|
||||
color_data.insert(color_data.end(), { c.r, c.g, c.b, c.a });
|
||||
}
|
||||
}
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Colors", color_data, outstream, binary, indent
|
||||
);
|
||||
indent = 2;
|
||||
vertexcolors.End(outstream, binary, indent, true);
|
||||
}
|
||||
}
|
||||
|
||||
// uvs, if any
|
||||
for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) {
|
||||
const auto num_uv = static_cast<size_t>(m->GetNumUVChannels());
|
||||
uv_indices.resize(std::max(num_uv, uv_indices.size()));
|
||||
uv_data.resize(std::max(num_uv, uv_data.size()));
|
||||
|
||||
// uvs, if any
|
||||
for (size_t uvi = 0; uvi < m->GetNumUVChannels(); uvi++) {
|
||||
if (m->mNumUVComponents[uvi] > 2) {
|
||||
// FBX only supports 2-channel UV maps...
|
||||
// or at least i'm not sure how to indicate a different number
|
||||
@@ -1254,71 +1215,111 @@ void FBXExporter::WriteObjects () {
|
||||
err << " but may be incorrectly interpreted on load.";
|
||||
ASSIMP_LOG_WARN(err.str());
|
||||
}
|
||||
FBX::Node uv("LayerElementUV", int32_t(uvi));
|
||||
uv.Begin(outstream, binary, indent);
|
||||
uv.DumpProperties(outstream, binary, indent);
|
||||
uv.EndProperties(outstream, binary, indent);
|
||||
uv.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Version", int32_t(101), outstream, binary, indent
|
||||
);
|
||||
// it doesn't seem like assimp keeps the uv map name,
|
||||
// so just leave it blank.
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Name", "", outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"MappingInformationType", "ByPolygonVertex",
|
||||
outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"ReferenceInformationType", "IndexToDirect",
|
||||
outstream, binary, indent
|
||||
);
|
||||
|
||||
std::vector<double> uv_data;
|
||||
std::vector<int32_t> uv_indices;
|
||||
std::map<aiVector3D,int32_t> index_by_uv;
|
||||
int32_t index = 0;
|
||||
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
|
||||
const aiVector3D &curUv =
|
||||
m->mTextureCoords[uvi][f.mIndices[pvi]];
|
||||
auto elem = index_by_uv.find(curUv);
|
||||
if (elem == index_by_uv.end()) {
|
||||
index_by_uv[curUv] = index;
|
||||
uv_indices.push_back(index);
|
||||
for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) {
|
||||
uv_data.push_back(curUv[x]);
|
||||
}
|
||||
++index;
|
||||
} else {
|
||||
uv_indices.push_back(elem->second);
|
||||
}
|
||||
for (size_t fi = 0; fi < m->mNumFaces; fi++) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) {
|
||||
const aiVector3D &curUv = m->mTextureCoords[uvi][f.mIndices[pvi]];
|
||||
auto elem = index_by_uv.find(curUv);
|
||||
if (elem == index_by_uv.end()) {
|
||||
index_by_uv[curUv] = index;
|
||||
uv_indices[uvi].push_back(index);
|
||||
for (uint32_t x = 0; x < m->mNumUVComponents[uvi]; ++x) {
|
||||
uv_data[uvi].push_back(curUv[x]);
|
||||
}
|
||||
++index;
|
||||
} else {
|
||||
uv_indices[uvi].push_back(elem->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
FBX::Node::WritePropertyNode(
|
||||
"UV", uv_data, outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"UVIndex", uv_indices, outstream, binary, indent
|
||||
);
|
||||
indent = 2;
|
||||
uv.End(outstream, binary, indent, true);
|
||||
}
|
||||
|
||||
offsets.push_back((int32_t)polygon_data.size());
|
||||
}
|
||||
|
||||
// i'm not really sure why this material section exists,
|
||||
// as the material is linked via "Connections".
|
||||
// it seems to always have the same "0" value.
|
||||
|
||||
FBX::Node::WritePropertyNode("Vertices", flattened_vertices, outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("PolygonVertexIndex", polygon_data, outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("GeometryVersion", int32_t(124), outstream, binary, indent);
|
||||
|
||||
FBX::Node normals("LayerElementNormal", int32_t(0));
|
||||
normals.Begin(outstream, binary, indent);
|
||||
normals.DumpProperties(outstream, binary, indent);
|
||||
normals.EndProperties(outstream, binary, indent);
|
||||
normals.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode("Version", int32_t(101),outstream,binary,indent);
|
||||
FBX::Node::WritePropertyNode("Name", "",outstream,binary,indent);
|
||||
FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex",outstream,binary,indent);
|
||||
FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct",outstream,binary,indent);
|
||||
FBX::Node::WritePropertyNode("Normals", normal_data,outstream,binary,indent);
|
||||
// note: version 102 has a NormalsW also... not sure what it is,
|
||||
// so stick with version 101 for now.
|
||||
indent = 2;
|
||||
normals.End(outstream,binary,indent,true);
|
||||
|
||||
const auto colorChannelIndex = 0;
|
||||
FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
|
||||
vertexcolors.Begin(outstream, binary, indent);
|
||||
vertexcolors.DumpProperties(outstream, binary, indent);
|
||||
vertexcolors.EndProperties(outstream, binary, indent);
|
||||
vertexcolors.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
|
||||
char layerName[8];
|
||||
snprintf(layerName, sizeof(layerName), "COLOR_%d", colorChannelIndex);
|
||||
FBX::Node::WritePropertyNode("Name", (const char *)layerName, outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("Colors", color_data, outstream, binary, indent);
|
||||
indent = 2;
|
||||
vertexcolors.End(outstream, binary, indent, true);
|
||||
|
||||
for (uint32_t uvi = 0; uvi < uv_data.size(); uvi++) {
|
||||
FBX::Node uv("LayerElementUV", int32_t(uvi));
|
||||
uv.Begin(outstream, binary, indent);
|
||||
uv.DumpProperties(outstream, binary, indent);
|
||||
uv.EndProperties(outstream, binary, indent);
|
||||
uv.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("MappingInformationType", "ByPolgonVertex", outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("ReferenceInformationType", "IndexToDirect", outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("UV", uv_data[uvi], outstream, binary, indent);
|
||||
FBX::Node::WritePropertyNode("UVIndex", uv_indices[uvi], outstream, binary, indent);
|
||||
indent = 2;
|
||||
uv.End(outstream, binary, indent, true);
|
||||
}
|
||||
|
||||
|
||||
// When merging multiple meshes, we instead use by polygon so the correct material is
|
||||
// assigned to each face. Previously, this LayerElementMaterial always had 0 since it
|
||||
// assumed there was 1 material for each node for all meshes.
|
||||
FBX::Node mat("LayerElementMaterial", int32_t(0));
|
||||
mat.AddChild("Version", int32_t(101));
|
||||
mat.AddChild("Name", "");
|
||||
mat.AddChild("MappingInformationType", "AllSame");
|
||||
mat.AddChild("ReferenceInformationType", "IndexToDirect");
|
||||
std::vector<int32_t> mat_indices = {0};
|
||||
mat.AddChild("Materials", mat_indices);
|
||||
if (node->mNumMeshes == 1) {
|
||||
mat.AddChild("MappingInformationType", "AllSame");
|
||||
mat.AddChild("ReferenceInformationType", "IndexToDirect");
|
||||
std::vector<int32_t> mat_indices = {0};
|
||||
mat.AddChild("Materials", mat_indices);
|
||||
} else {
|
||||
mat.AddChild("MappingInformationType", "ByPolygon");
|
||||
mat.AddChild("ReferenceInformationType", "IndexToDirect");
|
||||
std::vector<int32_t> mat_indices(polygon_data.size());
|
||||
uint32_t curr_offset = 0;
|
||||
for (uint32_t mi = 0; mi < node->mNumMeshes; mi++) {
|
||||
uint32_t num_faces = mScene->mMeshes[node->mMeshes[mi]]->mNumFaces;
|
||||
for (uint32_t fi = 0; fi < num_faces; fi++) {
|
||||
mat_indices[curr_offset + fi] = mi;
|
||||
}
|
||||
curr_offset += num_faces;
|
||||
}
|
||||
mat.AddChild("Materials", mat_indices);
|
||||
}
|
||||
mat.Dump(outstream, binary, indent);
|
||||
|
||||
// finally we have the layer specifications,
|
||||
@@ -1331,12 +1332,10 @@ void FBXExporter::WriteObjects () {
|
||||
le.AddChild("TypedIndex", int32_t(0));
|
||||
layer.AddChild(le);
|
||||
|
||||
for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) {
|
||||
le = FBX::Node("LayerElement");
|
||||
le.AddChild("Type", "LayerElementColor");
|
||||
le.AddChild("TypedIndex", int32_t(ci));
|
||||
layer.AddChild(le);
|
||||
}
|
||||
le = FBX::Node("LayerElement");
|
||||
le.AddChild("Type", "LayerElementColor");
|
||||
le.AddChild("TypedIndex", int32_t(0));
|
||||
layer.AddChild(le);
|
||||
|
||||
le = FBX::Node("LayerElement");
|
||||
le.AddChild("Type", "LayerElementMaterial");
|
||||
@@ -1348,8 +1347,7 @@ void FBXExporter::WriteObjects () {
|
||||
layer.AddChild(le);
|
||||
layer.Dump(outstream, binary, indent);
|
||||
|
||||
for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
|
||||
{
|
||||
for(unsigned int lr = 1; lr < uv_data.size(); ++ lr) {
|
||||
FBX::Node layerExtra("Layer", int32_t(lr));
|
||||
layerExtra.AddChild("Version", int32_t(100));
|
||||
FBX::Node leExtra("LayerElement");
|
||||
@@ -1361,7 +1359,14 @@ void FBXExporter::WriteObjects () {
|
||||
// finish the node record
|
||||
indent = 1;
|
||||
n.End(outstream, binary, indent, true);
|
||||
}
|
||||
|
||||
for (uint32_t ni = 0; ni < node->mNumChildren; ni++) {
|
||||
visit_node_geo(node->mChildren[ni]);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
visit_node_geo(mScene->mRootNode);
|
||||
|
||||
|
||||
// aiMaterial
|
||||
@@ -1726,7 +1731,8 @@ void FBXExporter::WriteObjects () {
|
||||
dnode.AddChild("Version", int32_t(101));
|
||||
dnode.Dump(outstream, binary, indent);
|
||||
// connect it
|
||||
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
|
||||
const auto node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode);
|
||||
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[node]);
|
||||
std::vector<int32_t> vertex_indices = vVertexIndice[mi];
|
||||
|
||||
for (unsigned int am = 0; am < m->mNumAnimMeshes; ++am) {
|
||||
@@ -1736,7 +1742,7 @@ void FBXExporter::WriteObjects () {
|
||||
// start the node record
|
||||
FBX::Node bsnode("Geometry");
|
||||
int64_t blendshape_uid = generate_uid();
|
||||
mesh_uids.push_back(blendshape_uid);
|
||||
blendshape_uids.push_back(blendshape_uid);
|
||||
bsnode.AddProperty(blendshape_uid);
|
||||
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry");
|
||||
bsnode.AddProperty("Shape");
|
||||
@@ -1923,22 +1929,15 @@ void FBXExporter::WriteObjects () {
|
||||
// otherwise check if this is the root of the skeleton
|
||||
bool end = false;
|
||||
// is the mesh part of this node?
|
||||
for (size_t i = 0; i < parent->mNumMeshes; ++i) {
|
||||
if (parent->mMeshes[i] == mi) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < parent->mNumMeshes && !end; ++i) {
|
||||
end |= parent->mMeshes[i] == mi;
|
||||
}
|
||||
// is the mesh in one of the children of this node?
|
||||
for (size_t j = 0; j < parent->mNumChildren; ++j) {
|
||||
for (size_t j = 0; j < parent->mNumChildren && !end; ++j) {
|
||||
aiNode* child = parent->mChildren[j];
|
||||
for (size_t i = 0; i < child->mNumMeshes; ++i) {
|
||||
if (child->mMeshes[i] == mi) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < child->mNumMeshes && !end; ++i) {
|
||||
end |= child->mMeshes[i] == mi;
|
||||
}
|
||||
if (end) { break; }
|
||||
}
|
||||
|
||||
// if it was the skeleton root we can finish here
|
||||
@@ -1952,8 +1951,7 @@ void FBXExporter::WriteObjects () {
|
||||
for (size_t i = 0; i < mScene->mNumMeshes; ++i) {
|
||||
auto &s = skeleton_by_mesh[i];
|
||||
for (const aiNode* n : s) {
|
||||
auto elem = node_uids.find(n);
|
||||
if (elem == node_uids.end()) {
|
||||
if (node_uids.find(n) == node_uids.end()) {
|
||||
node_uids[n] = generate_uid();
|
||||
}
|
||||
}
|
||||
@@ -1969,6 +1967,8 @@ void FBXExporter::WriteObjects () {
|
||||
if (!m->HasBones()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const aiNode *mesh_node = get_node_for_mesh((uint32_t)mi, mScene->mRootNode);
|
||||
// make a deformer for this mesh
|
||||
int64_t deformer_uid = generate_uid();
|
||||
FBX::Node dnode("Deformer");
|
||||
@@ -1980,10 +1980,7 @@ void FBXExporter::WriteObjects () {
|
||||
dnode.Dump(outstream, binary, indent);
|
||||
|
||||
// connect it
|
||||
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
|
||||
|
||||
//computed before
|
||||
std::vector<int32_t>& vertex_indices = vVertexIndice[mi];
|
||||
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mesh_node]);
|
||||
|
||||
// TODO, FIXME: this won't work if anything is not in the bind pose.
|
||||
// for now if such a situation is detected, we throw an exception.
|
||||
@@ -1997,7 +1994,6 @@ void FBXExporter::WriteObjects () {
|
||||
// as it can be instanced to many nodes.
|
||||
// All we can do is assume no instancing,
|
||||
// and take the first node we find that contains the mesh.
|
||||
aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode);
|
||||
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
|
||||
|
||||
// now make a subdeformer for each bone in the skeleton
|
||||
@@ -2026,14 +2022,15 @@ void FBXExporter::WriteObjects () {
|
||||
sdnode.AddChild("Version", int32_t(100));
|
||||
sdnode.AddChild("UserData", "", "");
|
||||
|
||||
std::set<int32_t> setWeightedVertex;
|
||||
// add indices and weights, if any
|
||||
if (b) {
|
||||
std::set<int32_t> setWeightedVertex;
|
||||
std::vector<int32_t> subdef_indices;
|
||||
std::vector<double> subdef_weights;
|
||||
int32_t last_index = -1;
|
||||
for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
|
||||
int32_t vi = vertex_indices[b->mWeights[wi].mVertexId];
|
||||
int32_t vi = vVertexIndice[mi][b->mWeights[wi].mVertexId] \
|
||||
+ uniq_v_before_mi[mi];
|
||||
bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
|
||||
if (vi == last_index || bIsWeightedAlready) {
|
||||
// only for vertices we exported to fbx
|
||||
@@ -2680,9 +2677,8 @@ void FBXExporter::WriteModelNodes(
|
||||
// handled later
|
||||
} else if (node->mNumMeshes == 1) {
|
||||
// connect to child mesh, which should have been written previously
|
||||
connections.emplace_back(
|
||||
"C", "OO", mesh_uids[node->mMeshes[0]], node_uid
|
||||
);
|
||||
// TODO double check this line
|
||||
connections.emplace_back("C", "OO", mesh_uids[node], node_uid);
|
||||
// also connect to the material for the child mesh
|
||||
connections.emplace_back(
|
||||
"C", "OO",
|
||||
@@ -2707,6 +2703,16 @@ void FBXExporter::WriteModelNodes(
|
||||
na.Dump(outstream, binary, 1);
|
||||
// and connect them
|
||||
connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
|
||||
} else if (node->mNumMeshes >= 1) {
|
||||
connections.emplace_back("C", "OO", mesh_uids[node], node_uid);
|
||||
for (size_t i = 0; i < node->mNumMeshes; i++) {
|
||||
connections.emplace_back(
|
||||
"C", "OO",
|
||||
material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex],
|
||||
node_uid
|
||||
);
|
||||
}
|
||||
WriteModelNode(outstream, binary, node, node_uid, "Mesh", transform_chain);
|
||||
} else {
|
||||
const auto& lightIt = lights_uids.find(node->mName.C_Str());
|
||||
if(lightIt != lights_uids.end()) {
|
||||
@@ -2723,34 +2729,20 @@ void FBXExporter::WriteModelNodes(
|
||||
}
|
||||
}
|
||||
|
||||
// if more than one child mesh, make nodes for each mesh
|
||||
if (node->mNumMeshes > 1 || node == mScene->mRootNode) {
|
||||
for (size_t i = 0; i < node->mNumMeshes; ++i) {
|
||||
// make a new model node
|
||||
int64_t new_node_uid = generate_uid();
|
||||
// connect to parent node
|
||||
connections.emplace_back("C", "OO", new_node_uid, node_uid);
|
||||
// connect to child mesh, which should have been written previously
|
||||
connections.emplace_back(
|
||||
"C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid
|
||||
);
|
||||
// also connect to the material for the child mesh
|
||||
connections.emplace_back(
|
||||
"C", "OO",
|
||||
material_uids[
|
||||
mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex
|
||||
],
|
||||
new_node_uid
|
||||
);
|
||||
|
||||
aiNode new_node;
|
||||
// take name from mesh name, if it exists
|
||||
new_node.mName = mScene->mMeshes[node->mMeshes[i]]->mName;
|
||||
// write model node
|
||||
WriteModelNode(
|
||||
outstream, binary, &new_node, new_node_uid, "Mesh", std::vector<std::pair<std::string,aiVector3D>>()
|
||||
);
|
||||
}
|
||||
if (node == mScene->mRootNode && node->mNumMeshes > 0) {
|
||||
int64_t new_node_uid = generate_uid();
|
||||
connections.emplace_back("C", "OO", new_node_uid, node_uid);
|
||||
connections.emplace_back("C", "OO", mesh_uids[node], new_node_uid);
|
||||
for (size_t i = 0; i < node->mNumMeshes; ++i) {
|
||||
connections.emplace_back(
|
||||
"C", "OO",
|
||||
material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex],
|
||||
new_node_uid
|
||||
);
|
||||
}
|
||||
aiNode new_node;
|
||||
new_node.mName = mScene->mMeshes[0]->mName;
|
||||
WriteModelNode(outstream, binary, &new_node, new_node_uid, "Mesh", {});
|
||||
}
|
||||
|
||||
// now recurse into children
|
||||
|
||||
@@ -90,7 +90,8 @@ namespace Assimp {
|
||||
|
||||
std::vector<FBX::Node> connections; // connection storage
|
||||
|
||||
std::vector<int64_t> mesh_uids;
|
||||
std::map<const aiNode*, int64_t> mesh_uids;
|
||||
std::vector<int64_t> blendshape_uids;
|
||||
std::vector<int64_t> material_uids;
|
||||
std::map<const aiNode*,int64_t> node_uids;
|
||||
std::map<std::string,int64_t> lights_uids;
|
||||
|
||||
Reference in New Issue
Block a user