Merge pull request #1824 from ey6es/master

Fixes for transforms and blendshapes on Blender FBX exports.
This commit is contained in:
ZappoMan 2014-01-31 22:05:14 -08:00
commit 8797c35834

View file

@ -738,6 +738,22 @@ ExtractedMesh extractMesh(const FBXNode& object) {
return data.extracted;
}
FBXBlendshape extractBlendshape(const FBXNode& object) {
FBXBlendshape blendshape;
foreach (const FBXNode& data, object.children) {
if (data.name == "Indexes") {
blendshape.indices = getIntVector(data.properties, 0);
} else if (data.name == "Vertices") {
blendshape.vertices = createVec3Vector(getDoubleVector(data.properties, 0));
} else if (data.name == "Normals") {
blendshape.normals = createVec3Vector(getDoubleVector(data.properties, 0));
}
}
return blendshape;
}
void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) {
glm::vec3 normal = glm::normalize(mesh.normals.at(firstIndex));
glm::vec3 bitangent = glm::cross(normal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex));
@ -760,6 +776,49 @@ QVector<int> getIndices(const QVector<QString> ids, QVector<QString> modelIDs) {
return indices;
}
typedef QPair<int, float> WeightedIndex;
void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIndex>& indices, ExtractedMesh& extractedMesh) {
foreach (const WeightedIndex& index, indices) {
extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1));
extractedMesh.blendshapeIndexMaps.resize(extractedMesh.mesh.blendshapes.size());
FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first];
QHash<int, int>& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first];
for (int i = 0; i < extracted.blendshape.indices.size(); i++) {
int oldIndex = extracted.blendshape.indices.at(i);
for (QMultiHash<int, int>::const_iterator it = extractedMesh.newIndices.constFind(oldIndex);
it != extractedMesh.newIndices.constEnd() && it.key() == oldIndex; it++) {
QHash<int, int>::iterator blendshapeIndex = blendshapeIndexMap.find(it.value());
if (blendshapeIndex == blendshapeIndexMap.end()) {
blendshapeIndexMap.insert(it.value(), blendshape.indices.size());
blendshape.indices.append(it.value());
blendshape.vertices.append(extracted.blendshape.vertices.at(i) * index.second);
blendshape.normals.append(extracted.blendshape.normals.at(i) * index.second);
} else {
blendshape.vertices[*blendshapeIndex] += extracted.blendshape.vertices.at(i) * index.second;
blendshape.normals[*blendshapeIndex] += extracted.blendshape.normals.at(i) * index.second;
}
}
}
}
}
QString getTopModelID(const QMultiHash<QString, QString>& parentMap,
const QHash<QString, FBXModel>& models, const QString& modelID) {
QString topID = modelID;
forever {
foreach (const QString& parentID, parentMap.values(topID)) {
if (models.contains(parentID)) {
topID = parentID;
goto outerContinue;
}
}
return topID;
outerContinue: ;
}
}
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
QHash<QString, ExtractedMesh> meshes;
QVector<ExtractedBlendshape> blendshapes;
@ -799,7 +858,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QVector<QString> jointRightFingertipIDs(jointRightFingertipNames.size());
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
typedef QPair<int, float> WeightedIndex;
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
for (int i = 0;; i++) {
QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
@ -827,22 +885,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
meshes.insert(getID(object.properties), extractMesh(object));
} else { // object.properties.at(2) == "Shape"
ExtractedBlendshape extracted = { getID(object.properties) };
foreach (const FBXNode& data, object.children) {
if (data.name == "Indexes") {
extracted.blendshape.indices = getIntVector(data.properties, 0);
} else if (data.name == "Vertices") {
extracted.blendshape.vertices = createVec3Vector(
getDoubleVector(data.properties, 0));
} else if (data.name == "Normals") {
extracted.blendshape.normals = createVec3Vector(
getDoubleVector(data.properties, 0));
}
}
ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) };
blendshapes.append(extracted);
}
} else if (object.name == "Model") {
@ -900,6 +943,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
bool rotationMaxX = false, rotationMaxY = false, rotationMaxZ = false;
glm::vec3 rotationMin, rotationMax;
FBXModel model = { name, -1 };
ExtractedMesh* mesh = NULL;
QVector<ExtractedBlendshape> blendshapes;
foreach (const FBXNode& subobject, object.children) {
bool properties = false;
QByteArray propertyName;
@ -969,9 +1014,23 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
} else if (subobject.name == "Vertices") {
// it's a mesh as well as a model
meshes.insert(getID(object.properties), extractMesh(object));
mesh = &meshes[getID(object.properties)];
*mesh = extractMesh(object);
} else if (subobject.name == "Shape") {
ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(),
extractBlendshape(subobject) };
blendshapes.append(blendshape);
}
}
// add the blendshapes included in the model, if any
if (mesh) {
foreach (const ExtractedBlendshape& extracted, blendshapes) {
addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh);
}
}
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
model.translation = translation;
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
@ -1084,29 +1143,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QString blendshapeChannelID = parentMap.value(extracted.id);
QString blendshapeID = parentMap.value(blendshapeChannelID);
QString meshID = parentMap.value(blendshapeID);
ExtractedMesh& extractedMesh = meshes[meshID];
foreach (const WeightedIndex& index, blendshapeChannelIndices.values(blendshapeChannelID)) {
extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1));
extractedMesh.blendshapeIndexMaps.resize(extractedMesh.mesh.blendshapes.size());
FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first];
QHash<int, int>& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first];
for (int i = 0; i < extracted.blendshape.indices.size(); i++) {
int oldIndex = extracted.blendshape.indices.at(i);
for (QMultiHash<int, int>::const_iterator it = extractedMesh.newIndices.constFind(oldIndex);
it != extractedMesh.newIndices.constEnd() && it.key() == oldIndex; it++) {
QHash<int, int>::iterator blendshapeIndex = blendshapeIndexMap.find(it.value());
if (blendshapeIndex == blendshapeIndexMap.end()) {
blendshapeIndexMap.insert(it.value(), blendshape.indices.size());
blendshape.indices.append(it.value());
blendshape.vertices.append(extracted.blendshape.vertices.at(i) * index.second);
blendshape.normals.append(extracted.blendshape.normals.at(i) * index.second);
} else {
blendshape.vertices[*blendshapeIndex] += extracted.blendshape.vertices.at(i) * index.second;
blendshape.normals[*blendshapeIndex] += extracted.blendshape.normals.at(i) * index.second;
}
}
}
}
addBlendshapes(extracted, blendshapeChannelIndices.values(blendshapeChannelID), meshes[meshID]);
}
// get offset transform from mapping
@ -1121,6 +1158,20 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QVector<QString> modelIDs;
QSet<QString> remainingModels;
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
// models with clusters must be parented to the cluster top
foreach (const QString& deformerID, childMap.values(model.key())) {
foreach (const QString& clusterID, childMap.values(deformerID)) {
if (!clusters.contains(clusterID)) {
continue;
}
QString topID = getTopModelID(parentMap, models, childMap.value(clusterID));
childMap.remove(parentMap.take(model.key()), model.key());
parentMap.insert(model.key(), topID);
goto outerBreak;
}
}
outerBreak:
// make sure the parent is in the child map
QString parent = parentMap.value(model.key());
if (!childMap.contains(parent, model.key())) {
@ -1129,20 +1180,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
remainingModels.insert(model.key());
}
while (!remainingModels.isEmpty()) {
QString top = *remainingModels.constBegin();
forever {
foreach (const QString& name, parentMap.values(top)) {
if (models.contains(name)) {
top = name;
goto outerContinue;
}
}
top = parentMap.value(top);
break;
outerContinue: ;
}
appendModelIDs(top, childMap, models, remainingModels, modelIDs);
QString topID = getTopModelID(parentMap, models, *remainingModels.constBegin());
appendModelIDs(parentMap.value(topID), childMap, models, remainingModels, modelIDs);
}
// convert the models to joints