Dust3D项目实训十二 | 基于skinnedmeshcreator的蒙皮网格生成分析

本文档介绍了Dust3D项目中的SkinnedMeshCreator模块,该模块专注于网格蒙皮的生成和更新,特别是在几何体变换后的适应。网格蒙皮涉及骨骼对网格点的权重控制,SkinnedMeshCreator通过createMeshFromTransform函数实现变换后的蒙皮匹配,确保在任何情况下都能得到合适的蒙皮效果。

2021SC@SDUSC

目录

分析概括

模块功能

 ​ 网格蒙皮详解

关键代码分析

SkinnedMeshCreator.h分析

SkinnedMeshCreator.cpp分析

SkinnedMeshCreator()函数

createMeshFromTransform()函数


分析概括

模块功能

此模块主要用于网格蒙皮的生成以及几何体发生变换后网格蒙皮的更新,在进行位置变换后部分网格发生了数量和位置的变换,而skinnedmeshcreator的功能就在于适配这种变换使任何情况下都形成合适的蒙皮网络

  
网格蒙皮详解

网格是蒙皮和自由变形的基础,蒙皮的本质也就是让骨骼控制网格上的点。 如果一个点受 N 个骨骼影响,那么这些根骨骼将按百分比,分配谁控制的多,谁控制的少(权重)。在蒙皮的过程中,主要的工作就是让权重值分配的合理。蒙皮的详细过程为:

  1. 创建好骨骼和网格点

  2. 添加影响骨骼

  3. 调整权重。设置权重值:选中指定的点,再指定好它受哪个骨骼影响,然后调值

关键代码分析

SkinnedMeshCreator.h分析

class SkinnedMeshCreator
{
public:
    SkinnedMeshCreator(const Object &object,
        const std::map<int, RigVertexWeights> &resultWeights);//构造函数
    Model *createMeshFromTransform(const std::vector<QMatrix4x4> &matricies);//在变换中创建网格
private:
    Object m_object;
    std::map<int, RigVertexWeights> m_resultWeights;
    std::vector<std::vector<int>> m_verticesOldIndices;//旧索引顶点
    std::vector<std::vector<QVector3D>> m_verticesBindPositions;//顶点绑定位置
    std::vector<std::vector<QVector3D>> m_verticesBindNormals;//顶点绑定法线
    std::vector<QColor> m_triangleColors;//三角面片颜色
};

SkinnedMeshCreator.cpp分析

SkinnedMeshCreator()函数

SkinnedMeshCreator()用于蒙皮网格内变量的初始化、初始属性的设置

SkinnedMeshCreator::SkinnedMeshCreator(const Object &object,const std::map<int, RigVertexWeights> &resultWeights) :m_object(object),m_resultWeights(resultWeights)
{
    //对原物体的三角面片信息的size进行resize判断重载
    m_verticesOldIndices.resize(m_object.triangles.size());
    m_verticesBindNormals.resize(m_object.triangles.size());
    m_verticesBindPositions.resize(m_object.triangles.size());
    const std::vector<std::vector<QVector3D>> *triangleVertexNormals = m_object.triangleVertexNormals();
    for (size_t triangleIndex = 0; triangleIndex < m_object.triangles.size(); triangleIndex++) {
        //迭代每一个三角面片
        for (int j = 0; j < 3; j++) {
            //迭代三角面片每一个点
            int oldIndex = m_object.triangles[triangleIndex][j];
            m_verticesOldIndices[triangleIndex].push_back(oldIndex);//旧索引顶点后添加oldIndex
            m_verticesBindPositions[triangleIndex].push_back(m_object.vertices[oldIndex]);//顶点绑定位置中添加vertices
            if (nullptr != triangleVertexNormals)
                m_verticesBindNormals[triangleIndex].push_back((*triangleVertexNormals)[triangleIndex][j]);
            else
                m_verticesBindNormals[triangleIndex].push_back(QVector3D());
        }
    }
    
    std::map<std::pair<QUuid, QUuid>, QColor> sourceNodeToColorMap;
    for (const auto &node: object.nodes)
        sourceNodeToColorMap.insert({{node.partId, node.nodeId}, node.color});
    //为面片添加颜色,初始为白色
    m_triangleColors.resize(m_object.triangles.size(), Theme::white);
    const std::vector<std::pair<QUuid, QUuid>> *triangleSourceNodes = object.triangleSourceNodes();
    if (nullptr != triangleSourceNodes) {
        for (size_t triangleIndex = 0; triangleIndex < m_object.triangles.size(); triangleIndex++) {
            const auto &source = (*triangleSourceNodes)[triangleIndex];
            m_triangleColors[triangleIndex] = sourceNodeToColorMap[source];//为每一个三角面片赋予颜色
        }
    }
}

