1663 lines · 80.2 KB · C++
RawDownload
////  GLTFSerializer.cpp//  libraries/model-serializers/src////  Created by Luis Cuenca on 8/30/17.//  Copyright 2017 High Fidelity, Inc.//  Copyright 2023 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #define CGLTF_IMPLEMENTATION #include "GLTFSerializer.h" #include <QtCore/QBuffer>#include <QtCore/QIODevice>#include <QtCore/QEventLoop>#include <QtCore/qjsondocument.h>#include <QtCore/qjsonobject.h>#include <QtCore/qjsonarray.h>#include <QtCore/qjsonvalue.h>#include <QtCore/qpair.h>#include <QtCore/qlist.h> #include <QtNetwork/QNetworkAccessManager>#include <QtNetwork/QNetworkRequest> #include <glad/glad.h>#include <qfile.h>#include <qfileinfo.h> #include <sstream> #include <glm/gtx/transform.hpp> #include <shared/NsightHelpers.h>#include <NetworkAccessManager.h>#include <ResourceManager.h>#include <PathUtils.h>#include <image/ColorChannel.h>#include <BlendshapeConstants.h>#include <procedural/ProceduralMaterialCache.h> #include "FBXSerializer.h" float atof_locale_independent(char* str) {    //TODO: Once we have C++17 we can use std::from_chars    std::istringstream streamToParse(str);    streamToParse.imbue(std::locale("C"));    float value;    if (!(streamToParse >> value)) {        qDebug(modelformat) << "cgltf: Cannot parse float from string: " << str;        return 0.0f;    }    return value;} #define GLTF_GET_INDICIES(accCount) int index1 = (indices[n + 0] * accCount); int index2 = (indices[n + 1] * accCount); int index3 = (indices[n + 2] * accCount); #define GLTF_APPEND_ARRAY_1(newArray, oldArray) GLTF_GET_INDICIES(1) \newArray.append(oldArray[index1]); \newArray.append(oldArray[index2]); \newArray.append(oldArray[index3]); #define GLTF_APPEND_ARRAY_2(newArray, oldArray) GLTF_GET_INDICIES(2) \newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); \newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); \newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); #define GLTF_APPEND_ARRAY_3(newArray, oldArray) GLTF_GET_INDICIES(3) \newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); \newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); \newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]); #define GLTF_APPEND_ARRAY_4(newArray, oldArray) GLTF_GET_INDICIES(4) \newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); newArray.append(oldArray[index1 + 3]); \newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); newArray.append(oldArray[index2 + 3]); \newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]); newArray.append(oldArray[index3 + 3]); glm::mat4 GLTFSerializer::getModelTransform(const cgltf_node& node) {    glm::mat4 tmat = glm::mat4(1.0);     if (node.has_matrix) {        tmat = glm::mat4(node.matrix[0], node.matrix[1], node.matrix[2], node.matrix[3],            node.matrix[4], node.matrix[5], node.matrix[6], node.matrix[7],            node.matrix[8], node.matrix[9], node.matrix[10], node.matrix[11],            node.matrix[12], node.matrix[13], node.matrix[14], node.matrix[15]);    } else {         if (node.has_scale) {            glm::vec3 scale = glm::vec3(node.scale[0], node.scale[1], node.scale[2]);            glm::mat4 s = glm::mat4(1.0);            s = glm::scale(s, scale);            tmat = s * tmat;        }         if (node.has_rotation) {            //quat(x,y,z,w) to quat(w,x,y,z)            glm::quat rotquat = glm::quat(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]);            tmat = glm::mat4_cast(rotquat) * tmat;        }         if (node.has_translation) {            glm::vec3 trans = glm::vec3(node.translation[0], node.translation[1], node.translation[2]);            glm::mat4 t = glm::mat4(1.0);            t = glm::translate(t, trans);            tmat = t * tmat;        }    }    return tmat;} bool GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues) {    for (size_t i = 0; i < _data->skins_count; i++) {        auto &skin = _data->skins[i];         if (skin.inverse_bind_matrices == NULL) {            return false;        }         cgltf_accessor &matricesAccessor = *skin.inverse_bind_matrices;        QVector<float> matrices;        if (matricesAccessor.type != cgltf_type_mat4) {            return false;        }        matrices.resize((int)matricesAccessor.count * 16);        size_t numFloats = cgltf_accessor_unpack_floats(&matricesAccessor, matrices.data(), matricesAccessor.count * 16);        Q_ASSERT(numFloats == matricesAccessor.count * 16);        inverseBindMatrixValues.push_back(std::vector<float>(matrices.begin(), matrices.end()));    }    return true;} bool GLTFSerializer::generateTargetData(cgltf_accessor *accessor, float weight, QVector<glm::vec3>& returnVector) {    QVector<float> storedValues;    if(accessor == nullptr) {        return false;    }    if (accessor->type != cgltf_type_vec3) {        return false;    }    storedValues.resize((int)accessor->count * 3);    size_t numFloats = cgltf_accessor_unpack_floats(accessor, storedValues.data(), accessor->count * 3);    if (numFloats != accessor->count * 3) {        return false;    }     for (int n = 0; n + 2 < storedValues.size(); n = n + 3) {        returnVector.push_back(glm::vec3(weight * storedValues[n], weight * storedValues[n + 1], weight * storedValues[n + 2]));    }    return true;} bool findNodeInPointerArray(const cgltf_node *nodePointer, cgltf_node **nodes, size_t arraySize, size_t &index) {    for (size_t i = 0; i < arraySize; i++) {        if (nodes[i] == nodePointer) {            index = i;            return true;        }    }    return false;} template<typename T> bool findPointerInArray(const T *pointer, const T *array, size_t arraySize, size_t &index) {    for (size_t i = 0; i < arraySize; i++) {        if (&array[i] == pointer) {            index = i;            return true;        }    }    return false;} bool findAttribute(const QString &name, const cgltf_attribute *attributes, size_t numAttributes, size_t &index) {    std::string nameString = name.toStdString();    for (size_t i = 0; i < numAttributes; i++) {        if (attributes[i].name == nullptr) {            qDebug(modelformat) << "GLTFSerializer: attribute with a null pointer name string";        } else {            if (strcmp(nameString.c_str(), attributes[i].name) == 0) {                index = i;                return true;            }        }    }    return false;} bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url) {    hfmModel.originalURL = url.toString();     int numNodes = (int)_data->nodes_count;     //Build dependencies    QVector<int> parents;    QVector<int> sortedNodes;    parents.fill(-1, numNodes);    sortedNodes.reserve(numNodes);    for(int index = 0; index < numNodes; index++) {        auto &node = _data->nodes[index];        for(size_t childIndexInParent = 0; childIndexInParent < node.children_count; childIndexInParent++) {            cgltf_node *child = node.children[childIndexInParent];            size_t childIndex = 0;            if (!findPointerInArray(child, _data->nodes, _data->nodes_count, childIndex)) {                qDebug(modelformat) << "findPointerInArray failed for model: " << _url;                hfmModel.loadErrorCount++;                return false;            }            parents[(int)childIndex] = index;        }        sortedNodes.push_back(index);    }     // Build transforms    typedef QVector<glm::mat4> NodeTransforms;    QVector<NodeTransforms> transforms;    transforms.resize(numNodes);    for (int index = 0; index < numNodes; index++) {        // collect node transform        auto &node = _data->nodes[index];        transforms[index].push_back(getModelTransform(node));        int parentIndex = parents[index];        while (parentIndex != -1) {            const auto& parentNode = _data->nodes[parentIndex];            // collect transforms for a node's parents, grandparents, etc.            transforms[index].push_back(getModelTransform(parentNode));            parentIndex = parents[parentIndex];        }    }     // since parent indices must exist in the sorted list before any of their children, sortedNodes might not be initialized in the correct order    // therefore we need to re-initialize the order in which nodes will be parsed    QVector<bool> hasBeenSorted;    hasBeenSorted.fill(false, numNodes);    {        int i = 0;  // initial index        while (i < numNodes) {            int currentNode = sortedNodes[i];            int parentIndex = parents[currentNode];            if (parentIndex == -1 || hasBeenSorted[parentIndex]) {                hasBeenSorted[currentNode] = true;                ++i;            } else {                int j = i + 1;  // index of node to be sorted                while (j < numNodes) {                    int nextNode = sortedNodes[j];                    parentIndex = parents[nextNode];                    if (parentIndex == -1 || hasBeenSorted[parentIndex]) {                        // swap with currentNode                        hasBeenSorted[nextNode] = true;                        sortedNodes[i] = nextNode;                        sortedNodes[j] = currentNode;                        ++i;                        currentNode = sortedNodes[i];                    }                    ++j;                }            }        }    }       // Build map from original to new indices    QVector<int> originalToNewNodeIndexMap;    originalToNewNodeIndexMap.fill(-1, numNodes);    for (int i = 0; i < numNodes; ++i) {        originalToNewNodeIndexMap[sortedNodes[i]] = i;    }      // Build joints    HFMJoint joint{};    joint.distanceToParent = 0;    hfmModel.jointIndices["x"] = numNodes;    QVector<glm::mat4> globalTransforms;    globalTransforms.resize(numNodes);     for (int nodeIndex : sortedNodes) {        auto& node = _data->nodes[nodeIndex];         joint.parentIndex = parents[nodeIndex];        if (joint.parentIndex != -1) {            joint.parentIndex = originalToNewNodeIndexMap[joint.parentIndex];        }        joint.transform = transforms[nodeIndex].first();        joint.translation = extractTranslation(joint.transform);        joint.rotation = glmExtractRotation(joint.transform);        glm::vec3 scale = extractScale(joint.transform);        joint.postTransform = glm::scale(glm::mat4(), scale); 		joint.parentIndex = parents[nodeIndex];        globalTransforms[nodeIndex] = joint.transform;        if (joint.parentIndex != -1) {            globalTransforms[nodeIndex] = globalTransforms[joint.parentIndex] * globalTransforms[nodeIndex];            joint.parentIndex = originalToNewNodeIndexMap[joint.parentIndex];        }         joint.name = node.name;        joint.isSkeletonJoint = false;        hfmModel.joints.push_back(joint);    }    hfmModel.shapeVertices.resize(hfmModel.joints.size());      // get offset transform from mapping    float unitScaleFactor = 1.0f;    float offsetScale = mapping.value("scale", 1.0f).toFloat() * unitScaleFactor;    glm::quat offsetRotation = glm::quat(glm::radians(glm::vec3(mapping.value("rx").toFloat(), mapping.value("ry").toFloat(), mapping.value("rz").toFloat())));    hfmModel.offset = glm::translate(glm::mat4(), glm::vec3(mapping.value("tx").toFloat(), mapping.value("ty").toFloat(), mapping.value("tz").toFloat())) *        glm::mat4_cast(offsetRotation) * glm::scale(glm::mat4(), glm::vec3(offsetScale, offsetScale, offsetScale));      // Build skeleton    std::vector<glm::mat4> jointInverseBindTransforms;    std::vector<glm::mat4> globalBindTransforms;    jointInverseBindTransforms.resize(numNodes);    globalBindTransforms.resize(numNodes);     hfmModel.hasSkeletonJoints = _data->skins_count > 0;    if (hfmModel.hasSkeletonJoints) {        std::vector<std::vector<float>> inverseBindValues;        if (!getSkinInverseBindMatrices(inverseBindValues)) {            qDebug(modelformat) << "GLTFSerializer::getSkinInverseBindMatrices: wrong matrices accessor type for model: " << _url;            hfmModel.loadErrorCount++;            return false;        }         for (int jointIndex = 0; jointIndex < numNodes; ++jointIndex) {            int nodeIndex = sortedNodes[jointIndex];            auto joint = hfmModel.joints[jointIndex];             for (size_t s = 0; s < _data->skins_count; ++s) {                const auto& skin = _data->skins[s];                size_t jointNodeIndex = 0;                joint.isSkeletonJoint = findNodeInPointerArray(&_data->nodes[nodeIndex], skin.joints, skin.joints_count, jointNodeIndex);                 // build inverse bind matrices                if (joint.isSkeletonJoint) {                    size_t matrixIndex = jointNodeIndex;                    std::vector<float>& value = inverseBindValues[s];                    size_t matrixCount = 16 * matrixIndex;                    if (matrixCount + 15 >= value.size()) {                        qDebug(modelformat) << "GLTFSerializer::buildGeometry: not enough entries in jointInverseBindTransforms: " << _url;                        hfmModel.loadErrorCount++;                        return false;                    }                    jointInverseBindTransforms[jointIndex] =                        glm::mat4(value[matrixCount], value[matrixCount + 1], value[matrixCount + 2], value[matrixCount + 3],                            value[matrixCount + 4], value[matrixCount + 5], value[matrixCount + 6], value[matrixCount + 7],                            value[matrixCount + 8], value[matrixCount + 9], value[matrixCount + 10], value[matrixCount + 11],                            value[matrixCount + 12], value[matrixCount + 13], value[matrixCount + 14], value[matrixCount + 15]);                } else {                    jointInverseBindTransforms[jointIndex] = glm::mat4();                }                globalBindTransforms[jointIndex] = jointInverseBindTransforms[jointIndex];                if (joint.parentIndex != -1) {                    globalBindTransforms[jointIndex] = globalBindTransforms[joint.parentIndex] * globalBindTransforms[jointIndex];                }                glm::vec3 bindTranslation = extractTranslation(hfmModel.offset * glm::inverse(jointInverseBindTransforms[jointIndex]));                hfmModel.bindExtents.addPoint(bindTranslation);            }            hfmModel.joints[jointIndex] = joint;        }    }      // Build materials    QVector<QString> materialIDs;    QString unknown = "Default";    for (size_t i = 0; i < _data->materials_count; i++) {        auto &material = _data->materials[i];        QString mid;        if (material.name != nullptr) {            mid = QString(material.name);        }else{            mid = QString::number(i);        }         materialIDs.push_back(mid);    }     for (int i = 0; i < materialIDs.size(); ++i) {        QString& matid = materialIDs[i];        hfmModel.materials[matid] = HFMMaterial();        HFMMaterial& hfmMaterial = hfmModel.materials[matid];        hfmMaterial.name = hfmMaterial.materialID = matid;        setHFMMaterial(hfmMaterial, _data->materials[i]);    }      // Build meshes    int nodeCount = 0;    hfmModel.meshExtents.reset();    for (int nodeIndex : sortedNodes) {        auto& node = _data->nodes[nodeIndex];         if (node.mesh != nullptr) {             hfmModel.meshes.append(HFMMesh());            HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];            mesh.modelTransform = globalTransforms[nodeIndex];             if (!hfmModel.hasSkeletonJoints) {                HFMCluster cluster;                cluster.jointIndex = nodeCount;                cluster.inverseBindMatrix = glm::mat4();                cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);                mesh.clusters.append(cluster);            } else { // skinned model                for (int j = 0; j < numNodes; ++j) {                    HFMCluster cluster;                    cluster.jointIndex = j;                    cluster.inverseBindMatrix = jointInverseBindTransforms[j];                    cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);                    mesh.clusters.append(cluster);                }            }            HFMCluster root;            root.jointIndex = 0;            root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex];            root.inverseBindTransform = Transform(root.inverseBindMatrix);            mesh.clusters.append(root);             QList<QString> meshAttributes;            for (size_t primitiveIndex = 0; primitiveIndex < node.mesh->primitives_count; primitiveIndex++) {                auto &primitive = node.mesh->primitives[primitiveIndex];                for (size_t attributeIndex = 0; attributeIndex < primitive.attributes_count; attributeIndex++) {                    auto &attribute = primitive.attributes[attributeIndex];                    QString key(attribute.name);                    if (!meshAttributes.contains(key)) {                        meshAttributes.push_back(key);                    }                }            }             for (size_t primitiveIndex = 0; primitiveIndex < node.mesh->primitives_count; primitiveIndex++) {                auto &primitive = node.mesh->primitives[primitiveIndex];                HFMMeshPart part = HFMMeshPart();                 if (primitive.indices == nullptr) {                    qDebug() << "No indices accessor for mesh: " << _url;                    hfmModel.loadErrorCount++;                    return false;                }                auto &indicesAccessor = primitive.indices;                 // Buffers                QVector<int> indices;                QVector<float> vertices;                int verticesStride = 3;                QVector<float> normals;                int normalStride = 3;                QVector<float> tangents;                int tangentStride = 4;                QVector<float> texcoords;                int texCoordStride = 2;                QVector<float> texcoords2;                int texCoord2Stride = 2;                QVector<float> colors;                int colorStride = 3;                QVector<uint16_t> joints;                int jointStride = 4;                QVector<float> weights;                int weightStride = 4;                 indices.resize((int)indicesAccessor->count);                size_t readIndicesCount = cgltf_accessor_unpack_indices(indicesAccessor, indices.data(), sizeof(unsigned int), indicesAccessor->count);                 if (readIndicesCount != indicesAccessor->count) {                    qWarning(modelformat) << "There was a problem reading glTF INDICES data for model " << _url;                    hfmModel.loadErrorCount++;                    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();                 // For each vertex (stride is WEIGHTS_PER_VERTEX), it contains index of the cluster that given weight belongs to.                QVector<uint16_t> clusterJoints;                QVector<float> clusterWeights;                 for (size_t attributeIndex = 0; attributeIndex < primitive.attributes_count; attributeIndex++) {                    if (primitive.attributes[attributeIndex].name == nullptr) {                        qDebug() << "Inalid accessor name for mesh: " << _url;                        hfmModel.loadErrorCount++;                        return false;                    }                    QString key(primitive.attributes[attributeIndex].name);                     if (primitive.attributes[attributeIndex].data == nullptr) {                        qDebug() << "Inalid accessor for mesh: " << _url;                        hfmModel.loadErrorCount++;                        return false;                    }                    auto accessor = primitive.attributes[attributeIndex].data;                    int accessorCount = (int)accessor->count;                     if (key == "POSITION") {

Lines 1–500 of 1663.