计算机图形学

0x01 概述

  • 计算机图形学(CG,Computer Graphics)是一门研究使用计算机生成图形的学科
    • 图形包括:形状、图片、动画、物体等
  • 研究内容
    • 输入:将图形或图形数据输入到计算机中的技术和设备
      • 输入设备:键盘、鼠标、扫描仪、触摸屏等
    • 表示:在计算机中使用几何和拓扑信息建立几何模型的方法
      • 几何信息:点、线、面的坐标值
      • 拓扑信息:点、线、面的连接关系
      • 几何模型:线框模型、面模型、体模型
    • 处理:对图像进行几何变换、投影变换、运算操作
      • 运算操作主要包括:并、交、差
    • 输出(显示):将计算机内特定表示形式的图形转换为图形输出设备能够接受的表示形式并显示或输出
      • 输出设备:显示器、打印机、绘图仪等
  • 相关应用
    • CAD:Computer Aided Design,计算机辅助设计
    • CAE:Computer Aided Education,计算机辅助教育
    • CAM:Computer Aided Making,计算机辅助制造
    • CIMS:Computer Integrated Manufacturing System,计算机集成制造系统
    • GIS:Geographical Information System,地理信息系统
    • GUI:Graphical User Interface,图形用户界面
    • AR:Augmented Reality,增强现实
    • VR:Virtual Reality,虚拟现实
    • 其他可视化、动画、仿真等领域的应用
  • 相关算法
    • 光栅扫描图形的生成:DDA、Bresenham 直线/圆弧算法、梁友栋-Barsky 算法
    • 图形变换
    • 真实感图形生成:Z 缓冲器算法、简单光照算法
    • 几何建模
    • 曲线曲面:贝塞尔曲线、均匀 B 样条、非均匀 B 样条

0x02 基本光栅生成

(1)概述

  • 目前应用最普及的显示器是基于阴极射线管(CRT)的光栅扫描显示器
    • 阴极射线管包括:电子枪、聚焦系统、加速电极、偏转系统、荧光屏
  • 像素:电子枪发射的电子束经过聚焦在偏转系统控制下轰击荧光屏而产生足够小的光点
  • 分辨率:CRT 在水平和垂直方向单位长度上能够识别的最大光点数
  • 光栅化:在绘制具有连续性质的直线、曲线或区域等基本图形时,需要确定最佳逼近器像素的过程
  • 扫描转换:光栅化按照扫描线的顺序的进行

(2)一维图形光栅化算法

a. 直线生成算法

I. 数值微分法 DDA

  • 数值微分法(DDA,Digital Differential Analyzer)公式如下:

    \[\begin{align*} |k|\lt1:y_{i+1}&=y_i+k\Delta x=y_i+k(\Delta x=1) \\ |k|\gt1:x_{i+1}&=x_i+\frac{\Delta y}k=x_i+\frac 1k(\Delta y=1) \end{align*} \]

  • 举例:用 DDA 转换两点\(A(1,0),\ B(2,3)\)的直线

    1. 两点构成直线的斜率 \(k=\frac{\Delta y}{\Delta x}=\frac{3-0}{2-1}=3\)

    2. 由于 \(|k|=3\gt1\),说明 \(\Delta y\gt\Delta x\),则有 \(x_{i+1}=x_i+\frac13\)\(\Delta y=1\),即 \(\begin{cases}x=x+\frac13\\y=y+1\end{cases}\)

    3. 根据上述结果,生成的离散点为:

      步进数 坐标
      0 \((1,\ 0)\)
      1 \((\frac43,\ 1)\approx(1,\ 1)\)
      2 \((\frac53,\ 2)\approx(2,\ 2)\)
      3 \((2,\ 3)\)

