UnityShader实战 之 体积光的实现

      大家好,我是Zander. 今天我们用Shader来模拟体积光。先看一下效果:


 这是在ShadowGun场景里的一个实现效果。

Shader代码如下:

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 。或者关注我的公众号:


  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值