从源头看Dust3d | (九)meshgenerator:网格生成

2021SC@SDUSC

目录

一、MeshGenerator类

(一)QObject类

(二)MeshGenerator类

二、重要函数

1.generate函数

2.reverseUuid函数

3.collectIncombinableMesh函数


一、MeshGenerator类

继承QObject类

(一)QObject类

   QObject类是所有QT对象的基类,还是“Qt中的对象模型”的核心类,其中最重要的功能就是“信号-槽”机制,“信号-槽”机制实现Qt对象之间的无缝交互

   以往点击按钮实现功能是通过回调函数与处理函数进行的,处理函数可以在适合的时候调用回调函数,但回调函数并不是类型安全的;并且回调函数与处理函数是强耦合的,处理函数必须要知道调用哪个回调函数

   信号与槽能代替上面的机制:在发生某一个特定事件的时候会产生一个信号,槽函数会接收特定的信号并且发出响应。因此,信号-槽机制是类型安全的,因为信号的签名与接收此信号的槽的签名一定是匹配的,不然无法实现接收功能

(二)MeshGenerator类

    MeshGenerator类的信号函数:void finished();

    槽函数:void process();

class MeshGenerator : public QObject
{
    Q_OBJECT
public:
    MeshGenerator(Snapshot *snapshot);
    ~MeshGenerator();
    bool isSuccessful();
    Model *takeResultMesh();
    Model *takePartPreviewMesh(const QUuid &partId);
    QImage *takePartPreviewImage(const QUuid &partId);
    const std::set<QUuid> &generatedPreviewPartIds();
    const std::set<QUuid> &generatedPreviewImagePartIds();
    Object *takeObject();
    std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *takeCutFaceTransforms();
    std::map<QUuid, std::map<QString, QVector2D>> *takeNodesCutFaces();
    void generate();
    void setGeneratedCacheContext(GeneratedCacheContext *cacheContext);
    void setSmoothShadingThresholdAngleDegrees(float degrees);
    void setInterpolationEnabled(bool interpolationEnabled);
    void setDefaultPartColor(const QColor &color);
    void setId(quint64 id);
    void setWeldEnabled(bool enabled);
    quint64 id();
signals:
    void finished();
public slots:
    void process();
    
private:
    QColor m_defaultPartColor = Qt::white;
    Snapshot *m_snapshot = nullptr;
    GeneratedCacheContext *m_cacheContext = nullptr;
    //脏标记位
    std::set<QString> m_dirtyComponentIds;
    std::set<QString> m_dirtyPartIds;
    float m_mainProfileMiddleX = 0;
    float m_sideProfileMiddleX = 0;
    float m_mainProfileMiddleY = 0;
    Object *m_object = nullptr;
    std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> m_nodeVertices;//顶点的位置及索引
    std::map<QString, std::set<QString>> m_partNodeIds;//存储顶点信息
    std::map<QString, std::set<QString>> m_partEdgeIds;//存储边信息
    std::set<QUuid> m_generatedPreviewPartIds;
    std::set<QUuid> m_generatedPreviewImagePartIds;
    Model *m_resultMesh = nullptr;
    std::map<QUuid, Model *> m_partPreviewMeshes;
    std::map<QUuid, QImage *> m_partPreviewImages;
    bool m_isSuccessful = false;
    bool m_cacheEnabled = false;
    float m_smoothShadingThresholdAngleDegrees = 60;//渲染角度阈值
    std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_cutFaceTransforms = nullptr;
    std::map<QUuid, std::map<QString, QVector2D>> *m_nodesCutFaces = nullptr;
    quint64 m_id = 0;
    std::vector<QVector3D> m_clothCollisionVertices;
    std::vector<std::vector<size_t>> m_clothCollisionTriangles;
    //焊接与插值
    bool m_weldEnabled = true;
    bool m_interpolationEnabled = true;
    