createMeshFromTransform()函数

createMeshFromTransform()用于几何体变换后的网格蒙皮修改操作,通过判断变换前后的位置变换形成新的网格,将旧网格的属性信息进行变换后赋予新网格,从而进行蒙皮的匹配

Model *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatrix4x4> &matricies)
{
    std::vector<std::vector<QVector3D>> transformedPositions = m_verticesBindPositions;
    std::vector<std::vector<QVector3D>> transformedPoseNormals = m_verticesBindNormals;
    
    if (!matricies.empty()) {
        //如果矩阵非空,更新变换的位置以及法线
        for (size_t i = 0; i < transformedPositions.size(); ++i) {
            //循环遍历变换位置信息
            for (size_t j = 0; j < 3; ++j) {
                const auto &weight = m_resultWeights[m_verticesOldIndices[i][j]];//赋予权重为顶点旧索引的结果权重
                QMatrix4x4 mixedMatrix;创建4*4的混合矩阵
                transformedPositions[i][j] = QVector3D();
                transformedPoseNormals[i][j] = QVector3D();
                for (int x = 0; x < MAX_WEIGHT_NUM; x++) {
                    float factor = weight.boneWeights[x];
                    if (factor > 0) {
                        //生成变换后的位置以及法线
                        transformedPositions[i][j] += matricies[weight.boneIndices[x]] * m_verticesBindPositions[i][j] * factor;
                        transformedPoseNormals[i][j] += matricies[weight.boneIndices[x]] * m_verticesBindNormals[i][j] * factor;
                    }
                }
            }
        }
    }
    
    ShaderVertex *triangleVertices = new ShaderVertex[m_object.triangles.size() * 3];
    int triangleVerticesNum = 0;
    for (size_t triangleIndex = 0; triangleIndex < m_object.triangles.size(); triangleIndex++) {
        for (int i = 0; i < 3; i++) {
            //设置变换后的颜色、位置、顶点、法线信息
            ShaderVertex &currentVertex = triangleVertices[triangleVerticesNum++];
            const auto &sourcePosition = transformedPositions[triangleIndex][i];
            const auto &sourceColor = m_triangleColors[triangleIndex];
            const auto &sourceNormal = transformedPoseNormals[triangleIndex][i];
            currentVertex.posX = sourcePosition.x();
            currentVertex.posY = sourcePosition.y();
            currentVertex.posZ = sourcePosition.z();
            currentVertex.texU = 0;
            currentVertex.texV = 0;
            currentVertex.colorR = sourceColor.redF();
            currentVertex.colorG = sourceColor.greenF();
            currentVertex.colorB = sourceColor.blueF();
            currentVertex.normX = sourceNormal.x();
            currentVertex.normY = sourceNormal.y();
            currentVertex.normZ = sourceNormal.z();
            currentVertex.metalness = Model::m_defaultMetalness;
            currentVertex.roughness = Model::m_defaultRoughness;
        }
    }
    
    return new Model(triangleVertices, triangleVerticesNum);//返回新模型
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值