Games101学习笔记(2)--作业4(Geometry)

155 阅读2分钟

1.基础知识

1.1 显式(Explicit)和隐式(Implicit)几何

  • Implicit:几何上的点符合某种特定的关系,如代数表达式,水平集和距离函数等; image.png image.png image.png image.png image.png 优点:1. 准确的描述;2. 针对几何的查询更简单(比如判断是否在几何体内,是否和几何体相交);3.拓扑变换更易处理。
  • Explicit:直接给出点的信息,如点云、多边形网格、NURBS。 image.png image.png

1.2 曲线(Curves)

重点是Bezier Curves(贝塞尔曲线);

4448664BC81882D4CD98690085F13647.png 贝塞尔曲线的代数表达式推导如下:

image.png

image.png image.png 贝塞尔曲线有个缺点:当起始的点数过多,就会导致曲线难以控制(每个起始点作为控制点的影响小)。为了解决这个问题,分段贝塞尔曲线是最常用的方法。 分段贝塞尔曲线最需要关注的是两段曲线连接处的光滑问题。 解决该问题的结论是:当两侧控制点与分段交接点共线且形成的线段长度相等时,满足曲线平滑性质。

1.3 曲面(surfaces)

bezier surfaces:将贝塞尔曲线扩展到面上。

image.png image.png

2. 网格的操作

Mesh subdivision;
Mesh simplification;
Mesh regularization;

2.1 subdivison(细分)

首先产生更多的三角形,然后调整他们的位置。

2.1.1 Loop subdivision

只针对三角形网格

  1. 先产生更多的三角形: image.png
  2. 调整每个点的位置,新产生的点和旧的点调整方式不同。

image.png

image.png

2.1.2 Catmull-Clark Subdivision

任意多边形网格

  • degree(度):一个点相邻点的个数;
  • Extraordinary vertex(奇异点):度不为4的点; 基本思路:
  1. 每个面增加一个顶点,每条边的中点增加一个顶点;

image.png 2. 第一次细分步骤后,所有的非四边形面消失了,形成了奇异点,之后只需要重复步骤1即可。

2.2 Simplification(简化)

image.png

消融影响小的顶点

怎样定义顶点对整体的影响呢? 使用二次度量误差(Quadric Error Metrics)

image.png QEM定义为顶点到其领域的三角面的距离的平方和。 边的QEM是顶点的QEM之和。 计算出每条边的QEM后,每次消融QEM最小的边,再计算所有边的QEM; 重复上述步骤,达到预期效果为止。

3. 作业

实现de Casteljau算法来绘制由4个控制点表示的Bézier曲线

image.png

cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t)
{
    // TODO: Implement de Casteljau's algorithm
    auto p = control_points;
    int loop = 0;
    while (loop < control_points.size() - 1)
    {
        for (int i = 0; i < control_points.size() - loop; i++)
        {
            p[i].x = (1 - t) * p[i].x + t * p[i + 1].x;
            p[i].y = (1 - t) * p[i].y + t * p[i + 1].y;
        }
        loop++;
    }
    return cv::Point2f(p[0]);
}

void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window)
{
    // TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's
    // recursive Bezier algorithm.
    for (double t = 0.0; t <= 1.0; t += 0.00001)
    {
        auto point = recursive_bezier(control_points, t);
        window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
    }
}

对于每一个t都需要且只需要最终的点坐标,所以先复制一个控制点数组(以防后来赋值操作改变了控制点数组的值),然后两个点算出t分点的坐标,并用索引小的元素存储坐标。