II. Bresenham 算法

  • Bresenham 算法公式如下:

    \[d_0=2\Delta y-\Delta x\\ \begin{cases} \ (x_i+1,\ y_i+1),\ d_i=d_{i-1}+2(\Delta y-\Delta x),\ d_i\geq0\\ \ (x_i+1,\ y_i),\ d_i=d_{i-1}+2\Delta y,\ d_i\lt0 \end{cases} \]

  • 举例:用 Bresenham 算法转换两点\(A(1,0),\ B(2,3)\)的直线

    1. \(d_0=2\Delta y_i-\Delta x=2\times(3-0)-(2-1)=5\ge0\)

    2. 根据上述结果,生成的离散点为:

      \(d_i\) 坐标
      5 \((1,\ 0)\)
      10 \((2,\ 1)\)
      15 \((3,\ 2)\)
      20 \((4,\ 3)\)

III. 异同

  • 都通过减少直线绘制过程中的浮点计算来提高效率
  • Bresenham 算法比 DDA 更准确、更高效
  • Bresenham 算法比 DDA 绘制圆和曲线精度更高
  • DDA 使用乘除法;Bresenham 算法使用加减法

b. 圆弧生成算法

  • 采用根据圆弧八分对称性的中点画圆法,公式如下:(\(r\) 表示半径)

    \[p_0=1-r,\ x_0=0,\ y_0=r\\ \begin{cases} (x_{i-1}+1,\ y_{i-1}-1),\ p_i=p_{i-1}+2(x_{i-1}-y_{i-1})+5\\ (x_{i-1}+1,\ y_{i-1}),\ p_i=p_{i-1}+2x_{i-1}+3,\ d\le 0 \end{cases} \]

    \(x_i\lt y_i\) 时,结束计算

(3)二维图形光栅化(区域填充)

多边形区域的表示方法包括:

  • 顶点表示:用多边形的顶点序列来表示多边形
    • 直观、几何意义强、占用内存少、易于几何变换
    • 没有明确指出多边形内的像素,不便区域填充
  • 点阵表示:用位于多边形内的像素集合来表示多边形
    • 便于区域填充
    • 丢失许多几何信息

a. 扫描线算法

  • 多边形填充步骤:
    1. 求交:计算扫描线与多边形各边的交点
    2. 排序:将交点按 \(x\) 值递增顺序排序
    3. 配对:每对交点代表扫描线与多边形的一个相交区间
    4. 填色:将相交区间内的像素填充为多边形颜色,以外的像素填充为背景色
  • 边的数据结构:
    • \(y_{max}\):边的上端点 \(y\) 坐标
    • \(x\):边的下端点 \(x\) 坐标(活化边链表中,表示扫描线与边的交点 \(x\) 坐标)
    • \(dx\):边的斜率的倒数 \(\frac1k\)
    • \(next\):指向下一条边的指针
  • 分类边表:按边的下端点 \(y\) 坐标,对非水平边进行分类的指针数组
    • \(y_i\) 归为第 \(i\) 类,类内按 \(x\)(相同时按\(dx\))的递增进行排序
  • 活性边:与当前扫描线相交的边
  • 有效边表:有效边按与扫描线交点 \(x\) 坐标值递增排序的链表
  • 有序边表算法:利用图形的空间连贯性和扫描线的连贯性来计算下一条扫描线与边的交点
  • 活化边表:由与当前扫描线相交的边组成,记录多边形的边沿扫描线的交点序列
    • 表随扫描线的移动而动态更新

b. 种子填充算法

  • 四连通区域:从源像素出发,通过上下左右移动,到达目标像素(四向)
    1. 种子像素入栈
    2. 当栈非空时,重复:
      1. 栈顶像素出栈
      2. 将出栈像素置为填充色
      3. 按四个方向检查与出栈像素的相邻像素,若其中某个像素不在边界且未设置成填充色,则将该像素入栈
  • 八连通区域:从源像素出发,通过上下左右以及对角线移动,到达目标像素(八向)
  • 四连通区域 \(\in\) 八连通区域
  • 四连通区域的边界是八连通区域,八连通区域的边界是四连通区域

0x03 几何变换

  • 齐次化:统一用矩阵乘法表示平移、旋转、缩放等几何变换,简化计算并便于硬件实现
  • 齐次坐标:用一个 \(n+1\) 维向量来表示一个 \(n\) 维向量
    • 规格化坐标:第 \(n+1\) 维向量的值为 \(1\)

