签到领奖

[再来一次] UnityShader实战 之 体积光的实现

[复制链接]
查看: 3369|回复: 6
排名
401
昨日变化
发表于 2017-1-6 13:49:43 | 显示全部楼层 |阅读模式
本帖最后由 里斯 于 2017-1-7 11:33 编辑

      大家好,我是Zander. 今天我们用Shader来模拟体积光。先看一下效果:
这是在ShadowGun场景里的一个实现效果。
Shader代码如下:
[AppleScript] 纯文本查看 复制代码
Shader "Custom/Blinking GodRays" {
        Properties {
                _MainTex ("Base texture", 2D) = "white" {}                                        //用于模拟光照的透明纹理
                _FadeOutDistNear ("Near fadeout dist", float) = 10                                      //小于这个距离时 会出现淡出效果
                _FadeOutDistFar ("Far fadeout dist", float) = 10000                                      //大于这个距离时 会出现淡出效果
                _Multiplier("Color multiplier", float) = 1                                        //光照颜色的乘数  可以用来调节最后的模拟光照
                _Bias("Bias",float) = 0                                                           //模拟闪烁时  波形的偏移  可以理解为波形图像Y方向的移动量
                _TimeOnDuration("ON duration",float) = 0.5                                        //模拟闪烁时  闪烁时亮着的时间
                _TimeOffDuration("OFF duration",float) = 0.5                                      //模拟闪烁时  闪烁时暗着的时间
                _BlinkingTimeOffsScale("Blinking time offset scale (seconds)",float) = 5          //模拟闪烁时  指定闪烁在波形中开始位置
                _SizeGrowStartDist("Size grow start dist",float) = 5                              //大于这个距离时,会开始对顶点进行扩展,即从0开始增长。
                _SizeGrowEndDist("Size grow end dist",float) = 50                                 //达到这个距离时,扩张达到最大程度,即扩展程度为1。
                _MaxGrowSize("Max grow size",float) = 2.5                                         //扩张的最大大小
                _NoiseAmount("Noise amount (when zero, pulse wave is used)", Range(0,0.5)) = 0    //模拟闪烁时,噪声的程度,用于混合均匀的脉冲波和噪声波
                _Color("Color", Color) = (1,1,1,1)                                                //用于改变光照颜色。
        }
        
        SubShader{
           
           Tags{ "Queue" = "Transparent"  "IgnoreProjector" = "True"  "RenderType" = "Transparent" }

           Blend One One    // 贴图和背景叠加   无Alpha透明通道处理 
           Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }

           CGINCLUDE
           #include "UnityCG.cginc"
            sampler2D _MainTex;
        
            float   _FadeOutDistNear;
                float   _FadeOutDistFar;
                float   _Multiplier;
                float   _Bias;
                float   _TimeOnDuration;
                float   _TimeOffDuration;
                float   _BlinkingTimeOffsScale;
                float   _SizeGrowStartDist;
                float   _SizeGrowEndDist;
                float   _MaxGrowSize;
                float   _NoiseAmount;
                float4  _Color;

                struct v2f{
                   float4 pos : SV_POSITION;   //裁剪空间中的顶点坐标  
                   float2 uv  : TEXCOORD0;     //顶点的纹理坐标  
                   fixed4 color : TEXCOORD1;    //顶点颜色 
                };

                v2f vert(appdata_full  v)
                { 
                    v2f  o;

                    float                time                         =  _Time.y + _BlinkingTimeOffsScale * v.color.b;                
                        float3            viewPos                    =  mul(UNITY_MATRIX_MV,v.vertex);                           //mul(x, y) 返回x、y矩阵相乘的积。
                        float                dist                        =  length(viewPos);                                         //length(v)  返回v向量的长度  dist  距离视角的远近
                        float                nfadeout            =  saturate(dist / _FadeOutDistNear);                       //saturate(x) 把x截取在[0, 1]之间    如果小于了_FadeOutDistNear,那么就会开始模拟淡出的效果
                        float                ffadeout            =  1 - saturate(max(dist - _FadeOutDistFar,0) * 0.2);       //0.2是模拟了淡入的速率
                        float                fracTime            =  fmod(time,_TimeOnDuration + _TimeOffDuration);           //fmod(x, y)  返回x/y的浮点余数。
                        float                wave                        =  smoothstep(0,_TimeOnDuration * 0.25,fracTime)  * (1 - smoothstep(_TimeOnDuration * 0.75,_TimeOnDuration,fracTime));  //smoothstep(min, max, x) 如果x的范围是[min, max],则返回一个介于0和1之间的Hermite插值。
                        float                noiseTime            =  time *  (6.2831853f / _TimeOnDuration);
                        float                noise                        =  sin(noiseTime) * (0.5f * cos(noiseTime * 0.6366f + 56.7272f) + 0.5f);
                        float                noiseWave            =  _NoiseAmount * noise + (1 - _NoiseAmount);
                        float                distScale            =  min(max(dist - _SizeGrowStartDist,0) / _SizeGrowEndDist,1);
                        
                                
                        wave = _NoiseAmount < 0.01f ? wave : noiseWave;    //这里主要是为了模拟闪烁的效果
                        
                        distScale = distScale * distScale * _MaxGrowSize * v.color.a;  //扩大顶点区域  这主要是为了模拟射灯的效果 ,我们在远离光源的过程中会感觉好像光照范围范围变大了
                        
                        wave += _Bias;
                        
                        ffadeout *= ffadeout;
                        
                        nfadeout *= nfadeout;
                        nfadeout *= nfadeout;
                        
                        nfadeout *= ffadeout;
                        
                        float4        mdlPos = v.vertex;
                        
                        mdlPos.xyz += distScale * v.normal;
                                        
                        o.uv                = v.texcoord.xy;
                        o.pos        = mul(UNITY_MATRIX_MVP, mdlPos);
                        o.color        = nfadeout * _Color * _Multiplier * wave;

                    return o;
                }
           ENDCG

           Pass {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #pragma fragmentoption ARB_precision_hint_fastest                
                        fixed4 frag (v2f i) : COLOR
                        {                
                                return tex2D (_MainTex, i.uv.xy) * i.color;
                        }
                        ENDCG 
        }        

        }
}



