大概是从去年8月份,我开始一边自学图形学一边开发软渲染器foolrenderer。除了模型加载用了开源代码以外,其他所有功能都是自己开发的。目前实现了基本的光栅化渲染,还添加了可编程渲染流水线、基于物理的材质等功能。
软渲染器(Software Renderer)是一类完全依靠软件驱动,不使用图形硬件加速的渲染器的统称。原本集成在显卡里的功能需要全部由开发者自己实现,软渲染的速度也远远比不上利用了硬件加速的渲染器。虽然软渲染器缺点很多,但也有一些实际应用场景:例如软渲染器有很好的兼容性,一些系统上的图形编程接口有软渲染层作为硬件不兼容时的后备渲染方案;可以用软渲染器实现一些显卡不支持的功能,早期的光线追踪就是纯软件实现的。
虽然我之前一直在开发游戏,但主要集中在玩法制作上,图形方面的知识其实了解的不多,这就导致我在制作游戏的时候遇到不少问题。比如,色彩贴图一般要用sRGB空间,为啥金属度、法线这类贴图不用;PBR材质里常说的分布函数是个啥,什么是GGX。诸如此类,看了网上的解释还是云里雾里。还有个问题是不会写着色器,很多视觉效果需要自定义的着色器实现,但我一直不熟悉渲染流水线,对着教程也写不出来。
所以我慢慢觉得有必要了解一些计算机图形的概念,于是乎开始找相关资料学习。经过了解之后发现,图形学的基础原理并没有想象中那么复杂,用学到的知识完全可以自己写一个软渲染器。我觉得边学边做个小软件挺有意思的,连带这样学稍微更有动力一点,所以就决定开发一个基于光栅化算法的软渲染器,也就是现在的foolrenderer项目。
因为是边学边做,所以foolrenderer的开发是按照自学进度走的,我学到哪里就给程序添加相应的功能。
首先就是为foolrenderer实现三角形光栅化功能,用人话说就是把三角形绘制到屏幕上。原理很简单:检查屏幕上的每一个像素,如果像素刚好落在三角形里面,就给这个像素设置对应颜色。当然了,每画一个三角形都要检查屏幕上的所有像素显然没有必要,最简单的优化方法是只检查三角形所在的矩形范围内的像素。
有了三角形光栅化,我接着添加了插值功能。接触过三维软件的老哥都知道,模型是由一个个点构造的三角形组成(多边形可以分解成若干个三角形)。这些点就叫顶点,顶点除了包括这个点的位置信息外还可以存储颜色、UV坐标、法线等等其他数据。插值说的就是把三角形三个顶点的数据均匀的过渡到三角形表面上。举个例子,如果三角形顶点都是红色,插值会得到一个红色三角形;如果三角形顶点分别是红、绿、蓝,经过差值得到的三角形呈现渐变色,越接近绿色顶点的地方颜色也越接近绿色。
到这里就已经可以渲染一个简单的模型了,只需要读取模型文件里的数据,然后一个个的把三角形画出来就行——当然事情也没有这么简单,得到的结果还有很多问题:比如,程序没有考虑三角形的前后位置关系,模型背面的三角形可能挡住前面的三角,那就用深度缓冲记录每个像素的前后位置,不画靠后的面;渲染器肯定要有调整模型位置大小的功能,还要模拟人眼近大远小的透视观察效果。这就需要利用线性代数提供的数学工具修改顶点位置;还应该给foolrenderer开发一个可编程渲染流水线,这样才方便给模型添加贴图和光照效果。
一番折腾foolrenderer逐渐像模像样起来,能真正能称得上是个渲染器了。在这个基础上可以开始添加一些常见的实时渲染技术,像什么法线贴图、阴影、基于物理的渲染等等。当然难度也开始慢慢变高了。实际开发这些功能后才发现,我们经常在软件中使用的技术,其实远比看起来的要复杂。
foolrenderer算是完成了吗?emmm从功能上来说恐怕还有很长一段距离,目前这个软渲染器只能说还很基础,甚至一些技术已经在现有的生产力工具里淘汰了。
随便举个例子,光是纹理这项功能到目前还只能用“残疾”来形容,最基本的双线性差值和Mipmap都没有,所以能在渲染的动画里看到明显的走样。更别提其他一些常见优化手段,更高级的全局照明,都还没来得及加进去。
同样的,图像方面的学习也才刚刚开始,继续练级呗还能咋整啊?
评论区
共 6 条评论热门最新