http://candycat1992.github.io/2016/06/25/diablo/
视频:GDC 2013
Diablo(暗黑破坏神),暴雪出品。演讲者是暴雪TA,额最后的QA环节听出来代码不是他写的(恩什么ps、vs他看起来也完全不知道,“I have no idea, haha”)……看来暴雪TA负责是的设计shader和特效,但代码还是另外由人来写的。
Simon在他的文章里详细分析了翅膀特效的实现,他当时没看到这个演讲所以很多靠猜很不容易……
“Blend Add” Shading

传统的additive(左边)太亮了,blend(中间)缺少bloom效果,所以他们选择右边这种。
他们所说的Blend Add实际就是把各个颜色或透明通道相乘以后又乘以了2进行加亮。
Blend One OneMinusSrcAlpha // Blend Add
Texture Multiplication Shader
下面的公式就是所有特效使用的基本公式,简单来说就是在普通的乘法后又乘以2。
下面他举了很多例子。先从最简单的开始。下面是两张非常简单的纹理,只考虑alpha通道,因此rgb现在都是白色。TEX1和TEX2是两张相同的纹理,但是按照不同的速率滚动,乘起来之后就可以得到右边的效果。看起来像云。
下面再添加一张纹理,TEX2现在是缩放成0.5,TEX3是放大成2.0,然后按不同速率滚动,得到更加复杂的类似云层飘逸的效果。
下面是再添加一张texture(其实只是第二张,前三张本质是一张纹理,只是uv不同),这张纹理定义了particle的基本区域,然后乘起来(注意这里没有乘以2,因为只是想作为mask)得到一个基本的particle渲染效果。
下面是把7个这样的particle叠在一起的效果,就很有圆状的动态效果了。
他指出很多特效都是靠这种方法,然后举了一些实际的例子。例如下面的幽灵毒药效果,TEX1不动,TEX2不断向上滚动,把17个这样的particle叠加起来就得到了右侧的效果。
再比如下面的火焰特效。
以及下面的冰冻拖尾特效。拖尾的动作还是依靠改变particle网格动画得到的,但每个particle的渲染是使用了这种方法。
下面这个特效也是仅靠两张texture来实现的。
下面这张图是上面那个特效的实现细节。TEX1是一个不动的纹理,TEX2不停滚动,然后整个特效再依靠12个particle的运动来实现。
同上,还有一些更复杂的例子。这个火焰只使用了23个particle。
上面的特效,这种方法来用于渲染一些伪体积渲染。例如下面的烟雾,只用了60个particle。
下面这张图是真正的网格。
下面的地火也是,只用了28个particle,和一些滚动的纹理。
这种方法大大节省了particle的数目,从而减少了overdraw,在作者看来这是一个huge win!oh yeah!这种方法的瓶颈其实是在memory上,而不是shader计算上。每个particle多用了大概两张texture,但减少了很多overdraw。
QA环节有一个人问,为什么要把alpha和rgb分开,和在一起可以吗?除了一些内容创建的原因,他更倾向于分开,因此这样每张texture都比较小,texture load的时间就比较快。