【WebGPU实时光追美少女】概览介绍
世界Skill
本系列文章将会论述如何用WebGPU来实现一个实时路径追踪渲染器,从一个简单渲染器为开端层层深入,了解经典路径追踪渲染器的各个部分,以及BRDF模型在路径追踪中的实现。
Github仓库在这里:dtysky/webgpu-renderer,Demo在:Demo,注意目前需要最新的Chrome Canary版本才能打开。
这个项目是我三个月前一边学习闫神的GAMES202一边搞的,当时搞了大半的进度后迫于搞给自己庆生的游戏Double;14所以暂时搁置,游戏搞完了肝也废了缓了一阵子又出了一些头疼现实问题,最近都解决了才重新捡起来。
大纲
下面这些是这系列教程的一个大纲,都是通过GAMES101和202相关章节、阅读资料以及自己的理解做出来的,由于个人水平有限,所以难免有错漏之处,欢迎指出。同时迫于毕业时许诺的“三十岁之前一定要出一个商业品质的独立游戏,而现在只有两年时间了”以及做好可能RUN的准备带来的焦虑,所以这系列文章主要目的是基于现有的进度尽快收尾而非达到最优化,所以下面章节有的部分可能并不会完美实现,这些部分我会特别注明。
这个系列的文章预计如下:
- 概览介绍:本章节,将会对整个项目涉及的知识做一个综述。
- WebGPU基础与简单渲染器:通过自己实现的一个简单渲染器来论述WebGPU的能力。
- 路径追踪-场景数据组织:针对路径追踪,如何组织场景数据,涉及到PBR材质、glTF、场景合并等。
- 路径追踪-管线组织与GBuffer:针对路径追踪,如何组织渲染管线,同时论述GBuffer的生成。
- 路径追踪-BVH构建与求交:如何构建BVH,以及如何在CS中求交。
- 路径追踪-随机采样与BRDF:论述如何在路径追踪中运用蒙特卡洛采样实现直接光照和间接光照,以及运用BRDF光照模型。
- 路径追踪-降噪与色调映射:如何对充满噪点的图像进行空间和时间的滤波,最后输出如何进行色调映射。
- 路径追踪-毛玻璃材质与BSDF:如何运用BSDF(BRDF+BTDF)模型实现毛玻璃材质。
- 踩坑与调试心得:对于WebGPU这样一个实验性的API(至少当时),我是如何进行调试的血泪史(主要是CS部分)。
- 性能优化:包括BVH并行构建、WebGPU管线优化等。
在这其中,章节7的降噪部分,目前大概率只会涉及到静态场景的简单滤波,而不会有Motion Vector、SVGF之类的进阶实现;章节8的BSDF至今仍未实现,并且不一定会实现,但关于透射整个框架已经搭好,会尽量做完吧;章节10的性能优化大概率不做了,如果梦想推进顺利可能会在未来某一天忽然补完。
(以上其实就是风险声明,烂尾别找我(逃
概览介绍
本项目主要分为两部分,第一是WebGPU部分,第二是路径追踪部分。
WebGPU
实时渲染在工业领域的应用离不开各个图形API,主流的API主要被各个系统厂商和标准委员会(实际上背后也是厂商)所支持,比如过去的OpenGL,OpenGL是一个跨平台的图形API,其迭代了漫长的岁月并在这些岁月中占据了这个领域大部分份额。在十年前,Web作为一个通用的平台也支持了图形接口,其名为WebGL,是OpenGL ES2在Web上的一个实现,在当时为Web带来了3D的可能。
但这也是十年前的事情了,在今天,图形API也遵循了“分久必合、合久必分”的规律,分裂成了DX12、Metal和Vulkan,这些API都更加底层、给开发者提供了更深层的可控性(当然同时也带来了更高的开发难度),相比于OpenGL,可谓是“自动挡”和“手动挡”的区别。而反观Web平台,这十年来却似乎毫无长进,在OpenGL迭代了如此多的版本后仍然停留在ES2的时代,只能打些扩展补丁缝缝补补,这当然很大一部分苹果不支持WebGL2的锅(虽然宣布将支持,但太晚了)。但苹果虽然在支持WebGL2上摸鱼,却也同时推进了更激进的下一代Web图形接口方案——WebGPU。关于WebGPU标准这几年的不断延期、标准的不断变更、API直到近两个月还在改、Shader变了一次又一次的槽就不吐了,总之,作为Web开发者的我们终于也有对标DX、Metal、Vulkan的图形API了,而事实上其API设计确实是借鉴了它们,并且用起来也足够简单。
值得欣慰的是,谷歌宣布Chrome 94的正式版将会正式支持WebGPU。
WebGPU标准目前的状态基本已经稳定,可见WebGPU标准。同时其使用的着色器也已确定,名为wgsl,详见WebGPU Shading Language。
在此项目中,我使用WebGPU实现了一个渲染器,其拥有UniformBlock
、Effect
、Material
、Geometry
、Texture
、RenderTexture
等资源的抽象,也有Scene
、Node
、Camera
、Light
的场景管理,还有Mesh
、ImageMesh
、ComputeUnit
这样负责渲染和计算的单元,基本可以说是麻雀虽小五脏俱全。
除此之外,项目也支持由我之前写的seinjs-unity-toolkit导出的PBR材质的glTF文件,来作为内置的路径追踪渲染器的资源。
路径追踪
光线追踪是不同于光栅化的另一种渲染思路,或者说才是最符合直觉的思路。但由于其性能开销较高,所以很少在实时领域使用,基本都用于离线渲染。但在硬件性能日益变强的今天,实时光线追踪已然成为可能。光线追踪有很多种实现方式,最适合做实时的便是路径追踪:
如图,其本质上是从人眼(或者说相机)发射射线,和场景中的物体求交,然后利用“光沿直线传播”的原理反向追踪计算光路,然后再计算直接或间接光照,实际上现在的光栅化流程可以看做是路径追踪中的第一步。路径追踪主要优点是可以实时计算出间接光照,即便是由于性能问题目前往往只能做到一次间接光照计算,但效果也已经很不错了。
但注意,路径追踪并非是万能的,其假设的“光沿直线传播”在遇到透镜时可能会失效。
所以,路径追踪的第一步就是要将整个场景的数据组织起来。我们现在往往将模型视为三角面的集合,并且用“材质”来描写模型的渲染方式。这在光栅化的流程中很自然,但对于路径追踪,由于光线的求交是针对整个场景的,所以必然涉及到整个场景模型的合并,也涉及到如何将我们熟悉的“模型-材质”模式转换成路径追踪适用的模式,这也就涉及到场景的合并,以及合并中材质、贴图等资源的管理。
有了合并过的场景,我们还要有一个方法把整个渲染流程管理起来,路径追踪和传统的光栅化流程不太一样,其前面部分和传统的延迟管线有点类似,但后面却大相径庭,所以如何合理得组织渲染流程也是个问题。
接下来便是光线和三角面如何求交的问题,诚然我们可以直接暴力求交,这对于小场景也不是不可以,但场景稍微大一点便是巨量的性能开销,这就要求我们去寻找更快的求教方法,也就引出一个问题——如何划分场景的层次来加速求交。这里我使用的是现在最常见的BVH,所以这一步就是论述如何构建BVH以及如何在CS中对BVH求交。
取得了光线和物体表面的交点,接下来要解决的便是光照计算。这里做的是真实渲染,走的是PBR流程(这么说可能有点不严谨),而如果要做相对物理正确的渲染,就会涉及到目前大家都在用的BRDF模型。在BRDF的描述中,一个着色点的最终结果是由其法线半球内各个方向的光线的贡献总和,而我们一次只能发射一条射线,并且每次间接光反射也只能反射或透射出一条,这就引出了“蒙特卡洛采样”,也引出了直接光照、间接漫反射、间接高光反射、能量衰减、重要性采样等等。
解决了采样问题,随之而来的是噪声和性能问题,首先是性能问题,诚然我们可以在同一帧发射大量射线来直接收敛出最终结果,但这往往意味着极高的开销,但如果不这样做,就又会导致极大的噪声。而这就引出了非常经典的“时间换空间”思想——将一帧多次拆成一次多帧,然后再来解决降噪。降噪首先要考虑时域的滤波,即“Temporal Filter”,使用一定的权重将当前帧和前一帧加权混合,不断加重上一帧的权重来使得结果最终收敛。以时间滤波为基准,还可以加入空间滤波进行辅助,本项目用到了联合双边滤波。对于静态场景这基本已经足够,但对于动态场景还需要做的更多,比如引入“Motion Vector”之类的,也会面临更多问题。除此之外,由于整个场景是HDR的,还需要进行色调映射防止过曝。
如果只考虑非透明物体,功能方面到此基本可以说结束了,若要考虑毛玻璃这种材质,必须要引入BSDF模型,同时要考虑BTDF和BRDF。除了光照模型之外,透射也会影响到求交的计算,以及终止条件的判定。
然后就是对于WebGPU这么一个比较新的图形API如何调试的问题,尤其是如何调试CS,经过血泪尝试我构建了一套使用Storage Buffer来调试的方法。。。哎。。。
最后是优化部分,其实项目中还是有很多地方可以优化的,首当其冲的就是BVH的构建和求交部分,可以使用莫顿码进行GPU加速。其次WebGPU部分也可以做一些优化,比如Binding Group部分。其他好像。。。想不起来了。。。
总结
我好菜啊感觉还是有很多地方没有理解深刻很容易忘尽力了,但是为了美少女也值得了(虽然发现最后性能好像并搞不定美少女...),但是开坑了就得含泪填完这是我作为码农一面的底线,希望大家多多指正。