这个系列主要是分析一些图像艺术的具体实现,随着学习的深入,世界会更加鲜活一些。往期文章可见
-
[落日云彩] 本篇
这个视觉效果用 5M以下的 GIF会丢失很多,所以放个视频。
以上的画面通过 100 行的简易代码实现,这个代码只有一个输入就是屏幕的坐标,也就是每个像素点位置。通过这个程序可以算出该像素需要输出什么颜色。当然需要一些基础.... 初次被推荐的读者朋友,可以看看上一篇3D火焰的文章。 我将不会再这篇继续赘述 光线步进+调色+湍流的技巧了。
距离场累加获得两个平面
通过一下代码,可以在屏幕上着色出上面的图像
for(float iteration=0.; iteration < 100.0; iteration++) { vec3 position = depth * rayDirection + rayOrigin; distance = 0.25 - abs(position.y); stepDistance = 0.0055 + abs(distance) / 4.0; depth += stepDistance; color += 3. / stepDistance;}
取rayOrigin = (0, 0, -5), rayTarget = (0, 0, 0) or (0, 1, 0) or (10, 1, 0) or (0, 5, 0). 可以得到每一步,步进长度,射线深度,颜色累加的曲线图。

2506024527
叠加三角波如云

2506020454
由上一节的两个平面变成上图,要做的事情。 就是在 y,z分量上做噪声一样的 fbm操作。 如下面代码
for(float octave = 5.0; octave <100.0; octave *= 2.0){ samplePoint.y += 0.6 * sin(samplePoint.z * octave * 1.0 ) / octave; samplePoint.z += 0.6 * sin(samplePoint.x * octave * 1.0 ) / octave;}
octave 的循环次数越多细节会越多。 当然这个画面有点单调,加上一点时间变由风起云涌的感觉。 当然也在补上一些 x分量的变化,让细节更加丰富。
for(float octave = 5.0; octave <100.0; octave *= 2.0){ samplePoint.x += 0.6 * sin(samplePoint.y * octave * 1.0 - .5 * time) / octave; samplePoint.y += 0.6 * sin(samplePoint.z * octave * 1.0 + 0.5*iTime) / octave; samplePoint.z += 0.6 * sin(samplePoint.x * octave * 1.0 + 0.5*iTime ) / octave;}

2506021346
着色
整个 shader最有魅力的地方,在于用简单的三角颜色 palette。做出了夕阳的感觉。 当然前面的参数我相信也是作者不断实验得到的。 看懂着色之前先了解一下 IQ大神发布的通过三角函数获取到色盘 iquilezles.org/articles/pa… 代码非常简单。
// cosine based palette, 4 vec3 paramsvec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ){ return a + b*cos( 6.28318*(c*t+d) );}
而我们只需要根据 对应点 x轴的值,做一个 cos函数,再随便配点颜色。
fragColor += ( cos( + samplePoint.x - vec4(3,4,5,0) ) )* (2.0 / stepDistance) ;
就可以得到 
这个时候再 三角函数中增加时间,就可以得到变化的颜色
fragColor += ( cos( + 0.5 * time + samplePoint.x - vec4(3,4,5,0) ) )* (2.0 / stepDistance) ;

2506034035
由于 cos将值的范围变成了[-1, 1]。 我们将其调整到正值。只需要再 cos外直接加一个 1.5
fragColor += ( cos( + 0.5 * time + samplePoint.x - vec4(3,4,5,0) ) + 1.5)* (2.0 / stepDistance) ;

2506034155
再来点小技巧。再三角函数里面增加一个放大之后的距离。 这样会让颜色更加散开一些。
fragColor += ( cos( signedDistance * 15. + 0.5 * time + samplePoint.x - vec4(3,4,5,0) ) + 1.5)

2506035437
最后也是最妙的一句话,增加个光感。超级无敌简单...
float lightIntensity = exp(signedDistance * 10.);float colorWeight = 1.0 / stepDistance;fragColor += ( cos( signedDistance * 15. + 0.5 * time + samplePoint.x - vec4(3,4,5,0) ) + 1.5) * lightIntensity * colorWeight;
最后就得到美妙的落日夕阳了 