Andrew Meadowsfix comment5d5dc2810 years agoHistory
1348 lines · 52.9 KB · C++
RawDownload
                             // NOTE: Random guy on the internet's recommended triangle slices                            //Triangle tri1 = { v0, v1, v2 };                            //Triangle tri2 = { v2, v3, v0 };                             thisMeshTriangles.push_back(tri1);                            thisMeshTriangles.push_back(tri2);                         }                    }                     if (part.triangleIndices.size() > 0) {                        int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE;                        int vIndex = 0;                        for (int t = 0; t < numberOfTris; t++) {                            int i0 = part.triangleIndices[vIndex++];                            int i1 = part.triangleIndices[vIndex++];                            int i2 = part.triangleIndices[vIndex++];                             glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f));                            glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f));                            glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f));                             // track the mesh parts in model space                            if (!atLeastOnePointInBounds) {                                thisPartBounds.setBox(mv0, 0.0f);                                atLeastOnePointInBounds = true;                            } else {                                thisPartBounds += mv0;                            }                            thisPartBounds += mv1;                            thisPartBounds += mv2;                             glm::vec3 v0 = calculateScaledOffsetPoint(mv0);                            glm::vec3 v1 = calculateScaledOffsetPoint(mv1);                            glm::vec3 v2 = calculateScaledOffsetPoint(mv2);                             Triangle tri = { v0, v1, v2 };                             thisMeshTriangles.push_back(tri);                        }                    }                    _calculatedMeshPartBoxes[QPair<int,int>(i, j)] = thisPartBounds;                }                _calculatedMeshTriangles[i] = thisMeshTriangles;                _calculatedMeshPartBoxesValid = true;            }        }        _calculatedMeshBoxesValid = true;        _calculatedMeshTrianglesValid = pickAgainstTriangles;    }} void Model::renderSetup(RenderArgs* args) {    // set up dilated textures on first render after load/simulate    const FBXGeometry& geometry = getFBXGeometry();    if (_dilatedTextures.isEmpty()) {        foreach (const FBXMesh& mesh, geometry.meshes) {            QVector<QSharedPointer<Texture> > dilated;            dilated.resize(mesh.parts.size());            _dilatedTextures.append(dilated);        }    }     if (!_meshGroupsKnown && isLoaded()) {        segregateMeshGroups();    }} void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene) {    if (_isVisible != newValue) {        _isVisible = newValue;         render::PendingChanges pendingChanges;        foreach (auto item, _modelMeshRenderItems.keys()) {            pendingChanges.resetItem(item, _modelMeshRenderItems[item]);        }        foreach (auto item, _collisionRenderItems.keys()) {            pendingChanges.resetItem(item, _collisionRenderItems[item]);        }        scene->enqueuePendingChanges(pendingChanges);    }} bool Model::addToScene(std::shared_ptr<render::Scene> scene,                       render::PendingChanges& pendingChanges,                       render::Item::Status::Getters& statusGetters,                       bool showCollisionHull) {    if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) {        _showCollisionHull = showCollisionHull;        segregateMeshGroups();    }     bool somethingAdded = false;     if (_modelMeshRenderItems.empty()) {        foreach (auto renderItem, _modelMeshRenderItemsSet) {            auto item = scene->allocateID();            auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);            if (statusGetters.size()) {                renderPayload->addStatusGetters(statusGetters);            }            pendingChanges.resetItem(item, renderPayload);            _modelMeshRenderItems.insert(item, renderPayload);            somethingAdded = true;        }    }    if (_collisionRenderItems.empty()) {        foreach (auto renderItem, _collisionRenderItemsSet) {            auto item = scene->allocateID();            auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);            if (statusGetters.size()) {                renderPayload->addStatusGetters(statusGetters);            }            pendingChanges.resetItem(item, renderPayload);            _collisionRenderItems.insert(item, renderPayload);            somethingAdded = true;        }    }     updateRenderItems();     _readyWhenAdded = readyToAddToScene();     return somethingAdded;} void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {    foreach (auto item, _modelMeshRenderItems.keys()) {        pendingChanges.removeItem(item);    }    _modelMeshRenderItems.clear();    _modelMeshRenderItemsSet.clear();    foreach (auto item, _collisionRenderItems.keys()) {        pendingChanges.removeItem(item);    }    _collisionRenderItems.clear();    _collisionRenderItemsSet.clear();    _meshGroupsKnown = false;    _readyWhenAdded = false;} void Model::renderDebugMeshBoxes(gpu::Batch& batch) {    int colorNdx = 0;    _mutex.lock();    foreach(AABox box, _calculatedMeshBoxes) {        if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) {            _debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID();        }        QVector<glm::vec3> points;         glm::vec3 brn = box.getCorner();        glm::vec3 bln = brn + glm::vec3(box.getDimensions().x, 0, 0);        glm::vec3 brf = brn + glm::vec3(0, 0, box.getDimensions().z);        glm::vec3 blf = brn + glm::vec3(box.getDimensions().x, 0, box.getDimensions().z);         glm::vec3 trn = brn + glm::vec3(0, box.getDimensions().y, 0);        glm::vec3 tln = bln + glm::vec3(0, box.getDimensions().y, 0);        glm::vec3 trf = brf + glm::vec3(0, box.getDimensions().y, 0);        glm::vec3 tlf = blf + glm::vec3(0, box.getDimensions().y, 0);         points << brn << bln;        points << brf << blf;        points << brn << brf;        points << bln << blf;         points << trn << tln;        points << trf << tlf;        points << trn << trf;        points << tln << tlf;         points << brn << trn;        points << brf << trf;        points << bln << tln;        points << blf << tlf;         glm::vec4 color[] = {            { 1.0f, 0.0f, 0.0f, 1.0f }, // red            { 0.0f, 1.0f, 0.0f, 1.0f }, // green            { 0.0f, 0.0f, 1.0f, 1.0f }, // blue            { 1.0f, 0.0f, 1.0f, 1.0f }, // purple            { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow            { 0.0f, 1.0f, 1.0f, 1.0f }, // cyan            { 1.0f, 1.0f, 1.0f, 1.0f }, // white            { 0.0f, 0.5f, 0.0f, 1.0f },            { 0.0f, 0.0f, 0.5f, 1.0f },            { 0.5f, 0.0f, 0.5f, 1.0f },            { 0.5f, 0.5f, 0.0f, 1.0f },            { 0.0f, 0.5f, 0.5f, 1.0f } };         DependencyManager::get<GeometryCache>()->updateVertices(_debugMeshBoxesID, points, color[colorNdx]);        DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINES, _debugMeshBoxesID);        colorNdx++;    }    _mutex.unlock();} Extents Model::getBindExtents() const {    if (!isActive()) {        return Extents();    }    const Extents& bindExtents = getFBXGeometry().bindExtents;    Extents scaledExtents = { bindExtents.minimum * _scale, bindExtents.maximum * _scale };    return scaledExtents;} Extents Model::getMeshExtents() const {    if (!isActive()) {        return Extents();    }    const Extents& extents = getFBXGeometry().meshExtents;     // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which    // is captured in the offset matrix    glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));    glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));    Extents scaledExtents = { minimum * _scale, maximum * _scale };    return scaledExtents;} Extents Model::getUnscaledMeshExtents() const {    if (!isActive()) {        return Extents();    }     const Extents& extents = getFBXGeometry().meshExtents;     // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which    // is captured in the offset matrix    glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));    glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));    Extents scaledExtents = { minimum, maximum };     return scaledExtents;} Extents Model::calculateScaledOffsetExtents(const Extents& extents,                                            glm::vec3 modelPosition, glm::quat modelOrientation) const {    // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix    glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));    glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));     Extents scaledOffsetExtents = { ((minimum + _offset) * _scale),                                    ((maximum + _offset) * _scale) };     Extents rotatedExtents = scaledOffsetExtents.getRotated(modelOrientation);     Extents translatedExtents = { rotatedExtents.minimum + modelPosition,                                  rotatedExtents.maximum + modelPosition };     return translatedExtents;} /// Returns the world space equivalent of some box in model space.AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const {    return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation));} glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const {    // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix    glm::vec3 offsetPoint = glm::vec3(getFBXGeometry().offset * glm::vec4(point, 1.0f));    glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale);    glm::vec3 rotatedPoint = _rotation * scaledPoint;    glm::vec3 translatedPoint = rotatedPoint + _translation;    return translatedPoint;} void Model::clearJointState(int index) {    _rig->clearJointState(index);} void Model::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {    _rig->setJointState(index, valid, rotation, translation, priority);} void Model::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) {    _rig->setJointRotation(index, valid, rotation, priority);} void Model::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {    _rig->setJointTranslation(index, valid, translation, priority);} int Model::getParentJointIndex(int jointIndex) const {    return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).parentIndex : -1;} int Model::getLastFreeJointIndex(int jointIndex) const {    return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;} void Model::setTextures(const QVariantMap& textures) {    if (isLoaded()) {        _needsUpdateTextures = true;        _geometry->getGeometry()->setTextures(textures);    }} void Model::setURL(const QUrl& url) {    // don't recreate the geometry if it's the same URL    if (_url == url && _geometry && _geometry->getURL() == url) {        return;    }     _url = url;     {        render::PendingChanges pendingChanges;        render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();        removeFromScene(scene, pendingChanges);        scene->enqueuePendingChanges(pendingChanges);    }     _needsReload = true;    _needsUpdateTextures = true;    _meshGroupsKnown = false;    invalidCalculatedMeshBoxes();    deleteGeometry();     _geometry = DependencyManager::get<ModelCache>()->getGeometry(url);    onInvalidate();} void Model::setCollisionModelURL(const QUrl& url) {    if (_collisionUrl == url) {        return;    }    _collisionUrl = url;    _collisionGeometry = DependencyManager::get<ModelCache>()->getGeometry(url);} bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {    return _rig->getJointPositionInWorldFrame(jointIndex, position, _translation, _rotation);} bool Model::getJointPosition(int jointIndex, glm::vec3& position) const {    return _rig->getJointPosition(jointIndex, position);} bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const {    return _rig->getJointRotationInWorldFrame(jointIndex, rotation, _rotation);} bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const {    return _rig->getJointRotation(jointIndex, rotation);} bool Model::getJointTranslation(int jointIndex, glm::vec3& translation) const {    return _rig->getJointTranslation(jointIndex, translation);} bool Model::getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotationOut) const {    return _rig->getAbsoluteJointRotationInRigFrame(jointIndex, rotationOut);} bool Model::getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translationOut) const {    return _rig->getAbsoluteJointTranslationInRigFrame(jointIndex, translationOut);} bool Model::getRelativeDefaultJointRotation(int jointIndex, glm::quat& rotationOut) const {    return _rig->getRelativeDefaultJointRotation(jointIndex, rotationOut);} bool Model::getRelativeDefaultJointTranslation(int jointIndex, glm::vec3& translationOut) const {    return _rig->getRelativeDefaultJointTranslation(jointIndex, translationOut);} bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const {    return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation);} QStringList Model::getJointNames() const {    if (QThread::currentThread() != thread()) {        QStringList result;        QMetaObject::invokeMethod(const_cast<Model*>(this), "getJointNames", Qt::BlockingQueuedConnection,            Q_RETURN_ARG(QStringList, result));        return result;    }    return isActive() ? getFBXGeometry().getJointNames() : QStringList();} class Blender : public QRunnable {public:     Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,        const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);     virtual void run(); private:     ModelPointer _model;    int _blendNumber;    std::weak_ptr<NetworkGeometry> _geometry;    QVector<FBXMesh> _meshes;    QVector<float> _blendshapeCoefficients;}; Blender::Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,        const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :    _model(model),    _blendNumber(blendNumber),    _geometry(geometry),    _meshes(meshes),    _blendshapeCoefficients(blendshapeCoefficients) {} void Blender::run() {    PROFILE_RANGE(__FUNCTION__);    QVector<glm::vec3> vertices, normals;    if (_model) {        int offset = 0;        foreach (const FBXMesh& mesh, _meshes) {            if (mesh.blendshapes.isEmpty()) {                continue;            }            vertices += mesh.vertices;            normals += mesh.normals;            glm::vec3* meshVertices = vertices.data() + offset;            glm::vec3* meshNormals = normals.data() + offset;            offset += mesh.vertices.size();            const float NORMAL_COEFFICIENT_SCALE = 0.01f;            for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {                float vertexCoefficient = _blendshapeCoefficients.at(i);                const float EPSILON = 0.0001f;                if (vertexCoefficient < EPSILON) {                    continue;                }                float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;                const FBXBlendshape& blendshape = mesh.blendshapes.at(i);                for (int j = 0; j < blendshape.indices.size(); j++) {                    int index = blendshape.indices.at(j);                    meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;                    meshNormals[index] += blendshape.normals.at(j) * normalCoefficient;                }            }        }    }    // post the result to the geometry cache, which will dispatch to the model if still alive    QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",        Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),        Q_ARG(const std::weak_ptr<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),        Q_ARG(const QVector<glm::vec3>&, normals));} void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) {    if (_scaleToFit != scaleToFit || _scaleToFitDimensions != dimensions) {        _scaleToFit = scaleToFit;        _scaleToFitDimensions = dimensions;        _scaledToFit = false; // force rescaling    }} void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRescale) {    // NOTE: if the model is not active, then it means we don't actually know the true/natural dimensions of the    // mesh, and so we can't do the needed calculations for scaling to fit to a single largest dimension. In this    // case we will record that we do want to do this, but we will stick our desired single dimension into the    // first element of the vec3 for the non-fixed aspect ration dimensions    if (!isActive()) {        _scaleToFit = scaleToFit;        if (scaleToFit) {            _scaleToFitDimensions = glm::vec3(largestDimension, FAKE_DIMENSION_PLACEHOLDER, FAKE_DIMENSION_PLACEHOLDER);        }        return;    }     if (forceRescale || _scaleToFit != scaleToFit || glm::length(_scaleToFitDimensions) != largestDimension) {        _scaleToFit = scaleToFit;         // we only need to do this work if we're "turning on" scale to fit.        if (scaleToFit) {            Extents modelMeshExtents = getUnscaledMeshExtents();            float maxDimension = glm::distance(modelMeshExtents.maximum, modelMeshExtents.minimum);            float maxScale = largestDimension / maxDimension;            glm::vec3 modelMeshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum;            glm::vec3 dimensions = modelMeshDimensions * maxScale;             _scaleToFitDimensions = dimensions;            _scaledToFit = false; // force rescaling        }    }} glm::vec3 Model::getScaleToFitDimensions() const {    if (_scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER &&        _scaleToFitDimensions.z == FAKE_DIMENSION_PLACEHOLDER) {        return glm::vec3(_scaleToFitDimensions.x);    }    return _scaleToFitDimensions;} void Model::scaleToFit() {    // If our _scaleToFitDimensions.y/z are FAKE_DIMENSION_PLACEHOLDER then it means our    // user asked to scale us in a fixed aspect ratio to a single largest dimension, but    // we didn't yet have an active mesh. We can only enter this scaleToFit() in this state    // if we now do have an active mesh, so we take this opportunity to actually determine    // the correct scale.    if (_scaleToFit && _scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER            && _scaleToFitDimensions.z == FAKE_DIMENSION_PLACEHOLDER) {        setScaleToFit(_scaleToFit, _scaleToFitDimensions.x);

Lines 501–1000 of 1348. Previous lines