Support vertex colours and multiple unnamed mesh materials.

# Conflicts:
#	libraries/fbx/src/GLTFSerializer.cpp
This commit is contained in:
Saracen 2018-09-25 07:56:44 +01:00
parent 5bf872b1b8
commit 471baf83c6
2 changed files with 166 additions and 56 deletions

View file

@ -261,6 +261,41 @@ bool GLTFSerializer::setAsset(const QJsonObject& object) {
return isAssetDefined; return isAssetDefined;
} }
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices GLTFSerializer::createAccessorSparseIndices(const QJsonObject& object) {
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices accessorSparseIndices;
getIntVal(object, "bufferView", accessorSparseIndices.bufferView, accessorSparseIndices.defined);
getIntVal(object, "byteOffset", accessorSparseIndices.byteOffset, accessorSparseIndices.defined);
getIntVal(object, "componentType", accessorSparseIndices.componentType, accessorSparseIndices.defined);
return accessorSparseIndices;
}
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues GLTFSerializer::createAccessorSparseValues(const QJsonObject& object) {
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues accessorSparseValues;
getIntVal(object, "bufferView", accessorSparseValues.bufferView, accessorSparseValues.defined);
getIntVal(object, "byteOffset", accessorSparseValues.byteOffset, accessorSparseValues.defined);
return accessorSparseValues;
}
GLTFAccessor::GLTFAccessorSparse GLTFSerializer::createAccessorSparse(const QJsonObject& object) {
GLTFAccessor::GLTFAccessorSparse accessorSparse;
getIntVal(object, "count", accessorSparse.count, accessorSparse.defined);
QJsonObject sparseIndicesObject;
if (getObjectVal(object, "indices", sparseIndicesObject, accessorSparse.defined)) {
accessorSparse.indices = createAccessorSparseIndices(sparseIndicesObject);
}
QJsonObject sparseValuesObject;
if (getObjectVal(object, "values", sparseValuesObject, accessorSparse.defined)) {
accessorSparse.values = createAccessorSparseValues(sparseValuesObject);
}
return accessorSparse;
}
bool GLTFSerializer::addAccessor(const QJsonObject& object) { bool GLTFSerializer::addAccessor(const QJsonObject& object) {
GLTFAccessor accessor; GLTFAccessor accessor;
@ -273,6 +308,12 @@ bool GLTFSerializer::addAccessor(const QJsonObject& object) {
if (getStringVal(object, "type", type, accessor.defined)) { if (getStringVal(object, "type", type, accessor.defined)) {
accessor.type = getAccessorType(type); accessor.type = getAccessorType(type);
} }
QJsonObject sparseObject;
if (getObjectVal(object, "sparse", sparseObject, accessor.defined)) {
accessor.sparse = createAccessorSparse(sparseObject);
}
getDoubleArrayVal(object, "max", accessor.max, accessor.defined); getDoubleArrayVal(object, "max", accessor.max, accessor.defined);
getDoubleArrayVal(object, "min", accessor.min, accessor.defined); getDoubleArrayVal(object, "min", accessor.min, accessor.defined);
@ -919,7 +960,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
QString unknown = "Default"; QString unknown = "Default";
int ukcount = 0; int ukcount = 0;
foreach(auto material, _file.materials) { foreach(auto material, _file.materials) {
QString mid = (material.defined["name"]) ? material.name : unknown + ukcount++; if (!(material.defined["name"])) {
QString name = unknown + QString::number(ukcount++);
material.name = name;
material.defined.insert("name", true);
}
QString mid = material.name;
materialIDs.push_back(mid); materialIDs.push_back(mid);
} }
@ -928,6 +975,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
hfmModel.materials[matid] = HFMMaterial(); hfmModel.materials[matid] = HFMMaterial();
HFMMaterial& hfmMaterial = hfmModel.materials[matid]; HFMMaterial& hfmMaterial = hfmModel.materials[matid];
hfmMaterial._material = std::make_shared<graphics::Material>(); hfmMaterial._material = std::make_shared<graphics::Material>();
hfmMaterial.name = hfmMaterial.materialID = matid;
setHFMMaterial(hfmMaterial, _file.materials[i]); setHFMMaterial(hfmMaterial, _file.materials[i]);
} }
@ -938,7 +986,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
auto& node = _file.nodes[nodeIndex]; auto& node = _file.nodes[nodeIndex];
if (node.defined["mesh"]) { if (node.defined["mesh"]) {
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
hfmModel.meshes.append(HFMMesh()); hfmModel.meshes.append(HFMMesh());
HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1]; HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];
if (!hfmModel.hasSkeletonJoints) { if (!hfmModel.hasSkeletonJoints) {
@ -962,6 +1010,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
root.inverseBindTransform = Transform(root.inverseBindMatrix); root.inverseBindTransform = Transform(root.inverseBindMatrix);
mesh.clusters.append(root); mesh.clusters.append(root);
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
HFMMeshPart part = HFMMeshPart(); HFMMeshPart part = HFMMeshPart();
int indicesAccessorIdx = primitive.indices; int indicesAccessorIdx = primitive.indices;
@ -972,10 +1021,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
int indicesAccBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0; int indicesAccBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0;
QVector<int> raw_indices;
QVector<glm::vec3> raw_vertices;
QVector<glm::vec3> raw_normals;
bool success = addArrayOfType(indicesBuffer.blob, bool success = addArrayOfType(indicesBuffer.blob,
indicesBufferview.byteOffset + indicesAccBoffset, indicesBufferview.byteOffset + indicesAccBoffset,
indicesAccessor.count, indicesAccessor.count,
@ -988,6 +1033,14 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
continue; continue;
} }
// Increment the triangle indices by the current mesh vertex count so each mesh part can all reference the same buffers within the mesh
int prevMeshVerticesCount = mesh.vertices.count();
if (prevMeshVerticesCount > 0) {
for (int i = 0; i < part.triangleIndices.count(); i++) {
part.triangleIndices[i] += prevMeshVerticesCount;
}
}
QList<QString> keys = primitive.attributes.values.keys(); QList<QString> keys = primitive.attributes.values.keys();
QVector<uint16_t> clusterJoints; QVector<uint16_t> clusterJoints;
QVector<float> clusterWeights; QVector<float> clusterWeights;
@ -1029,22 +1082,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
for (int n = 0; n < normals.size(); n = n + 3) { for (int n = 0; n < normals.size(); n = n + 3) {
mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2]));
} }
} else if (key == "COLOR_0") {
QVector<float> colors;
success = addArrayOfType(buffer.blob,
bufferview.byteOffset + accBoffset,
accessor.count,
colors,
accessor.type,
accessor.componentType);
if (!success) {
qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url;
continue;
}
int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3;
for (int n = 0; n < colors.size() - 3; n += stride) {
mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2]));
}
} else if (key == "TANGENT") { } else if (key == "TANGENT") {
QVector<float> tangents; QVector<float> tangents;
success = addArrayOfType(buffer.blob, success = addArrayOfType(buffer.blob,
@ -1092,6 +1129,22 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
} }
for (int n = 0; n < texcoords.size(); n = n + 2) { for (int n = 0; n < texcoords.size(); n = n + 2) {
mesh.texCoords1.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); mesh.texCoords1.push_back(glm::vec2(texcoords[n], texcoords[n + 1]));
}
} else if (key == "COLOR_0") {
QVector<float> colors;
success = addArrayOfType(buffer.blob,
bufferview.byteOffset + accBoffset,
accessor.count,
colors,
accessor.type,
accessor.componentType);
if (!success) {
qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url;
continue;
}
int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3;
for (int n = 0; n < colors.size() - 3; n += stride) {
mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2]));
} }
} else if (key == "JOINTS_0") { } else if (key == "JOINTS_0") {
QVector<uint16_t> joints; QVector<uint16_t> joints;
@ -1251,6 +1304,14 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
mesh.meshIndex = hfmModel.meshes.size(); mesh.meshIndex = hfmModel.meshes.size();
} }
mesh.meshExtents.reset();
foreach(const glm::vec3& vertex, mesh.vertices) {
mesh.meshExtents.addPoint(vertex);
hfmModel.meshExtents.addPoint(vertex);
}
mesh.meshIndex = hfmModel.meshes.size();
} }
nodecount++; nodecount++;
} }
@ -1404,10 +1465,6 @@ HFMTexture GLTFSerializer::getHFMTexture(const GLTFTexture& texture) {
void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) { void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) {
if (material.defined["name"]) {
fbxmat.name = fbxmat.materialID = material.name;
}
if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) { if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) {
glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], glm::vec3 emissive = glm::vec3(material.emissiveFactor[0],
material.emissiveFactor[1], material.emissiveFactor[1],

View file

@ -481,6 +481,49 @@ namespace GLTFAccessorComponentType {
}; };
} }
struct GLTFAccessor { struct GLTFAccessor {
struct GLTFAccessorSparse {
struct GLTFAccessorSparseIndices {
int bufferView;
int byteOffset{ 0 };
int componentType;
QMap<QString, bool> defined;
void dump() {
if (defined["bufferView"]) {
qCDebug(modelformat) << "bufferView: " << bufferView;
}
if (defined["byteOffset"]) {
qCDebug(modelformat) << "byteOffset: " << byteOffset;
}
if (defined["componentType"]) {
qCDebug(modelformat) << "componentType: " << componentType;
}
}
};
struct GLTFAccessorSparseValues {
int bufferView;
int byteOffset{ 0 };
QMap<QString, bool> defined;
void dump() {
if (defined["bufferView"]) {
qCDebug(modelformat) << "bufferView: " << bufferView;
}
if (defined["byteOffset"]) {
qCDebug(modelformat) << "byteOffset: " << byteOffset;
}
}
};
int count;
GLTFAccessorSparseIndices indices;
GLTFAccessorSparseValues values;
QMap<QString, bool> defined;
void dump() {
}
};
int bufferView; int bufferView;
int byteOffset { 0 }; int byteOffset { 0 };
int componentType; //required int componentType; //required
@ -489,6 +532,7 @@ struct GLTFAccessor {
bool normalized{ false }; bool normalized{ false };
QVector<double> max; QVector<double> max;
QVector<double> min; QVector<double> min;
GLTFAccessorSparse sparse;
QMap<QString, bool> defined; QMap<QString, bool> defined;
void dump() { void dump() {
if (defined["bufferView"]) { if (defined["bufferView"]) {
@ -521,6 +565,10 @@ struct GLTFAccessor {
qCDebug(modelformat) << m; qCDebug(modelformat) << m;
} }
} }
if (defined["sparse"]) {
qCDebug(modelformat) << "sparse: ";
sparse.dump();
}
} }
}; };
@ -763,6 +811,11 @@ private:
int& outidx, QMap<QString, bool>& defined); int& outidx, QMap<QString, bool>& defined);
bool setAsset(const QJsonObject& object); bool setAsset(const QJsonObject& object);
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices createAccessorSparseIndices(const QJsonObject& object);
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues createAccessorSparseValues(const QJsonObject& object);
GLTFAccessor::GLTFAccessorSparse createAccessorSparse(const QJsonObject& object);
bool addAccessor(const QJsonObject& object); bool addAccessor(const QJsonObject& object);
bool addAnimation(const QJsonObject& object); bool addAnimation(const QJsonObject& object);
bool addBufferView(const QJsonObject& object); bool addBufferView(const QJsonObject& object);