Closer to mesh fix.

This commit is contained in:
Andrzej Kapolka 2013-10-31 13:49:06 -07:00
parent 09babeca5d
commit a15bff3857

View file

@ -562,23 +562,28 @@ void appendModelIDs(const QString& parentID, const QMultiHash<QString, QString>&
class Vertex {
public:
glm::vec3 position;
int originalIndex;
glm::vec3 normal;
glm::vec2 texCoord;
};
uint qHash(const Vertex& vertex, uint seed = 0) {
return qHash((qint32*)&vertex.position.x) + qHash((qint32*)&vertex.position.y) +
qHash((qint32*)&vertex.position.z) + seed*27;
return qHash(vertex.originalIndex, seed);
}
bool operator==(const Vertex& v1, const Vertex& v2) {
return v1.position == v2.position && v1.normal == v2.normal && v1.texCoord == v2.texCoord;
return v1.originalIndex == v2.originalIndex && v1.normal == v2.normal && v1.texCoord == v2.texCoord;
}
class ExtractedMesh {
public:
FBXMesh mesh;
QMultiHash<int, int> newIndices;
};
class MeshData {
public:
FBXMesh mesh;
ExtractedMesh extracted;
QVector<glm::vec3> vertices;
QVector<int> polygonIndices;
bool normalsByVertex;
@ -597,13 +602,13 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
}
Vertex vertex;
vertex.position = data.vertices.at(vertexIndex);
vertex.originalIndex = vertexIndex;
if (data.normalIndices.isEmpty()) {
vertex.normal = data.normals.at(data.normalsByVertex ? vertexIndex : index);
} else {
int normalIndex = data.normalIndices.at(index);
int normalIndex = data.normalIndices.at(data.normalsByVertex ? vertexIndex : index);
if (normalIndex >= 0) {
vertex.normal = data.normals.at(normalIndex);
}
@ -621,18 +626,20 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
QHash<Vertex, int>::const_iterator it = data.indices.find(vertex);
if (it == data.indices.constEnd()) {
indices.append(data.mesh.vertices.size());
data.indices.insert(vertex, data.mesh.vertices.size());
data.mesh.vertices.append(vertex.position);
data.mesh.normals.append(vertex.normal);
data.mesh.texCoords.append(vertex.texCoord);
int newIndex = data.extracted.mesh.vertices.size();
indices.append(newIndex);
data.indices.insert(vertex, newIndex);
data.extracted.newIndices.insert(vertexIndex, newIndex);
data.extracted.mesh.vertices.append(data.vertices.at(vertexIndex));
data.extracted.mesh.normals.append(vertex.normal);
data.extracted.mesh.texCoords.append(vertex.texCoord);
} else {
indices.append(*it);
}
}
FBXMesh extractMesh(const FBXNode& object) {
ExtractedMesh extractMesh(const FBXNode& object) {
MeshData data;
QVector<int> materials;
foreach (const FBXNode& child, object.children) {
@ -681,8 +688,8 @@ FBXMesh extractMesh(const FBXNode& object) {
while (data.polygonIndices.at(endIndex++) >= 0);
int materialIndex = (polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0;
data.mesh.parts.resize(max(data.mesh.parts.size(), materialIndex + 1));
FBXMeshPart& part = data.mesh.parts[materialIndex];
data.extracted.mesh.parts.resize(max(data.extracted.mesh.parts.size(), materialIndex + 1));
FBXMeshPart& part = data.extracted.mesh.parts[materialIndex];
if (endIndex - beginIndex == 4) {
appendIndex(data, part.quadIndices, beginIndex++);
@ -703,7 +710,7 @@ FBXMesh extractMesh(const FBXNode& object) {
}
}
return data.mesh;
return data.extracted;
}
void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) {
@ -718,7 +725,7 @@ void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) {
}
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
QHash<QString, FBXMesh> meshes;
QHash<QString, ExtractedMesh> meshes;
QVector<ExtractedBlendshape> blendshapes;
QMultiHash<QString, QString> parentMap;
QMultiHash<QString, QString> childMap;
@ -986,17 +993,17 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QPair<int, float> index = blendshapeChannelIndices.value(blendshapeChannelID);
QString blendshapeID = parentMap.value(blendshapeChannelID);
QString meshID = parentMap.value(blendshapeID);
FBXMesh& mesh = meshes[meshID];
mesh.blendshapes.resize(max(mesh.blendshapes.size(), index.first + 1));
mesh.blendshapes[index.first] = extracted.blendshape;
// apply scale if non-unity
if (index.second != 1.0f) {
FBXBlendshape& blendshape = mesh.blendshapes[index.first];
for (int i = 0; i < blendshape.vertices.size(); i++) {
blendshape.vertices[i] *= index.second;
blendshape.normals[i] *= index.second;
}
ExtractedMesh& extractedMesh = meshes[meshID];
extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1));
FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[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++) {
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);
}
}
}
@ -1084,22 +1091,22 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QVariantHash springs = mapping.value("spring").toHash();
QVariant defaultSpring = springs.value("default");
for (QHash<QString, FBXMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
FBXMesh& mesh = it.value();
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value();
// accumulate local transforms
QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key());
mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat();
extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat();
glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID);
// look for textures, material properties
int partIndex = mesh.parts.size() - 1;
int partIndex = extracted.mesh.parts.size() - 1;
bool generateTangents = false;
foreach (const QString& childID, childMap.values(modelID)) {
if (partIndex < 0) {
break;
}
FBXMeshPart& part = mesh.parts[partIndex];
FBXMeshPart& part = extracted.mesh.parts[partIndex];
if (textureFilenames.contains(childID)) {
part.diffuseFilename = textureFilenames.value(childID);
continue;
@ -1131,25 +1138,25 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
// if we have a normal map (and texture coordinates), we must compute tangents
if (generateTangents && !mesh.texCoords.isEmpty()) {
mesh.tangents.resize(mesh.vertices.size());
foreach (const FBXMeshPart& part, mesh.parts) {
if (generateTangents && !extracted.mesh.texCoords.isEmpty()) {
extracted.mesh.tangents.resize(extracted.mesh.vertices.size());
foreach (const FBXMeshPart& part, extracted.mesh.parts) {
for (int i = 0; i < part.quadIndices.size(); i += 4) {
setTangents(mesh, part.quadIndices.at(i), part.quadIndices.at(i + 1));
setTangents(mesh, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2));
setTangents(mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3));
setTangents(mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i));
setTangents(extracted.mesh, part.quadIndices.at(i), part.quadIndices.at(i + 1));
setTangents(extracted.mesh, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2));
setTangents(extracted.mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3));
setTangents(extracted.mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i));
}
for (int i = 0; i < part.triangleIndices.size(); i += 3) {
setTangents(mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1));
setTangents(mesh, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2));
setTangents(mesh, part.triangleIndices.at(i + 2), part.triangleIndices.at(i));
setTangents(extracted.mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1));
setTangents(extracted.mesh, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2));
setTangents(extracted.mesh, part.triangleIndices.at(i + 2), part.triangleIndices.at(i));
}
}
}
// find the clusters with which the mesh is associated
mesh.isEye = false;
extracted.mesh.isEye = false;
QVector<QString> clusterIDs;
foreach (const QString& childID, childMap.values(it.key())) {
foreach (const QString& clusterID, childMap.values(childID)) {
@ -1162,41 +1169,44 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QString jointID = childMap.value(clusterID);
if (jointID == jointEyeLeftID || jointID == jointEyeRightID) {
mesh.isEye = true;
extracted.mesh.isEye = true;
}
// see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion
// of skinning information in FBX
fbxCluster.jointIndex = modelIDs.indexOf(jointID);
fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
mesh.clusters.append(fbxCluster);
extracted.mesh.clusters.append(fbxCluster);
}
}
// if we don't have a skinned joint, parent to the model itself
if (mesh.clusters.isEmpty()) {
if (extracted.mesh.clusters.isEmpty()) {
FBXCluster cluster;
cluster.jointIndex = modelIDs.indexOf(modelID);
mesh.clusters.append(cluster);
extracted.mesh.clusters.append(cluster);
}
// whether we're skinned depends on how many clusters are attached
if (clusterIDs.size() > 1) {
mesh.clusterIndices.resize(mesh.vertices.size());
mesh.clusterWeights.resize(mesh.vertices.size());
extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size());
extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size());
for (int i = 0; i < clusterIDs.size(); i++) {
QString clusterID = clusterIDs.at(i);
const Cluster& cluster = clusters[clusterID];
for (int j = 0; j < cluster.indices.size(); j++) {
int index = cluster.indices.at(j);
glm::vec4& weights = mesh.clusterWeights[index];
int oldIndex = cluster.indices.at(j);
for (QMultiHash<int, int>::const_iterator it = extracted.newIndices.constFind(oldIndex);
it != extracted.newIndices.end() && it.key() == oldIndex; it++) {
glm::vec4& weights = extracted.mesh.clusterWeights[it.value()];
// look for an unused slot in the weights vector
for (int k = 0; k < 4; k++) {
if (weights[k] == 0.0f) {
mesh.clusterIndices[index][k] = i;
weights[k] = cluster.weights.at(j);
break;
// look for an unused slot in the weights vector
for (int k = 0; k < 4; k++) {
if (weights[k] == 0.0f) {
extracted.mesh.clusterIndices[it.value()][k] = i;
weights[k] = cluster.weights.at(j);
break;
}
}
}
}
@ -1204,11 +1214,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
// extract spring edges, connections if springy
if (mesh.springiness > 0.0f) {
if (extracted.mesh.springiness > 0.0f) {
QSet<QPair<int, int> > edges;
mesh.vertexConnections.resize(mesh.vertices.size());
foreach (const FBXMeshPart& part, mesh.parts) {
extracted.mesh.vertexConnections.resize(extracted.mesh.vertices.size());
foreach (const FBXMeshPart& part, extracted.mesh.parts) {
for (int i = 0; i < part.quadIndices.size(); i += 4) {
int index0 = part.quadIndices.at(i);
int index1 = part.quadIndices.at(i + 1);
@ -1220,10 +1230,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
edges.insert(QPair<int, int>(qMin(index2, index3), qMax(index2, index3)));
edges.insert(QPair<int, int>(qMin(index3, index0), qMax(index3, index0)));
mesh.vertexConnections[index0].append(QPair<int, int>(index3, index1));
mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
mesh.vertexConnections[index2].append(QPair<int, int>(index1, index3));
mesh.vertexConnections[index3].append(QPair<int, int>(index2, index0));
extracted.mesh.vertexConnections[index0].append(QPair<int, int>(index3, index1));
extracted.mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
extracted.mesh.vertexConnections[index2].append(QPair<int, int>(index1, index3));
extracted.mesh.vertexConnections[index3].append(QPair<int, int>(index2, index0));
}
for (int i = 0; i < part.triangleIndices.size(); i += 3) {
int index0 = part.triangleIndices.at(i);
@ -1234,18 +1244,18 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
edges.insert(QPair<int, int>(qMin(index1, index2), qMax(index1, index2)));
edges.insert(QPair<int, int>(qMin(index2, index0), qMax(index2, index0)));
mesh.vertexConnections[index0].append(QPair<int, int>(index2, index1));
mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
mesh.vertexConnections[index2].append(QPair<int, int>(index1, index0));
extracted.mesh.vertexConnections[index0].append(QPair<int, int>(index2, index1));
extracted.mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
extracted.mesh.vertexConnections[index2].append(QPair<int, int>(index1, index0));
}
}
for (QSet<QPair<int, int> >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) {
mesh.springEdges.append(*edge);
extracted.mesh.springEdges.append(*edge);
}
}
geometry.meshes.append(mesh);
geometry.meshes.append(extracted.mesh);
}
// process attachments