学习:栅格化和纹理处理
下面我用“从数学到像素”的视角把 GPU 中栅格化Rasterization和纹理处理Texture Processing的核心原理讲清楚尽量避开纯硬件细节但保留关键思想。一、GPU 渲染的整体流程先建立全局观一个三角形最终变成屏幕上的像素大致经历顶点处理 → 图元装配 → 光栅化 → 片元处理 → 输出合并栅格化决定“哪些像素被三角形覆盖”纹理处理决定“这些像素长什么样颜色”二、栅格化Rasterization原理1️⃣ 栅格化在做什么一句话定义把连续的几何图形三角形转换为离散的屏幕像素片元 / fragments本质是一个“点-三角形包含性测试” 问题。2️⃣ 输入是什么顶点着色器输出后每个三角形有三个屏幕空间坐标(x1, y1, z1, w1) (x2, y2, z2, w2) (x3, y3, z3, w3)经过透视除法后得到(x/w, y/w, z/w)此时坐标是屏幕像素坐标。3️⃣ 核心思想扫描线 重心坐标✅ 方法一扫描线算法传统找到三角形覆盖的包围盒对每一行scanline计算与三角形边的交点填充交点之间的像素---------------- | | | | #### | ###### | | ######|####### | ----------------✅ 方法二重心坐标现代 GPU 主流对每一个像素点 P计算P α·A β·B γ·C其中α, β, γ 是重心坐标判断条件α ≥ 0 且 β ≥ 0 且 γ ≥ 0✅ 满足 → 像素在三角形内❌ 否则 → 丢弃优点天然支持插值颜色、法线、UV非常适合并行计算4️⃣ 属性插值非常关键一旦知道重心坐标就可以插值color α·cA β·cB γ·cC uv α·uvA β·uvB γ·uvC depth α·zA β·zB γ·zC这就是片元着色器的输入来源5️⃣ 早期深度测试Early Z现代 GPU 在栅格化阶段就做深度预测试被遮挡的片元直接丢弃✅ 节省大量片元着色计算三、纹理处理Texture Processing原理1️⃣ 纹理的本质纹理 一块连续的图像数据常见形式2D 纹理最普遍Cube Map3D 纹理体渲染2️⃣ 纹理坐标UV每个片元有(u, v) ∈ [0, 1]GPU 把它映射到纹理像素texelx u × (width - 1) y v × (height - 1)3️⃣ 纹理采样Texture Sampling✅ 最近邻采样Nearest取最近的 texel快锯齿明显✅ 双线性插值Bilinear取 2×2 的 texelP lerp( lerp(T00, T10, fx), lerp(T01, T11, fx), fy )✅ 平滑✅ 实时渲染主流✅ 三线性过滤Trilinear在mipmap 层之间再做一次插值lerp( bilinear(level n), bilinear(level n1), fz )✅ 消除远处闪烁4️⃣ Mipmap核心加速技术提前生成Level 0: 原图 Level 1: 1/2 Level 2: 1/4 ...GPU 根据屏幕像素密度自动选择层级✅ 减少缓存 miss✅ 防止摩尔纹5️⃣ 纹理缓存与局部性纹理访问特点空间局部性强顺序访问多GPU 使用纹理缓存Texture Cache2×2 像素 quad 同时采样用于导数计算6️⃣ 各向异性过滤Anisotropic Filtering当纹理以“倾斜角度”观察时普通 mipmap 会模糊各向异性过滤沿拉伸方向采样更多 texel✅ 画质显著提升四、栅格化 纹理处理的协同流程三角形 ↓ 光栅化生成片元 ↓ 插值 UV / 颜色 / 深度 ↓ 片元着色器 ↓ 纹理采样访存 ↓ 深度测试 ↓ 写入 Framebuffer五、为什么 GPU 特别适合这件事特性原因高度并行每个像素独立SIMD / Warp同时处理 2×2 像素专用纹理单元硬件插值 过滤深度/模板单元硬件 early-ZTile-Based移动 GPU 优化带宽六、一句话总结栅格化决定“画哪里”纹理处理决定“画成什么样”