    //
    void collectParts();
    void collectIncombinableComponentMeshes(const QString &componentIdString);
    void collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache);
    //与脏标记相关:
    bool checkIsComponentDirty(const QString &componentIdString);
    bool checkIsPartDirty(const QString &partIdString);
    bool checkIsPartDependencyDirty(const QString &partIdString);
    void checkDirtyFlags();
    bool fillPartWithMesh(GeneratedPart &partCache, 
        const QUuid &fillMeshFileId,
        float deformThickness,
        float deformWidth,
        float cutRotation,
        const StrokeMeshBuilder *strokeMeshBuilder);
    MeshCombiner::Mesh *combinePartMesh(const QString &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes=true);
    MeshCombiner::Mesh *combineComponentMesh(const QString &componentIdString, CombineMode *combineMode);
    void makeXmirror(const std::vector<QVector3D> &sourceVertices, const std::vector<std::vector<size_t>> &sourceFaces,
        std::vector<QVector3D> *destVertices, std::vector<std::vector<size_t>> *destFaces);
    void collectSharedQuadEdges(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces,
        std::set<std::pair<PositionKey, PositionKey>> *sharedQuadEdges);
    MeshCombiner::Mesh *combineTwoMeshes(const MeshCombiner::Mesh &first, const MeshCombiner::Mesh &second,
        MeshCombiner::Method method,
        bool recombine=true);
    void generateSmoothTriangleVertexNormals(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
        const std::vector<QVector3D> &triangleNormals,
        std::vector<std::vector<QVector3D>> *triangleVertexNormals);
    const std::map<QString, QString> *findComponent(const QString &componentIdString);
    CombineMode componentCombineMode(const std::map<QString, QString> *component);
    MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
        GeneratedComponent &componentCache);
    MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
    QString componentColorName(const std::map<QString, QString> *component);
    void collectUncombinedComponent(const QString &componentIdString);
    void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
    void postprocessObject(Object *object);//后处理
    void collectErroredParts();
    void preprocessMirror();//镜面处理
    QString reverseUuid(const QString &uuidString);
};

二、重要函数

1.generate函数

     首先进行镜像处理,之后不断循环迭代cacheContext,得到它们的镜像部分,直到形成完整对称的几何体,完成镜像处理,之后再对合并网格进行焊接并再检查没有进行合并的网格,对没有进行合并的网格进行处理。最后,使用后处理完善模型m_object,生成新的模型

void MeshGenerator::generate()
{
    if (nullptr == m_snapshot)
        return;

    m_isSuccessful = true;
    
    QElapsedTimer countTimeConsumed;//添加计时器
    countTimeConsumed.start();
    
    //获得canvas的位置
    m_mainProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat();
    m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
    m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
    
    preprocessMirror();//镜像处理
    
    m_object = new Object;
    m_object->meshId = m_id;
    //m_cutFaceTransforms = new std::map<QUuid, nodemesh::Builder::CutFaceTransform>;
    //m_nodesCutFaces = new std::map<QUuid, std::map<QString, QVector2D>>;
    
    bool needDeleteCacheContext = false;//用于表示CacheContext是否存在
    if (nullptr == m_cacheContext) {
        m_cacheContext = new GeneratedCacheContext;
        needDeleteCacheContext = true;
    } else {
        
        m_cacheEnabled = true;
        //parts
        for (auto it = m_cacheContext->parts.begin(); it != m_cacheContext->parts.end(); ) {
            if (m_snapshot->parts.find(it->first) == m_snapshot->parts.end()) {
                //在partMirrorIdMap中找到mirrorFrom并加进cacheContext
                auto mirrorFrom = m_cacheContext->partMirrorIdMap.find(it->first);
                if (mirrorFrom != m_cacheContext->partMirrorIdMap.end()) {
                    if (m_snapshot->parts.find(mirrorFrom->second) != m_snapshot->parts.end()) {
                        it++;
                        continue;
                    }
                    m_cacheContext->partMirrorIdMap.erase(mirrorFrom);
                }
                it->second.releaseMeshes();
                it = m_cacheContext->parts.erase(it);
                continue;
            }
            it++;
        }
        //components
        for (auto it = m_cacheContext->components.begin(); it != m_cacheContext->components.end(); ) {
            if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) {
                for (auto combinationIt = m_cacheContext->cachedCombination.begin(); combinationIt != m_cacheContext->cachedCombination.end(); ) {
                    if (-1 != combinationIt->first.indexOf(it->first)) {
                        //qDebug() << "Removed cached combination:" << combinationIt->first;
                        delete combinationIt->second;
                        combinationIt = m_cacheContext->cachedCombination.erase(combinationIt);
                        continue;
                    }
                    combinationIt++;
                }
                it->second.releaseMeshes();
                it = m_cacheContext->components.erase(it);
                continue;
            }
            it++;
        }
    }
    
    collectParts();//存储点和边的信息
    checkDirtyFlags();
    
    //用dirty位进行优化加速
    for (const auto &dirtyComponentId: m_dirtyComponentIds) {
        for (auto combinationIt = m_cacheContext->cachedCombination.begin(); combinationIt != m_cacheContext->cachedCombination.end(); ) {
            if (-1 != combinationIt->first.indexOf(dirtyComponentId)) {
                //qDebug() << "Removed dirty cached combination:" << combinationIt->first;
                delete combinationIt->second;
                combinationIt = m_cacheContext->cachedCombination.erase(combinationIt);
                continue;
            }
            combinationIt++;
        }
    }
    
    m_dirtyComponentIds.insert(QUuid().toString());
    //进行组合
    
    CombineMode combineMode;
    auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
    
    const auto &componentCache = m_cacheContext->components[QUuid().toString()];
    
    m_object->nodes = componentCache.objectNodes;
    m_object->edges = componentCache.objectEdges;
    m_nodeVertices = componentCache.objectNodeVertices;
        
    std::vector<QVector3D> combinedVertices;
    std::vector<std::vector<size_t>> combinedFaces;
    if (nullptr != combinedMesh) {
        combinedMesh->fetch(combinedVertices, combinedFaces);
        //焊接
        if (m_weldEnabled) {
            size_t totalAffectedNum = 0;
            size_t affectedNum = 0;
            do {
                std::vector<QVector3D> weldedVertices;
                std::vector<std::vector<size_t>> weldedFaces;
                affectedNum = weldSeam(combinedVertices, combinedFaces,
                    0.025, componentCache.noneSeamVertices,
                    weldedVertices, weldedFaces);
                //将两个面焊接起来
                combinedVertices = weldedVertices;
                combinedFaces = weldedFaces;
                totalAffectedNum += affectedNum;
            } while (affectedNum > 0);
        }
        recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
        //处理经过焊接的部分
        m_object->vertices = combinedVertices;
        m_object->triangles = combinedFaces;
    }
    
    // 递归检查未组合的组件
    collectUncombinedComponent(QUuid().toString());
    collectIncombinableComponentMeshes(QUuid().toString());
    
    collectErroredParts();
    postprocessObject(m_object);//后处理
    
    m_resultMesh = new Model(*m_object);//生成新模型
    
    delete combinedMesh;

    if (needDeleteCacheContext) {
        delete m_cacheContext;
        m_cacheContext = nullptr;
    }
    
    qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
}

