欢迎光临
我们一直在努力

【Unity Shader】究竟什么是光栅化(Rasterization)

本文以工程视角梳理光栅化的核心概念与实现要点:光栅化可以统一理解为对二维指示函数的采样。在此基础上,分别说明像素中心采样、点在三角形内判定(边函数/叉积同侧)、边界像素归属规则(Top-Left Rule)以及常见的性能优化手段(Bounding Box 与增量计算)。


1. 核心概念:光栅化在做什么

光栅化的本质是:把连续的几何图形(通常是三角形)转换为离散像素表示。

从计算角度可以统一为:

  • 定义一个二维指示函数(Indicator Function)
  • 对该函数在像素采样点上进行采样
  • 将采样结果写入帧缓冲(颜色、深度等)

直观表述:

光栅化 = 对二维指示函数进行采样


在这里插入图片描述

2. 指示函数(Indicator Function)

在二维屏幕空间中,定义:

inside(tri, x, y)

含义:

  • 点 ((x, y)) 在三角形内 → 返回 1
  • 点 ((x, y)) 在三角形外 → 返回 0

数学表达:
f(x,y)={1,(x,y)∈triangle0,otherwise
f(x, y)=
\\begin{cases}
1, & (x,y)\\in triangle \\\\
0, & \\text{otherwise}
\\end{cases}
f(x,y)={1,0,(x,y)triangleotherwise

在渲染实现里,这个 0/1 结果会决定“该像素是否被该三角形覆盖(covered)”。

在这里插入图片描述


3. 光栅化基本流程(最小版本)

最直接的实现是遍历像素并判断覆盖关系:

for (int x = 0; x < xmax; ++x)
for (int y = 0; y < ymax; ++y)
image[x][y] = inside(tri, x + 0.5, y + 0.5);

关键点:

  • 遍历像素网格(离散)
  • 对每个像素使用采样点(通常是像素中心)
  • 根据 inside 结果写入像素(覆盖)

4. 为什么使用 (x + 0.5, y + 0.5):像素中心采样

像素在几何意义上是一个区域(小方块),而不是数学意义上的点。常见约定:

  • ((x, y)):像素左下角
  • ((x+0.5, y+0.5)):像素中心(采样点)

GPU 默认的规则通常采用中心采样(Center Sampling)。工程上这样做的好处是:

  • 采样位置明确、可复现
  • 与后续抗锯齿(如 MSAA 的多采样点)逻辑一致

5. 点在三角形内的判定:边函数(Edge Function)/叉积同侧

光栅化最核心的几何判断是:一个采样点是否被三角形覆盖。常用方法是“对三条边做同侧测试”。

三角形顶点:
P0,P1,P2
P_0, P_1, P_2
P0,P1,P2

对每条边定义边向量,并对点 (P) 计算叉积符号(二维里可以视为 z 分量):

C0=(P1−P0)×(P−P0)
C_0 = (P_1-P_0)\\times(P-P_0)
C0=(P1P0)×(PP0)

C1=(P2−P1)×(P−P1)
C_1 = (P_2-P_1)\\times(P-P_1)
C1=(P2P1)×(PP1)

C2=(P0−P2)×(P−P2)
C_2 = (P_0-P_2)\\times(P-P_2)
C2=(P0P2)×(PP2)

判定规则:

  • 若 (C_0, C_1, C_2) 全部同号 → 点在三角形内部(或边上,取决于边界规则)
  • 否则 → 点在三角形外部

几何意义:

点必须位于三条边的同一侧。

工程实现中常将这一类判定写成“边函数(edge function)”,以便做增量更新优化。


6. 边界问题(Edge Cases)与 Top-Left Rule

问题:如果采样点刚好落在三角形边上,属于哪个三角形?
在网格化渲染中,两个相邻三角形共享边,若规则不一致会导致:

  • 重叠:两个三角形都认为该像素属于自己
  • 裂缝:两个三角形都不认为该像素属于自己

常见工业做法:Top-Left Rule:

  • 上边、左边:判为“内侧”(包含)
  • 下边、右边:判为“外侧”(不包含)

目标:

  • 让每个像素只归属一个三角形
  • 避免裂缝与重叠

7. 性能问题与优化路径

7.1 暴力遍历的问题

若对整个屏幕做 inside 测试,会产生大量无效计算,因为三角形通常只覆盖局部区域。

7.2 Bounding Box(包围盒)优化

在这里插入图片描述

先计算三角形在屏幕空间的最小包围矩形:
minX,maxX,minY,maxY
minX, maxX, minY, maxY
minX,maxX,minY,maxY

只遍历该区域:

for x in [minX, maxX]
for y in [minY, maxY]
inside(...)

收益:大幅减少无效像素测试,是最基础且高收益的优化。

7.3 增量计算(Incremental Computation)

边函数在屏幕空间是线性函数,相邻像素的结果只差一个常量偏移,因此可以递推:

  • ((x,y)\\rightarrow(x+1,y)) 可通过“上一个值 + 常量”得到
  • 避免每个像素重新计算叉积/边函数

收益:减少重复计算,属于硬件光栅化的常见优化思路。


8. 完整光栅化流程(概念版)

  • 输入三角形顶点(已完成投影与视口变换,处于屏幕空间)
  • 计算 Bounding Box,限定遍历范围
  • 遍历像素中心采样点 ((x+0.5, y+0.5))
  • 使用边函数/同侧测试进行 inside 判定
  • 覆盖像素并进入后续阶段(插值、深度测试、着色、写入)
  • 可选:边函数增量更新进一步优化

  • 9. 统一认知模型

    光栅化可以统一理解为:
    几何→函数→采样→离散图像
    \\text{几何}\\rightarrow \\text{函数}\\rightarrow \\text{采样}\\rightarrow \\text{离散图像}
    几何函数采样离散图像

    GPU 的工作可以抽象为:

    for each pixel:
    if inside(triangle):
    shade() // 进入插值/深度测试/片元着色等


    10. 后续知识点(建议的衔接顺序)

    光栅化只是开始,通常下一步会接:

    • 重心坐标(Barycentric Coordinates)与属性插值(颜色/UV/法线)
    • 深度测试(Z-buffer)
    • 抗锯齿(MSAA/SSAA 与采样点)
    • 纹理采样与过滤(Bilinear/Trilinear/MipMap)

    总结一句话

    光栅化 = 判断像素是否被三角形覆盖(inside)+ 在离散网格上对覆盖结果采样与填充,并在工程上通过边界规则与遍历/递推优化保证正确性与性能。

    赞(0)
    未经允许不得转载:171主机测评 » 【Unity Shader】究竟什么是光栅化(Rasterization)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址