(1)二维变换

a. 平移

  • 平移前坐标为 \((x,\ y)\)\(x\)\(y\) 轴方向分别平移 \(T_x\)\(T_y\) 个单位后,新坐标为 \((x',\ y')=(x+T_x,\ y+T_y)\)

  • 矩阵表示:

    \[\begin{bmatrix} x'\\y' \end{bmatrix} = \begin{bmatrix} 1&0\\ 0&1 \end{bmatrix} \begin{bmatrix} x\\y \end{bmatrix} + \begin{bmatrix} T_x\\T_y \end{bmatrix} \]

  • 采用齐次坐标:

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} 1&0&T_x\\ 0&1&T_y\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

b. 旋转

  • 旋转前坐标为 \((x,\ y)\),按逆时针旋转角 \(\theta\) 后,新坐标为 \((x',\ y')=(x\cos\theta-y\sin\theta,\ x\sin\theta+y\cos\theta)\)

  • 矩阵表示:

    \[\begin{bmatrix} x'\\y' \end{bmatrix} = \begin{bmatrix} S_x&0\\ 0&S_y \end{bmatrix} \begin{bmatrix} x\\y \end{bmatrix} \]

  • 采用齐次坐标:

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} S_x&0&0\\ 0&S_y&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

c. 缩放

  • 缩放前坐标为 \((x,\ y)\)\(x\)\(y\) 轴方向分别缩放 \(S_x\)\(S_y\) 倍后,新坐标为 \((x',\ y')=(xS_x,\ yS_y)\)

  • 矩阵表示:

    \[\begin{bmatrix} x'\\y' \end{bmatrix} = \begin{bmatrix} \cos\theta&-\sin\theta\\ \sin\theta&\cos\theta \end{bmatrix} \begin{bmatrix} x\\y \end{bmatrix} \]

  • 采用齐次坐标:

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} \cos\theta&-\sin\theta&0\\ \sin\theta&\cos\theta&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

d. 对称

均采用齐次坐标表示

  • 关于 \(x\) 轴对称,\((x',\ y')=(x,\ -y)\)

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} 1&0&0\\ 0&-1&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

  • 关于 \(y\) 轴对称,\((x',\ y')=(-x,\ y)\)

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} -1&0&0\\ 0&1&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

  • 关于坐标原点对称,\((x',\ y')=(-x,\ -y)\)

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} -1&0&0\\ 0&-1&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

e. 错切

均采用齐次坐标表示

  • 沿 \(y\) 轴错切,\((x',\ y')=(x,\ y+x\tan\theta)\)

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} 1&0&0\\ \tan\theta&1&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

  • 沿 \(x\) 轴错切,\((x',\ y')=(x+y\tan\theta,\ y)\)

    \[\begin{bmatrix} x'\\y'\\1 \end{bmatrix} = \begin{bmatrix} 1&\tan\theta&0\\ 0&1&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\1 \end{bmatrix} \]

(2)三维变换