具体的实现逻辑我在上面添加了注释 ,如有不对的地方,还望不吝指导。
所需要的图片:

所需要的模型资源地址:
链接:http://pan.baidu.com/s/1kVJjjTX 密码:payr
最后的实现效果 :
   
好了,这一章就写到这,欢迎大家加入QQ群:280993838 。或者关注我的公众号:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

免费评分

参与人数 1泰斗币 +50 收起 理由
里斯 + 50 赞一个!

查看全部评分

最近访问 头像模式 列表模式
+1
1131°C
6
  • aa710315280
  • 里斯
  • try111
  • 墨麟
  • 天长第9
过: 他们
楼主热帖
2武林新丁
108/200
排名
429
昨日变化
发表于 2017-1-6 14:21:20 | 显示全部楼层
看了LZ的帖子,我只想说一句很好很强大!
[发帖际遇]: aa710315280 拉灯想跟你学用unity做航母,这是 1 泰斗币当学费了. 幸运榜 / 衰神榜
5武林高手
1396/2000
排名
223
昨日变化
发表于 2017-1-7 11:34:10 | 显示全部楼层
膜拜神贴
回复

使用道具 举报

3江湖小虾
214/500
排名
235
昨日变化
1
发表于 2017-1-8 10:21:26 | 显示全部楼层
膜拜膜拜
回复

使用道具 举报

2武林新丁
112/200
排名
374
昨日变化
发表于 2017-1-9 09:25:08 | 显示全部楼层
泰斗帖子强,满满正能量。
3江湖小虾
496/500
排名
374
昨日变化
发表于 2017-1-9 13:45:50 | 显示全部楼层
膜拜神贴,后面请保持队形~
[发帖际遇]: 天长第9 发帖时在路边捡到 2 泰斗币,偷偷放进了口袋. 幸运榜 / 衰神榜
发表于 2017-1-11 17:27:47 | 显示全部楼层
bfdbfdb fgdfg dfgfdgdf gdfgfdg retretr regergreg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /3 下一条

在线客服(工作时间:9:00-22:00)
010-82609395
泰斗社区公众号

Copyright   ©2015-2016  【泰斗社区】-专注互联网游戏和应用的开发者平台  Powered by©Discuz!  技术支持:迪恩网络     ( 沪ICP备14023207号-9 )