Rainforest (a shadertoy demo) 小注

点击左上角的标题(Rainforest)可以跳转到 shadertoy 上的页面(可以看到代码)w

整个demo由screen quad上的fragment shader实现,也是shadertoy的存在意义。
作者是 Íñigo Quílez (不会念,ta的blog中说也可以写成 Inigo Quilez),shadertoy的创始人,id叫做iq,绝对的神仙。(逃

嗯,打算试着梳理一下这个demo的实现原理之类的(不自量力),大概也就是做个笔记x
好,是新的坑。
我的数学实在是太烂了所以还不敢写ML的东西尽管有那个分类

1. shadertoy & Ray marching

shadertoy 是一个基于WebGL的,大家写并分享shader的地方。但不同于一般意义上的shader,shadertoy中几乎只有fragment (pixel) shader,因此你不能用通常的顶点和三角形组成网格并定义一个场景,进行绘制。

场景中一般只有一个screen quad(一个填满整个屏幕(clip space)的四边形)和运行于其上的fragment shader。也就是说,你只能定义一种函数:从屏幕空间的一个二维向量到一个颜色值的映射(接收一组坐标(x,y)并根据坐标值产生颜色)。这个颜色将会被绘制在屏幕上,得到最终的绘制结果。此外,shadertoy还提供至多4个额外缓冲区(你可以先在缓冲区中绘制,再从缓冲区采样并得到最终渲染结果)、各种变量(键盘、鼠标事件,当前时间等),一些预先定义好的贴图(2D, 3D和cubemap;包括噪声和一些常见的纹理)甚至音频文件。

注意到屏幕空间中一组坐标(x,y),当前相机(视点)位置,视角(与相机焦距有关,一般为60~90度,广角镜头的视角较大)和宽高比唯一定义了一条由当前视点出发指向某方向的射线,shadertoy中的场景便可以使用基于射线(比如光线追踪,Ray tracing)的方法构建出来。 在代码中定义好场景,每个像素对应一或多条射线,求得射线与场景的交点并计算对应的颜色值即为最后的输出。

“ray tracing”的图片搜索结果
一般意义上的 Ray tracing(光线追踪),wikipedia

在shadertoy中,一般使用\mathbb{R}^3下的 Signed distance field (SDFs) 来定义场景。SDF是一个标量场,一个定义在空间中的函数,其值为点(x,y,z)到最近表面的距离。当点在表面(比如一个球面)内部时,其值取负值,得名Signed distance field(带符号的距离场x)。满足 SDF(x)=0 的点集构成了一个等值面(isosurface),便是我们想要定义的场景。

我们从射线的起始点出发,让射线不断地沿着其朝向前进,并使用SDF的值作为步长。当SDF值足够小时,我们判断射线与表面相交。与Ray tracing不同的是,我们不再求射线与面的解析(准确的)交点,而是通过计算一个当前点与表面距离的函数(SDF),当其值接近0时判断相交,这种方法便称为Ray marching (来自这里的定义)。此外,似乎用于体渲染(Voxel rendering)的那种方法(不知道该叫什么,大概是射线每次前进一定步长并在每一步累积颜色)也叫Ray marching(?)。

Sphere tracing has a adaptive step size
用SDF函数值作为步长的Ray marching示意图。来源

多个SDF之间也可以很方便的合并。如,f_{new}(x) = min(f_1(x), f_2(x))会让我们得到f_1f_2的并集。关于Ray marching,在网上也有很多写得很好的教程,这里就不多说了(我好啰嗦x)。比如:
https://www.alanzucconi.com/2016/07/01/volumetric-rendering/
http://forum.china.unity3d.com/thread-21000-1-1.html (上面的中文版)

2. Rainforest中的地形

(从本节开始是rainforest的内容,不会再过多的涉及基本概念和知识之类的x)

发表评论

电子邮件地址不会被公开。