转载自:
这个标题看起来有点奇怪,大部分人觉得shader的主要用途就是为游戏服务,可惜这最基本的概念却最容易被忽略。如果你经常访问这个blog,就知道我已经很久没有写任何关于shader的文章了。不是我不再对shader感兴趣,就像人人都爱写GUI程序一样,shader永远是游戏编程最让人兴奋的部分-----可以马上获得代码的直观视觉反馈,让人很有成就感。不过当我经历了一个产品的开发过程,并且开始研究引擎设计以后,有了些不同的看法:)。
当我刚开始学习3D程序,觉得shader很神奇(相信很多人也和我一样),看了大量关于shader的文章,写了很多”漂亮”的shader。可惜当正式开发一款产品时却发现原来写过的大部分shader都无法使用。Why? 在学习shader的过程中,大部分人写的程序都只能称为”demo”,我们使用了最前沿的图形学算法,几百行hlsl代码,只为实现一种特效。但对对一个完整的产品来说,需要同时在场景中实现大量不同材质/特效,并且让系统能尽可能在底端硬件上也能跑。结果demo里的Parallax Occlusion Mappiing需要简化为Parallax Mapping甚至normal mapping等等。因此,针对游戏开发的shader必须非常有实用性和可行性,必须对特定游戏/场景做大量优化,而这些都是我们在写demo时不会想到也无法预料的。
Rule No.1,当为游戏开发shader时,需要时时把可行性放在第一位,记住这个shader还必须和其他大量shader”共存”,不要让一个shader拖垮一个系统。
接下来rule No.2,低质量的shader比没有还要糟! 噢,这看起来和rule No. 1完全矛盾?非也,非也。继续前面的话题,当你为了满足系统需要,把某个shader简化到极限时,相应的问题也就出现了:图像质量会变的非常差,最糟的情况下,也许一个”特效”变为让玩家讨厌的特性。举个例子来说,自从Doom 3之后,动态阴影就成了游戏开发的大热门话题,几乎所有游戏都把它作为标准特性之一。但是任何实现过shadow mapping的人都知道,看似简单的阴影实际上是非常耗费系统资源的。于是,为了让游戏支持这样的特性,我们减小shadow map大小,简化采样算法,结果是虽然得到了动态阴影,效果却非常差:明显的锯齿,抖动和不正确的阴影。没人喜欢这样的阴影,明显的锯齿只会不停让玩家觉得讨厌。每次遇到这样的情况,我都会直接在设置里把阴影关闭。
于是有了rule No.3,把资源用在刀刃上。如果你发现无法在现有资源下很好的实现某种特效,那么完全删除这个特性也许是最好的选择,把节约的资源增加到其他已有特效上。Wow从04年11月发布到去年为止都没有动态阴影,不过这并不影响它成为世界上最流行的游戏。几乎没有玩家不停要求增加阴影,论坛中更多的是对新场景视觉效果的赞叹和对某个技能特效的讨论。在激烈的游戏中,没有人会去关心阴影是否正确,更能让玩家兴奋的是释放技能时华丽的特效和对方受伤出洒出的血液。与其把资源花费在阴影这种出力不讨好的特性上,我更愿意把技能特效做的华丽,花哨。
最后rule No.4,有个性的shader才是好shader。每次开发shader时,不要以crysis作为你的参考目标,即使你成功达到了crysis的水平,人们也只会说:噢,又一个类似crysis的游戏。你的shader应该让游戏画面看起来与众不同。如果玩家一看到画面,就知道是某某游戏,那么你的shader或者更进一步说,你的视觉效果设计就成功了。反观farcry 2和crysis,独立提取出一幅画面之后,你大概很难分清他们来自哪个游戏,因此,从某种这角度来说,后来者farcry 2是失败的。