UnityShader学习笔记[二百七十二]用近似穹顶透视的方式实现天空盒极光

UnityShader学习笔记[二百七十二]用近似穹顶透视的方式实现天空盒极光

转载自 用近似穹顶透视的方式实现极光

疑惑的地方加了理解 用简单的uv偏移多次采样的方式,制作有厚度和自然动态的极光效果。

制作极光的方式很多,想做真实做好看有两个重要的点,1是极光的动态,2是极光的厚度体积感。

先上个动图演示:

制作思路

这里是相当于是在天空盒的shader里面绘制极光,即shader的环境都是所处的天空盒。有世界坐标系,采样CubeMap,还可以使用屏幕uv等。

如果只是在地表上看极光(不用飞到极光里去),是有简单的方式模拟出极光厚度的。我一开始想到的是用视差贴图,我之前做的动态天空球是一个半球体,并且把各种天体云层都画在一个pass里,所以如果用视差贴图做,就会沿着球体的法线向外发散。而真实的极光厚度应该是垂直地表的。

所以我想到个简单的方式,就是在屏幕坐标上假定一个天顶的轴点(0.5, 4),这是一个屏幕的uv。 极光的贴图直接以这个轴点偏移多次绘制,可以模拟出垂直地表的厚度。但这个方式是有缺点的,如果camera可以一直仰望90°以上的话就会穿帮。所幸大部分游戏camera都会锁到90°仰望角,所以用这个trick做法是ok的。

正常的屏幕uv是0到1.而0.5,4是屏幕中心向上很上的一个位置了。天空盒往这个方向绘制多次 是往屏幕上方内部收拢。这和以前绘制的冰块做法有些类似。

左图视角控制在0-90度就没问题,能感受到近似垂直于地面的厚度;右图如果仰角大于90度,看上去厚度就不垂直于地面了。

因为对于相机仰角大于90度的时候,应该是0.5,-4的一个方向即屏幕下方才算是天空往上的一个方向。所以有需求的话可以根据实际更改。

具体实现方式

先定义2个RT,用来之后做厚度来回Blit。可以降采样,我用的1/4分辨率。

第一个pass绘制基础的极光曲线。我直接用sin,cos函数根据世界坐标计算出3根极光曲线,并且带一些随机厚度变化,为了之后做出极光垂直一缕一缕的效果。

形状可以通过大的sin和小sin的结合的方式,通过世界坐标系的x轴输入,得到z轴方向上的变化。如果是单纯的一个sin则三角函数的走向太过明显。所以要两个sin函数结合,一个sin函数控制较大的起伏,一个sin函数控制较小的起伏。

大的sin一般是输入值x坐标乘以了较小的数值,在相同x范围内sin的输入跨度较小,所以sin输出起伏频率变化不快。而大的sin输出以后一般会乘以较大的值,起到一种大起大落的效果

小的sin一般是输入值x坐标乘以了较大的数值,在相同x范围内sin的输入跨度较da,所以sin输出起伏频率变化较快。而小的sin输出以后一般会乘以较小的值,起到一种小幅度的变化频率较频繁的效果。

两者相加可以得到这种效果。相加可以表示在大起落的函数基础上,叠加小起落。

一条线条内的实际上是执行了两个表达式几乎相同的函数,这两个函数只有上下两个z轴方向上的位移。在这两个函数之间的片源,就属于线条了。

另外线条的粗细可以使用uv采样噪声图的方式来实现。在这两个函数之间的片源,采样噪声图,用噪声图的灰度值相乘来表达自身的极光强弱。

这是R通道的做法 这个pass的R通道是极光曲线,G通道输出天空与玩家的距离值,为了以后做极光的fade out和厚度变化。所以可见,G通道是越远透明度越大。

第二个pass绘制极光厚度的渐变。做法就是以虚拟天顶的屏幕UV坐标(0.5,4)为轴心,偏移采样16次(这里的次数可以根据厚度需要缩减),绘制出极光厚度和颜色渐变。

这里在第一次计算了极光的图以后,将其blit到指定的图上,然后输入到偏移的shader里面。进行偏移以及和偏移前的图进行叠加。

是不是有点像小时候玩的塑料弹簧玩具?

这里也用到了之前第一个pass的Y通道的距离,用来控制远处的极光厚度变窄,强度变弱,做出大纵深的视觉冲击感。

这里主要是偏移的时候,采样了绿色通道的值,1-以后 与固定偏移值相乘以后,得到了远处的偏移较小,近处偏移较大的接近自然的效果。

为后面模糊处理的时候,近处较厚远处较薄的表现做好计算。

第三第四个pass就是做2次轴向模糊,一个pass做8次采样,2个pass足够画出平滑的厚度了。

波形写的比较简陋,3条波会交错穿插。

效果优化

代码算出来的3根极光曲线感觉不是很自然,之后我又试了一下直接采贴图的方式。用perlin噪点让平行线扭曲,这样可以画出自然的极光线条。(RG通道2种输密线用来模拟强度变化)

直接用xz坐标采样,在两张图之间以及纯黑之间lerp。则表现上是xz平面上的直线的显隐。

所以要做一些对两张图进行一些扭曲。扭曲用到了第三张图。xz平面采样第三张图的值作为自身x方向上的叠加值以及z方向上的叠加值。

原本的xz值与这个叠加值相加以后,用来采样线条图。 这样扭曲的uv采样到的是扭曲的线条。然后第三张图通过时间乘以速度控制采样的偏移offset,分两个不同的方向和速度运动。

两次运动的值用来采样线条图。得到的就是随时间扭曲的线条图了。

但是只是扭曲,显隐程度上依然是整体的变化,实际上每个区域有自己的微小显隐变化。这种微小变化,也是可以通过噪声图来得到,噪声图第三次通过时间乘以速度控制采样的偏移offset,可以不同的方向和速度运动。 xz坐标采样这个图的灰度值来控制区域内的显隐变化。

扭曲会有些波形粘连的状态,不像代码写的波形那么规整,各有各的优缺点吧,都是靠时间和经验慢慢磨。

然后加上了控制强度的参数

总结

这个做法用了2个1/4分辨率的RT,4个Pass,其中渐变和模糊pass用的采样数比较高,但这些多次采样是用在1/4分辨率RT上的,总体开销还能接受吧。

总之极光也就是个添彩的效果,如果性能还有富余的话可以尝试加加看。

相关推荐

Apple Store
数字365吉凶

Apple Store

📅 07-28 👁️ 400
爱奇艺小芽贷放款审核中,多久能到账?真的稳吗?
iphone6s颜色 快和小编一起来看看四款iPhone 6s的颜色对比_世界聚看点