2.reverseUuid函数

    实现Uuid(唯一码)的倒转,用于实现镜面效果

QString MeshGenerator::reverseUuid(const QString &uuidString)
{
    QUuid uuid(uuidString);
    QString newIdString = uuid.toString();
    QString newRawId = newIdString.mid(1, 8) +
        newIdString.mid(10, 4) +
        newIdString.mid(15, 4) +
        newIdString.mid(20, 4) +
        newIdString.mid(25, 12);
    std::reverse(newRawId.begin(), newRawId.end());
    return "{" + newRawId.mid(0, 8) + "-" +
        newRawId.mid(8, 4) + "-" +
        newRawId.mid(12, 4) + "-" +
        newRawId.mid(16, 4) + "-" +
        newRawId.mid(20, 12) + "}";
}

3.collectIncombinableMesh函数

    调用recoverQuads将没有合并的四边形与三角形面都放入到uncombinedTriangleAndQuads中

    用updateVertexIndices经过两次循环得到所有没有合并的面数

    最后将没有合并的点、面与m_object进行合并

void MeshGenerator::collectIncombinableMesh(const MeshCombiner::Mesh *mesh, const GeneratedComponent &componentCache)
{
    if (nullptr == mesh)
        return;
    //获取未合并点与面的信息

    std::vector<QVector3D> uncombinedVertices;
    std::vector<std::vector<size_t>> uncombinedFaces;
    mesh->fetch(uncombinedVertices, uncombinedFaces);
    std::vector<std::vector<size_t>> uncombinedTriangleAndQuads;
    
    //将没有合并的四边形与三角形面合并
    recoverQuads(uncombinedVertices, uncombinedFaces, componentCache.sharedQuadEdges, uncombinedTriangleAndQuads);
    
    //迭代得出所有数量
    auto vertexStartIndex = m_object->vertices.size();
    auto updateVertexIndices = [=](std::vector<std::vector<size_t>> &faces) {
        for (auto &it: faces) {
            for (auto &subIt: it)
                subIt += vertexStartIndex;
        }
    };

    //使用updateVertexIndices得出未合并的所有面数
    updateVertexIndices(uncombinedFaces);
    updateVertexIndices(uncombinedTriangleAndQuads);
    
    //将未合并的点、面与m_object合并
    m_object->vertices.insert(m_object->vertices.end(), uncombinedVertices.begin(), uncombinedVertices.end());
    m_object->triangles.insert(m_object->triangles.end(), uncombinedFaces.begin(), uncombinedFaces.end());
    m_object->triangleAndQuads.insert(m_object->triangleAndQuads.end(), uncombinedTriangleAndQuads.begin(), uncombinedTriangleAndQuads.end());
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值