几何体

几何分类

  1. 隐式: 不告诉每个顶点在哪,但告诉几何关系,f(x, y, z) = 0,很难采样,但可以简单的判断出点是否在面上,或者物体内外
  2. 显式: 直接给出点的坐标,或者通过参数映射的方式给出,如: (u, v) => (x, y, z),容易采样,但很难判断点是否在面上,或者物体内外
  3. 按需选择,目前没有一个完美的方法解决所有问题

隐式几何

  1. 球体:x^2 + y^2 + z^2 = 1
  2. 甜甜圈: ...
  3. 心形: ...
  4. CSG: 通过基本几何的布尔运算(交集,并集,差集),形成复杂几何
  5. 距离函数SDF: 空间中任何一个点到你想要表述的几何形体上面任何一个点的最小距离
    1. 融合运动边界
    2. 水平集: 可以用一张表来表示距离函数,表里存储了离散值,针对每个离散值求f(x)=0
    3. 等高线
  6. 分形: 以不同缩放尺寸重复自己的形状,递归,broccoli

显示几何

  1. 点云: 只要空间中的点够密集,就能表示成物体表面,是一个点的数组,通常三维物体扫描是点云,经常被转换为多边形的面,如果密度较低,很难画出来
  2. 多边形面: 比较常用的应用,更多为三角形
  3. obj文件格式: 文本文件,定义了顶点,纹理坐标,法线,面(每3个顶点一个面,每个顶点包含顶点坐标,纹理坐标,法线)

贝塞尔曲线

  1. 用一系列控制点定义一个曲线
  2. 曲线一定经过起止点
  3. 二次贝塞尔曲线: 3个点p0, p1, p2给定一个t = [0,1],标记b0-b1,b1-b2上对应的t比例的点,连接这两个点,在找到该连线对应t比例的点,则这个点就是曲线上的一个点,针对所有t找到连续的曲线点,连接起来则为二次贝塞尔曲线
  4. 三次贝塞尔曲线: 4个点,同上
  5. 二次贝塞尔曲线代数求解: 点b01表示b0和b1上t的线性插值,p12同理,则b01 = (1-t)*b0 + t*b1, b12 = (1-t)*b1 + t*b2,则b02 = (1-t)*b01 + t*b12 = (1-t)^2 * b0 + 2t(1-t)*b1 + t^2 * b2
  6. n次贝塞尔曲线展开式: 伯恩斯坦多项式
  7. 性质
    1. 一定过起止点: b(0) = b0, b(1) = b1
    2. 三次贝塞尔起止点的切线: b'(0) = 3(b1 - b0), b'(1) = 3(b3 - b2)
    3. 给控制点做仿射变换,原曲线不变,等效于所有点做仿射变换
    4. 凸包: 1)包裹所有几何形体的最小凸多边形,2)橡皮筋绕钉子,自动收缩,3)贝塞尔曲线一定在控制点围成的多边形内
  8. 逐段贝塞尔曲线: 由多个贝塞尔曲线拼起来的,每4个控制点定义一段
  9. 如何控制曲线连接处是否平滑: 切线方向一致,且等距离
  10. C0连续: 连接点接触即可,第一段的终止点等于第二段的起点
  11. C1连续: 连接点切线方向一致,且等距离

样条

  1. 经过一系列点的连续的曲线
  2. b样条: 局部性,类似于逐段贝塞尔

曲面

  1. 贝塞尔曲面: 4条贝塞尔曲线,在某一时刻t对应的点作为控制点,在画一条贝塞尔曲线,则连续的时间t形成的面就是贝塞尔曲面

几何处理

  1. 网格细分
  2. 网格简化
  3. 网格正规化

网格细分

  1. 引入更多三角形
  2. 调整新旧顶点的位置
  3. loop细分: 按各边中点连线,1拆4,针对新旧顶点做不同的位置调整。取新顶点所在边的共享边的两个三角形,该边的顶点设为A,B,与该边相对的顶点为C,D,则新顶点P = 3/8 * (A + B) + 1/8 * (C + D)。取旧顶点周围共享该点的所有三角形,n表示顶点的度(连接边的数量),u表示跟度有关系的一个数(3/(8*n)),一方面要相信自己的位置,另一方面要相信相邻顶点的位置的平均,通过加权的方式得到新的位置,P = (1 - n*u) * origin_position + u * neighbor_position_sum
  4. catmull-clark细分: 对于一般网格的细分(非三角形),分为四边形面和非四边形面,定义奇异点是度不等于4的点
    1. 取每一条边的中点和每一个面的中点,并且把边上的中点和面的中点都连起来
    2. 经过一次细分之后,奇异点数从2变成了4
    3. 只要在非四边形中的点,连接边上的点,新引入的点一定是奇异点
    4. 非四边形面在一次细分之后,都变成了奇异点,以后奇异点数不再增加
    5. 面上的新点的更新方式: 取面的所有顶点求平均,(v1 + v2 + v3 + v4) / 4
    6. 边上的新点的更新方式: 取边的2个顶点与相邻面的新点求平均,(f1 + f2 + v1 + v2) /
    7. 旧点的更新方式: 取周围所有新点和自己本身求一个加权平均,((f1+f2+f3+f4) + 2*(m1+m2+m3+m4) + 4*p) / 16,其中f表示面上新点,m表示边上新点,p表示自身

网格简化

  1. 边坍缩: 把一条边的两个顶点,合为一个顶点,问题在于坍缩哪条边
  2. 二次度量误差: 新点到旧边的距离的平方和最小
  3. 边坍缩可以计算所有边的二次度量误差,从最小的开始坍缩,存在问题更新了一条边之后,产生新点和新边会导致之前计算的数据已经不准确了,用堆或者动态队列解决,贪心算法

阴影映射

  1. 图像空间算法: 不需要知道几何体,需解决锯齿问题
  2. 不在阴影中的点: 摄像机与光源都能看到这个点
  3. 经典shadow mapping只能处理点光源,也叫硬阴影
    1. 从光源看向场景,记录所有点的深度信息
    2. 从相机看向场景,看到的每一个点,映射回光源的视角,找到对应点的深度值,与记录该点的深度值作对比,如果等于记录的深度值,则可见,如果大于记录的深度值,则不可见
    3. 由于浮点数做相等判断有精度问题,会有一些斑点问题
    4. shadow map分辨率高,则锯齿就会少一些
  4. 软阴影: 物理中的半影,点光源只能产生硬阴影