均采用齐次坐标表示

  • 平移:

    \[\begin{bmatrix} x'\\y'\\z'\\1 \end{bmatrix} = \begin{bmatrix} 1&0&0&T_x\\ 0&1&0&T_y\\ 0&0&1&T_z\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\z\\1 \end{bmatrix} \]

  • 旋转:

    沿 \(x\) 轴逆时针旋转角 \(\theta\)

    \[\begin{bmatrix} x'\\y'\\z'\\1 \end{bmatrix} = \begin{bmatrix} 1&0&0&0\\ 0&\cos\theta&-\sin\theta&0\\ 0&\sin\theta&\cos\theta&0\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\z\\1 \end{bmatrix} \]

    沿 \(y\) 轴逆时针旋转角 \(\theta\)

    \[\begin{bmatrix} x'\\y'\\z'\\1 \end{bmatrix} = \begin{bmatrix} \cos\theta&0&\sin\theta&0\\ 0&1&0&0\\ -\sin\theta&0&\cos\theta&0\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\z\\1 \end{bmatrix} \]

    沿 \(z\) 轴逆时针旋转角 \(\theta\)

    \[\begin{bmatrix} x'\\y'\\z'\\1 \end{bmatrix} = \begin{bmatrix} \cos\theta&-\sin\theta&0&0\\ \sin\theta&\cos\theta&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} x\\y\\z\\1 \end{bmatrix} \]

0x04 直线段裁剪

(1)Cohen-Sutherland 算法

  • 二进制编码方法:共四位,依次表示 上下右左,剪裁区域编码如下:

    1001 1000 1010
    0001 0000 0010
    0101 0100 0110
  • 步骤:

    1. 求线段两端点的编码 \(code_1\)\(code_2\)
    2. 根据 \(code_1\)\(code_2\) 进行裁剪:
      • \(code_1=0\)\(code_2=0\),则线段在裁剪区域内
      • \(code_1\ \&\ code_2\neq0\),则线段两端点同在裁剪区域一侧
    3. 求出线段与裁剪区域的交点,在该交点处将线段一分为二,对在裁剪区域内的线段重复上述处理

(2)梁-Barsky 算法

  • 窗口边界的四条边分为两类:始边、终边

  • 对于 \((x_0,\ y_0)\)\((x_1,\ y_1)\) 构成的线段,有 \(\Delta x=x_1-x_0\\\Delta y=y_1-y_0\)

    \[\begin{cases} \Delta x\ge0\Rightarrow x=x_L为始边,x=x_R为终边\\ \Delta x\lt0\Rightarrow x=x_L为终边,x=x_R为始边 \end{cases} \]

    \[\begin{cases} \Delta y\ge0\Rightarrow y=y_B为始边,y=y_T为终边\\ \Delta y\lt0\Rightarrow y=y_B为终边,y=y_T为始边 \end{cases} \]

  • 步骤:

    1. 求线段两端点 \(P_0 P_1\) 与两条始边的交点参数 \(t_0\)\(t_1\),令 \(t_u=\max(t_0,\ t_1,\ 0)\),则 \(t_u\) 为三者中里距离 \(P_1\) 最近点的参数
    2. 求线段两端点 \(P_0 P_1\) 与两条终边的交点参数 \(t_2\)\(t_3\),令 \(t_v=\max(t_2,\ t_3,\ 0)\),则 \(t_v\) 为三者中里距离 \(P_0\) 最近点的参数
    3. \(t_v\gt t_v\),则可见线段区间为 \([t_v,\ t_u]\)
  • 裁剪条件:

    \[\begin{cases} x_L\le x_1+u\Delta x\le x_R\\ y_B\le y_1+u\Delta y\le y_T \end{cases} \]

    其中,\(up_k\le q_k(k=1,2,3,4)\)

    \[p_1=-\Delta x=x_1-x_2&q_1=x_1-x_L\\ p_2=\Delta x=x_2-x_1&q_2=x_R-x_1\\ p_3=-\Delta y=y_1-y_2&q_3=y_1-y_B\\ p_4=\Delta y=y_2-y_1&q_4=y_T-y_1 \]

0x05 光照模型

  • 真实感图形绘制:通过综合利用数学、物理学、计算机以及心理学等知识,在计算机图形输出设备上,绘制能够以假乱真的图像
  • 光强 \(I\):描述物体表面朝某方向辐射光的颜色
    • 既表示光能大小,又表示光的色彩组成

(1)基本光照模型

  • 光照模型:又称明暗模型,用于物体表面某点处的光强计算

  • 简单光照模型:只考虑反射光的作用

    • 反射光的组成包括:环境光、漫反射光、镜面反射光
  • 环境光:来自周围各个方向上的、均匀地向各个方向反射的光

    • 某点对环境光的反射强度为 \(I_e=I_aK_a\)
      • \(I_a\):物体表面对泛光的反射光强
      • \(K_a\):物体表面对泛光的反射率
  • 漫反射光:来自一个方向的、均匀地向各个方向反射的光

    • 某点的漫反射光强为 \(I_d=I_pK_d\cos\theta,\ \theta\in[0,\ \frac\pi2]\)
    • 如果 \(\theta\) 的两边入射向量 \(L\) 和法向量 \(N\) 均规格化为单位矢量,则 \(I_d=I_pK_d(L\cdot N)\)
  • 镜面反射光:遵循反射定律的、来自一个方向并法向量另一侧反射的光

    • 某点的镜面反射光强为 \(I_s=I_pK_s\cos^n\alpha\)
    • 如果 \(\alpha\) 的两边反射向量 \(R\) 和视线向量 \(V\) 均规格化为单位矢量,则 \(I_s=I_pK_s(R\cdot V)^n\)
  • 从视点观察到物体表面任意一点的光强为:

    \[\begin{align*} I&=I_e+I_d+I_s\\ &=I_aK_a+I_pK_d(L\cdot N)+I_pK_s(R\cdot V)^n \end{align*} \]

(2)Gouraud 明暗处理

  • 又称亮度插值明暗处理,通过对多边形顶点颜色进行线性插值来绘制其内部的各个点
  • 单线性插值发步骤:
    1. 计算每个多边形顶点处的平均单位法向量
    2. 对每个顶点根据简单光照模型来计算其光强
    3. 在多边形表面上将顶点强度进行线性插值
  • 双线性插值法步骤:
    1. 为每个多边形顶点赋予法向量
    2. 利用 Phong 光照模型计算顶点处平均光强
    3. 插值计算离散边上的各点光强
    4. 双线性插值多边形内部各点处的光强

(3)Phong 明暗处理

  • 又称法向量插值明暗处理,通过对多边形顶点的法向量进行插值,以产生中间各点的法向量
  • 步骤:
    1. 计算每个多边形顶点处的平均单位法向量
    2. 用双线性插值方法求多边形内部各点的法向量
    3. 按光照模型确定多边形内部各点的光强

(4)纹理

  • 颜色纹理:通过颜色的色彩或明暗度变化来体现出物体表面的细节

    • 取决于物体表面光学属性
    • 一般生成方法:预先定义纹理模式,之后建立物体表面的点与纹理模式的点之间的对应
  • 几何纹理:不规则细小凸凹

    • 取决于物体表面微观几何
  • 纹理映射:当物体表面的可见点确定后,以纹理模式的对应点参与光照模型进行计算,并把纹理模式附到物体表面的方法

    graph LR 1["纹理空间<br/>(s,t)数组坐标"] <--纹理和表面变换--> 2["物体空间<br/>(u,v)表面参数"] <--观察和投影变换--> 3["像素空间<br/>(x,y)像素坐标"]

(5)光线跟踪

  • 光线跟踪:基于几何光学原理,通过模拟光的传播路径,确定反射、折射、阴影等
  • 光线跟踪算法:逆向跟踪从光源发出的光,经由物体间的多词反射和折射后,投射到物体表面,并最终进入眼睛的过程
  • 光线跟踪算法特点:简单、生成的图像真实感强、计算量大
  • 光线逆向跟踪步骤:
    1. 将显示缓存区看作由空间中像素组成的矩形阵列,眼睛透过这些像素看到场景中的物体
    2. 对于每个像素计算其色彩值:
      1. 计算由视点连接像素中心的光线延长后所碰到的第一个物体的交点
      2. 使用局部光照模型计算交点处颜色值
      3. 沿交点处的反射和折射方向对光线进行跟踪
  • 光线跟踪算法步骤:
    1. 对像素执行以下操作:
      1. 从视点出发,通过该像素中心,向场景发出光线 \(R\),并求该光线与场景中物体的全部交点,来获得距离视点最近的交点 \(P\),依据局部光照模型计算该点的颜色值 \(I_c\)
      2. \(P\) 处沿着 \(R\) 镜面反射方向和透射方向各衍生出一条光线
      3. 分别对衍生出的光线递归执行上述操作步骤,分别计算亮度贡献 \(I_s\)\(I_t\)
      4. 依据 Whitted 光照模型计算 \(P\) 处光亮度,并将结果赋给该像素
    2. 重复上述操作直至所有屏幕上的像素被处理完成
posted @ 2025-07-05 01:46  SRIGT  阅读(58)  评论(0)    收藏  举报