原地址https://www.shadertoy.com/view/4dsGRn
这个"反向光线追踪"+体积光的代码简单清晰,加注释总共也就300+行。本人也是初学者,除了1行不是完全理解,其他都完全搞懂了。在此与分享。
其实最基本的光线追踪和体积光并不难。不过,首先了解一下本代码中的光线追踪和体积光的基本算法。
"反向光线追踪":把屏幕空间的每一个像素转化到三维空间,并沿着视线方向发射大量视线束,并计算视线束碰到的场景点上的颜色c,使得color+=c(使用Blinn-Phong光照模型),可多次重复此步骤(即多次反向光线追踪/视线束反弹),使得color+=c,最终得到该像素的光线追踪颜色(起点函数/主函数:mainImage)
体积光:同上的大量视线束起点开始,将每个起点做一次随机偏移,并以步长累次采样,相加得像素的体积光颜色。每次采样看是否与光源有遮挡,有遮挡的话此点采样值为0,否则为此点照度*inscattering,inscattering是一个比较小的值(<1)。所以这里的体积光算法是不太物理,比较经验,要调参数的算法。并且,对于近处的物体,由于视线束逐步采样会由于碰到其停止,所以只要是近处的像素都会因为采样次数不足而比较暗。所以这个体积光算法只能具体情况具体应用啦。
最终颜色=光线追踪颜色+0.5*体积光颜色;(0.5比较经验)
原地址渲染的画面会有噪点,是体积光算法导致的,关掉体积光即可“丝滑”。反向光线追踪是不会出现噪点的,而正向光线追踪(光子从光源发出,被屏幕捕捉)是会的。
原代码可以改成多次反向光线追踪/视线束反弹版本,你可以看到"多次"版本的球中球中球有反射效果,而原地址的版本仅做了2次反弹,球中球中球是没有反射效果的。
最后,完整版。本人注释,小改成多次反弹的代码:
// Ray tracing with improvised volumetric shadows
// Attempting to make it windows friendly by reducing loopiness.
// Thanks to iq for fixing the sphere intersection code, sqrt(-n) is bad :)
// Matthijs De Smedt
// @anji_nl
const float ZMAX = 99999.0;
const float EPSILON = 0.001;
const int MAX_BOUNCES = 20; // For looping version
const int VOLUMETRIC_SAMPLES = 10;
//交点
struct Intersection
{
vec3 p;
//与向量束起点的距离
float dist;
vec3 n;
vec3 diffuse;
vec3 specular;
};
//向量束,用作视线束和体积光里的射线检测
struct Ray
{
vec3 o;
vec3 dir;
};
struct Light
{
vec3 p;
vec3 color;