数字孪生Shader图像艺术解析7 落日边云层间

167 阅读3分钟

这个系列主要是分析一些图像艺术的具体实现,随着学习的深入,世界会更加鲜活一些。往期文章可见

  1. 扫描雷达,告警,Dash 圆

  2. 2D光环

  3. 六边形半球发光护盾

  4. 直线 PolyLine

  5. 2D火焰

  6. 3D火焰

  7. [落日云彩] 本篇

这个视觉效果用 5M以下的 GIF会丢失很多,所以放个视频。

 mp.weixin.qq.com/s/kV0HCogci…

以上的画面通过 100 行的简易代码实现,这个代码只有一个输入就是屏幕的坐标,也就是每个像素点位置。通过这个程序可以算出该像素需要输出什么颜色。当然需要一些基础.... 初次被推荐的读者朋友,可以看看上一篇3D火焰的文章。 我将不会再这篇继续赘述 光线步进+调色+湍流的技巧了。

距离场累加获得两个平面

2505312502 通过一下代码,可以在屏幕上着色出上面的图像

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

2506024527

叠加三角波如云

2506020454

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

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) ;

就可以得到 2506033915

这个时候再 三角函数中增加时间,就可以得到变化的颜色

fragColor +=  ( cos(  + 0.5 * time   + samplePoint.x  - vec4(3,4,5,0) ) )* (2.0 / stepDistance) ;

2506034035

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

2506034155

再来点小技巧。再三角函数里面增加一个放大之后的距离。 这样会让颜色更加散开一些。

fragColor +=  ( cos(  signedDistance * 15.   + 0.5 * time   + samplePoint.x  - vec4(3,4,5,0) )  + 1.5)

2506035437

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;

最后就得到美妙的落日夕阳了 2506030004