纳金网

标题: ShadowGun shader 解析(1) [打印本页]

作者: star-小虎    时间: 2013-10-11 17:23
标题: ShadowGun shader 解析(1)
去年的时候就从网上下了这个工程,虽然只有一个场景和一些shader,不过这些已经足够了。像这样公司能将自己项目的一部分放在网上供大家学习真是难能可贵的,对于untiy移动平台的开发人员更是重要的学习资料。
大家可能打开项目之后无从下手,虽然ShadowGun的效果更现在次时代游戏比起来还是有差距的,不过在当时的移动平台上可是赚足了眼球。其实的优化方法值得大家学习。本文希望有一定shader基础的人来阅读,我怕误人子弟,对别人的代码上理解上可能有些偏差。请大家提出宝贵意见,共同学习共同进步。
这个项目我在itouch4上测试过,平均30-40帧,最多3万个三角形。


大家看到上面这张图了么,这是shadowgun游戏里的第一个场景,我要更大家讲的就是,人物的材质,地面的材质,雕像的材质,体积光的材质等等这些。本文不是教程,不会由浅入深为大家讲解,所以会把一些有趣的shader先展示给大家,我认为对大家更有帮助。
1.红旗飘飘


我先来讲讲这个彩旗飘飘的效果,我们的美术想要这个效果,我就研究了一下。发觉很有意思。Shader里关键的代码在这里

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em]2

[backcolor=rgb(250, 250, 250) !important][size=1em]3

[size=1em]4

[backcolor=rgb(250, 250, 250) !important][size=1em]5

[size=1em]6

[backcolor=rgb(250, 250, 250) !important][size=1em]7

[size=1em]8

[backcolor=rgb(250, 250, 250) !important][size=1em]9

[size=1em]10

[backcolor=rgb(250, 250, 250) !important][size=1em]11

[size=1em]12

[backcolor=rgb(250, 250, 250) !important][size=1em]13

[size=1em]14

[backcolor=rgb(250, 250, 250) !important][size=1em]15

[size=1em]16

[backcolor=rgb(250, 250, 250) !important][size=1em]17

[size=1em]18

[backcolor=rgb(250, 250, 250) !important][size=1em]19

[size=1em]20

[backcolor=rgb(250, 250, 250) !important][size=1em]21

[size=1em]22

[backcolor=rgb(250, 250, 250) !important][size=1em]23

[size=1em]24

[backcolor=rgb(250, 250, 250) !important][size=1em]25

[size=1em]26

[backcolor=rgb(250, 250, 250) !important][size=1em]27

[size=1em]28

[backcolor=rgb(250, 250, 250) !important][size=1em]29

[size=1em]30

[backcolor=rgb(250, 250, 250) !important][size=1em]31

[size=1em]32

[backcolor=rgb(250, 250, 250) !important][size=1em]33

[size=1em]34

[backcolor=rgb(250, 250, 250) !important][size=1em]35

[size=1em]36

[backcolor=rgb(250, 250, 250) !important][size=1em]37

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]inline float4 AnimateVertex2(float4 pos, float3 normal, float4 animParams,float4 wind,float2 time)
[size=1em]{  
[backcolor=rgb(250, 250, 250) !important][size=1em]    // animParams stored in color
[size=1em]    // animParams.x = branch phase
[backcolor=rgb(250, 250, 250) !important][size=1em]    // animParams.y = edge flutter factor
[size=1em]    // animParams.z = primary factor
[backcolor=rgb(250, 250, 250) !important][size=1em]    // animParams.w = secondary factor
[size=1em]      
[backcolor=rgb(250, 250, 250) !important][size=1em]    float fDetailAmp = 0.1f;
[size=1em]    float fBranchAmp = 0.3f;
[backcolor=rgb(250, 250, 250) !important][size=1em]           
[size=1em]    // Phases (object, vertex, branch)
[backcolor=rgb(250, 250, 250) !important][size=1em]    float fObjPhase = dot(_Object2World[3].xyz, 1);
[size=1em]    float fBranchPhase = fObjPhase + animParams.x;
[backcolor=rgb(250, 250, 250) !important][size=1em]           
[size=1em]    float fVtxPhase = dot(pos.xyz, animParams.y + fBranchPhase);
[backcolor=rgb(250, 250, 250) !important][size=1em]           
[size=1em]    // x is used for edges; y is used for branches
[backcolor=rgb(250, 250, 250) !important][size=1em]    float2 vWavesIn = time  + float2(fVtxPhase, fBranchPhase );
[size=1em]           
[backcolor=rgb(250, 250, 250) !important][size=1em]    // 1.975, 0.793, 0.375, 0.193 are good frequencies
[size=1em]    float4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);
[backcolor=rgb(250, 250, 250) !important][size=1em]           
[size=1em]    vWaves = SmoothTriangleWave( vWaves );
[backcolor=rgb(250, 250, 250) !important][size=1em]    float2 vWavesSum = vWaves.xz + vWaves.yw;
[size=1em]      
[backcolor=rgb(250, 250, 250) !important][size=1em]    // Edge (xz) and branch bending (y)
[size=1em]    float3 bend = animParams.y * fDetailAmp * normal.xyz;
[backcolor=rgb(250, 250, 250) !important][size=1em]    bend.y = animParams.w * fBranchAmp;
[size=1em]    pos.xyz += ((vWavesSum.xyx * bend) + (wind.xyz * vWavesSum.y * animParams.w)) * wind.w;
[backcolor=rgb(250, 250, 250) !important][size=1em]      
[size=1em]    // Primary bending
[backcolor=rgb(250, 250, 250) !important][size=1em]    // Displace position
[size=1em]    pos.xyz += animParams.z * wind.xyz;
[backcolor=rgb(250, 250, 250) !important][size=1em]           
[size=1em]    return pos;
[backcolor=rgb(250, 250, 250) !important][size=1em]}




