源码分析学习记录(3)——细分曲面

本文介绍了细分曲面在建模中的重要性,特别是Catmull-Clark细分算法。这个算法能够处理任意拓扑的多边形并保持平滑效果。文中详细讲解了算法的几个关键步骤,如创建中间节点、二维面细分、网格平滑等,并涉及到插值函数、边长平均计算等技术。
摘要由CSDN通过智能技术生成

2021SC@SDUSC
细分曲面是建模技术中面表示的重要方式,它通过存储低分辨率控制网格以及相关细分规则来获取平滑网格曲面,解决了任意拓扑和一致性表示问题,保留局部性、仿射不变性。例如,硬多边形建模的基本流程就是使用最少的面来表达物体的形状,再通过添加细分曲面使模型变得平滑。Dust3D研发时期侧视图

Catmull-Clark细分

曲面细分需要有几何规则和拓扑规则,几何规则用于计算新顶点的位置,拓扑规则用于确定新顶点的连接关系。从作者的blog中我们推测Dust3D采用Catmull-Clark算法进行模型曲面的细分,引入了CGAL库中的Subdivision_method。Catmull-Clark细分是一种非常重要的网格细分法则,其可以对任意拓扑结构的多边形进行细分。
在这里插入图片描述

请添加图片描述

createIntermediateNode()

首先来看一个简单的插值函数。插值技术从我们一开始在计算机图形学课上接触时就已经感受到了它不可撼动的重要地位,它在曲线平滑、数字图像处理、计算机动画中有广泛应用。
在这里插入图片描述

void StrokeModifier::createIntermediateNode(const Node &firstNode, const Node &secondNode, float factor, Node *resultNode)
{
   
    float firstFactor = 1.0 - factor;
    //节点位置插值
    resultNode->position = firstNode.position * firstFactor + secondNode.position * factor;
    //插值得节点半径
    resultNode->radius = firstNode.radius * firstFactor + secondNode.radius * factor;
    //复制邻近节点的参数
    if (factor <= 0.5) {
   
        resultNode->originNodeIndex = firstNode.originNodeIndex;
        resultNode->nearOriginNodeIndex = firstNode.originNodeIndex;
        resultNode->farOriginNodeIndex = secondNode.originNodeIndex;
        resultNode->cutRotation = firstNode.cutRotation;
        resultNode->cutTemplate = firstNode.cutTemplate;
    } else {
   
        resultNode->originNodeIndex = secondNode.originNodeIndex;
        resultNode->nearOriginNodeIndex = secondNode.originNodeIndex;
        resultNode->farOriginNodeIndex = firstNode.originNodeIndex;
        resultNode->cutRotation = secondNode.cutRotation;
        resultNode->cutTemplate = secondNode.cutTemplate;
    }
}

subdivideFace2D()

输入一个面,对于面上的每个点生成新面点和新边点:

  • 新面点:原点与前后相邻的点三者加权平均,其中原点占最高的权重
  • 新边点:原点与相邻的下一个点的平均
void subdivideFace2D(std::vector<QVector2D> *face)
{
   
    auto oldFace = *face;
    face->resize(oldFace.size() * 2);
    for (size_t i = 0, n = 0; i < oldFace.size(); ++i) {
   
        size_t h = (i + oldFace.size() - 1) % oldFace.size();
        size_t j = (i + 1) % oldFace.size();
        //新面点
        (*face)[n++] = oldFace[h] * 0.125 + oldFace[i] * 0.75 + oldFace[j] * 0.125;
        //新边点
        (*face)[n++] = (oldFace[i] + oldFace[j]) * 0.5;
    }
}

网格平滑

interpolateSegment()

对from到to进行分段的插值

void CentripetalCatmullRomSpline::interpolateSegment(std::vector<QVector3D> &knots,
    size_t from, size_t to) 
{
   
    const QVector3D &p0 = knots[
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值