[CG] TinyRenderer 学习记录(3):Z-Buffer 与 Shader
TL;DR
- 移除了 fRange 函数。
- 实现了 Z-Buffer 算法——可以正确处理遮挡关系了!
- 引入了可编程 Shader(目前仅支持顶点着色器和片段着色器)。
- 引入了透视除法、NDC 和视口变换 (这些都是顶点着色器连带的东西,所以顺便实现了)
- 把 Model 封装成类,将模型的加载和渲染解耦。
代码就不放在本文里面了,可以参考我的 pyTinyRenderer 。虽然我当初的计划是把这个学习记录做成类似教程的东西,但又想到网上类似的文章很多,而且写得很好,遂作罢。
还有一件事。如果你看过原作者 ssloy 的 tinyrenderer 教程,可能会注意到我的学习记录和他的教程不是完全对应的。这是因为他的教程面向的对象是零基础,在初期为了实现某些本来只有后期才能实现的效果时,做了一些妥协,导致代码看上去不是很清晰,有点 “堆积” 的感觉,然后等学到后面之后又要把前面这些多余的代码删掉或是封装起来。我因为之前学过,所以就不拐弯抹角了,直接按照 pipeline 写,遇到不太清楚的地方再参考教程。
接下来主要讲讲实现过程中遇到的两个问题。
线性变换与非线性变换
本节含有误导性内容,已废弃。原因见文末。
首先是线性变换和非线性变换的顺序问题。结论是应当先做线性变换,再做非线性变换,这个没有异议,关键是原因。我记得去年暑假初学图形学的时候还推导过,但现在已经忘得一干二净了……
这个问题源于视口变换。视口变换将 NDC 空间的坐标变换到屏幕空间,也就是:
为此需要计算视口变换矩阵
习惯性地,我写出:
如果按照 “先做线性变换,再做非线性变换” 的规则得到的就是上述矩阵,写法也很简单,左上角的 3x3 矩阵是线性变换矩阵,最右边的一列是平移向量,两者互不干扰。
但我又想,如果把顺序反过来,矩阵会是什么样子的呢?于是我在纸上写出如下内容:
结果居然没有变化!我开始怀疑自己的记忆是否出了问题……
画了图之后才发现是特殊情况。
一般来说,调换顺序前后得到的两个矩阵是不相等的,比如先做平移(非线性变换)将物体移动至
但是,本次变换的目标十分特殊——
我画了一个示意图:
原始物体为 1,变换后物体为 2,执行的都是 2 倍的缩放变换,但是下面的物体在变换后发生了移动,原因前面已经解释过了。
保留小数是画蛇添足
然后就是小数的问题。顶点数据一般都是带有小数部分的,但实际的屏幕 / 图像由一个个像素组成,使用整数来索引。本着尽可能不损失信息的原则,我将取整操作放到 “写像素” 这一步进行。
举个例子,在利用重心坐标对三角形进行光栅化的函数中,第一步是计算包围盒,第二步是遍历包围盒判断点是否在三角形内,如果是则绘制。这两步涉及的坐标,我用的都是浮点数,直到最后的 setPixel 时才取整。本以为这样会更加精确,但结果反而如下图所示
出现了很多细细的白线,专业一点叫 artifact。
如果在第一步计算包围盒时取整,结果就是正确的:
原因我暂时不太清楚,但可以确定的是,保留小数是画蛇添足的行为,所以我把相关的代码全都改过了,并且删掉了 fRange
函数。
最终结果
写完上面这些内容后,打了两个小时的鬼泣 5,见到了名场面)
睡前打开工程,例行回顾了一下今天写的代码,发现 Z-Buffer 的插值写错了……
将错误更正后得到的结果如下:
有点恐怖谷效应——不过作者的教程里面有更瘆人的,感兴趣的话可以看看。
废弃 “线性变换与非线性变换” 一节的原因
今天(24 年 3 月 21 日)推导投影矩阵的时候发现一味遵从 “先线性变换再非线性变换” 的规则反而会搞复杂……可能是因为太久没看图形学,臆造出来了这样的规则,看来复习一下还是很有必要的。
问题是这样的:因为透视投影矩阵有一部分来自于正射投影矩阵,所以我从正射投影矩阵开始推导。目标很简单,就是把一个由 left, right, top, bottom, near, far 六个变量定义的长方体盒变换为
嗯,我想之所以会有 “先线性变换再非线性变换” 的规则,主要是因为这样的变换矩阵可以直接写出来,不需要额外的矩阵乘法,但这一规则如前面所说容易出错。
总之,具体问题具体分析。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)