大家打开TerrainEngine.cginc文件.../Unity\Editor\Data\CGIncludes这个目录下面,里面有个AnimateVertex函数,大家就可以知道这函数从哪里来的。这还没完,如果有人看过GPU GEMS 3 里面有一篇Chapter 16. Vegetation Procedural Animation and Shading in Crysiscrysis的植被特效。建议大家看看,不要以为是老技术,其实技术没有新旧,只是看能不能为我所用。Crysis中的这个方法,用VS来完成摆动动画,节约了很多资源。可以腾出更多的性能空间。尤其是手持设备更应该注意的问题。
没想到shadowgun改都没改就拿过来用了,连注释都一样,如果不知道出处根本就不知道是什么。当然shadowgun的牛人是理解的,因为权重是写在模型顶点颜色上的,不知道这个怎么做的出效果。不过下面这段代码在这个效果里其实没什么用,因为_Object2World[3].xyz000,本来是用来做向位移的。为了做风吹过以后的层次感。

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em]2

[backcolor=rgb(250, 250, 250) !important][size=1em]3

[size=1em]4

[backcolor=rgb(250, 250, 250) !important][size=1em]5

[size=1em]6

[backcolor=rgb(250, 250, 250) !important][size=1em]7

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]// Phases (object, vertex, branch)
[size=1em]    float fObjPhase = dot(_Object2World[3].xyz, 1);
[backcolor=rgb(250, 250, 250) !important][size=1em]    float fBranchPhase = fObjPhase + animParams.x;
[size=1em]      
[backcolor=rgb(250, 250, 250) !important][size=1em]      
[size=1em]  float fDetailAmp = 0.1f;
[backcolor=rgb(250, 250, 250) !important][size=1em]    float fBranchAmp = 0.3f;




就是振幅.

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em]2

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]// x is used for edges; y is used for branches
[size=1em]    float2 vWavesIn = time  + float2(fVtxPhase, fBranchPhase );




Crysis里叶子的边用了x,叶子当中的茎干用yshadow gun里旗子本身的摆动用了y,边上的摆动用了x。其实都差不多,就是你有时想不到这么用。

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em]2

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]// 1.975, 0.793, 0.375, 0.193 are good frequencies
[size=1em]float4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);




是将两个频率映射成4个,不知道大家能否理解,这样就有了4个不同的频率。

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]vWaves = SmoothTriangleWave( vWaves );




这里用了三角波,就是为了不用sin cos 为了一点效率,很有借鉴,不过还要看实际测试。

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]float2 vWavesSum = vWaves.xz + vWaves.yw;




将两个频率合并,为了看上去没有规律。

[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em]2

[backcolor=rgb(250, 250, 250) !important][size=1em]3

[size=1em]4

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]// Edge (xz) and branch bending (y)
[size=1em]    float3 bend = animParams.y * fDetailAmp * normal.xyz;
[backcolor=rgb(250, 250, 250) !important][size=1em]    bend.y = animParams.w * fBranchAmp;
[size=1em]    pos.xyz += ((vWavesSum.xyx * bend) + (wind.xyz * vWavesSum.y * animParams.w)) * wind.w;






这里就是融合的部分,animParams.y叶子的权重从顶点色的绿色获得,fDetailAmp 振幅,normal法线叶子是按法线方向飘动的。下面也是一样的道理。
[url=]复制代码[/url]
[backcolor=rgb(250, 250, 250) !important][size=1em]1

[size=1em][backcolor=rgb(250, 250, 250) !important][size=1em]pos.xyz += animParams.z * wind.xyz;




加上风的偏移量,最后就完成了。

总结:
建议大家可以参考gpugems3上的文章,看更多的材料可以帮大家更好的理解,这个方法,我认为也是不错的。植被,简单的布料,旗帜,都可以用。虽然简单但很有效,完全用gpu计算,用于大量使用的话更有效的。


  • [url=][/url]
  • 图片:图片2.png

    [url=][/url]





作者: nts    时间: 2013-10-13 11:18
希望楼主提供原文章地址
作者: run0006    时间: 2014-5-7 04:14
感謝分享!
作者: likunhan    时间: 2014-5-7 09:20
感谢分享!
作者: Kadina    时间: 2014-5-14 09:58
thank you thanks sharing

作者: 张动画    时间: 2014-5-14 13:24
ShadowGun shader 解析




欢迎光临 纳金网 (http://old.narkii.com/club/) Powered by Discuz! X2.5