UnityShader实现简单的体积光

欢迎来到我的博客
又开始疯狂摸鱼了,药丸药丸!!!真是是间歇性踌躇满志,持续性混吃等死啊。
本篇文章用两种比较简单的方法实现了体积光,因为简单,所以瑕疵还是有的。
在这里插入图片描述
上图是百度百科的丁达尔效应那弄来的图片,太美了…这个光照,然后看看代码实现的
在这里插入图片描述
这…这是什么鬼…
看看第二种
在这里插入图片描述
唔…本篇博客到此结束,再见…

下面是代码,第一种方法参照了本篇博客Unity Shader-GodRay,体积光(BillBoard,Volume Shadow,Raidal Blur,Ray-Marching).
说了参考,还不是直接拿人家的代码自己实现一遍…好吧

// An highlighted block
Shader "Learn/VolumeShadow"
{
	Properties
	{
		_Color("Color", Color) = (1,1,1,0.002)
		_MainTex ("Texture", 2D) = "white" {}
		_LightTex ("Texture", 2D) = "white" {}
		_ExtrusionFactor("Extrusion", Range(0, 2)) = 0.1//挤出因子
		_Intensity("Intensity", Range(0, 10)) = 1//强度
		_WorldLightPos("LightPos", Vector) = (0,0,0,0)//输入一个光照位置
		_BumpMap ("Mormal Map", 2D) = "bump" {}
		_BumpScale("Bump Scale", Float)=1.0
		_Specular("Specular",Color)=(1, 1, 1, 1)
		_Gloss("Gloss",Range(8.0,256))=20
	}
	SubShader
	{
		CGINCLUDE
		#include "UnityCG.cginc"

		float4 _Color;
		//sampler2D _MainTex;
		float4 _WorldLightPos;
		float _ExtrusionFactor;
		float _Intensity;
		//float4 _MainTex_ST;//模型偏移
		sampler2D _LightTex;
		float4 _LightTex_ST;
		sampler2D _BumpMap;
		float4 _BumpMap_ST;
		float _BumpScale;//凹凸
		fixed4 _Specular;
		float _Gloss;

		struct v2f{
			float4 pos:SV_POSITION;
			float2 uv :TEXCOORD0;
			float distance:TEXCOORD1;
		};

		v2f vert(appdata_base v)
		{
			v2f o;
			float3 objectLightPos=mul(unity_WorldToObject,_WorldLightPos.xyz).xyz;
			float3 objectLightDir=objectLightPos-v.vertex.xyz;
			float dotValue=dot(objectLightDir,v.normal);//计算漫反射系数

			float controlValue=sign(dotValue)*0.5+0.5;
			//sign计算输入值的符号,dotValue(-1,0,1)。controlValue(0~1)
			float4 vpos=v.vertex;
			vpos.xyz-=objectLightDir*_ExtrusionFactor*controlValue;//计算顶点位置,按光照反方向挤出

			o.uv=v.texcoord.xy;
			o.pos=UnityObjectToClipPos(vpos);
			o.distance=length(objectLightDir);

			return o;
		}

		fixed4 frag(v2f i):COLOR
		{
			fixed4 tex=tex2D(_LightTex,i.uv);
			//顶点到光的距离与物体到光的距离控制一个衰减值
			float att=i.distance/_WorldLightPos.w;
			return _Color*tex*att*_Intensity;
		}

		ENDCG

		UsePass "MyShader/NormaMapTangentSpace/NORMAL_MAP_TANGENT_SPACE"
		//这是《Unity Shader入门精要》里计算法线和光照的pass
		
		Pass
		{
			Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent + 1" }
			LOD 100
			Blend SrcAlpha OneMinusSrcAlpha
			Cull off
			ZWrite off
			Fog{ Color(0,0,0,0)}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma fragmentoption ARB_precision_hint_fastest
			//最快的,意思就是会用低精度(一般是指fp16),以提升片段着色器的运行速度,减少时间。
			
			ENDCG
		}

	}

	Fallback "Specular"
}

第二种方法参考了本篇博客[shader]体积光影.

Shader "Learn/LightTrail"
{
	//1:模型空间 2:世界空间 3:观察空间 4:裁剪空间

	//UNITY_MATRIX_MVP:将坐标或者方向从1到4
	//UNITY_MATRIX_MV:将坐标或者方向从1到3
	//UNITY_MATRIX_VP:将坐标或者方向从2到4
	//UNITY_MATRIX_V:将坐标或者方向从2到3
	//UNITY_MATRIX_P:将坐标或者方向从3到4

	Properties
	{
		_BackColor("BackColor",Color) = (0,0,0,1)
		_LightColor("LightColor",Color) = (1,1,0,1)
		_MainTex("Texture", 2D) = "white" {}
		_SmoothRange("SmoothRange",Range(0,20)) = 1
		_TrailColor("TrailColor",Color) = (0,0,0,1)
		_TrailPower("TrailPower",Range(0,10)) = 2
		_TrailLength("TrailLength",Range(0,500)) = 100
	}
	SubShader
	{
		Tags { "RenderType"="Transparent" "Queue"="Transparent" }
		LOD 100

		CGINCLUDE 
		#include "UnityCG.cginc"
		#include "Lighting.cginc"

		sampler2D _MainTex;
		float4 _MainTex_ST;
		fixed4 _BackColor;
		fixed4 _LightColor;
		float _SmoothRange;
		fixed4 _TrailColor;
		float _TrailPower;
		float _TrailLength;

		struct a2v_one
		{
			float4 vertex : POSITION;
			float2 uv : TEXCOORD0;
			float3 normal:NORMAL;
		};

		struct v2f_one
		{
			float2 uv : TEXCOORD0;
			UNITY_FOG_COORDS(1)
			float4 vertex : SV_POSITION;
			float4 wPos:TEXCOORD2;
			float3 normal:TEXCOORD3;
		};

		struct v2f_two
		{
			float4 vertex:SV_POSITION;
			float3 wPos:TEXCOORD0;
			float3 normal:TEXCOORD1;
		};

		v2f_one vert_one (a2v_one v)
		{
			v2f_one o;
			o.vertex = UnityObjectToClipPos(v.vertex);
			o.wPos=mul(unity_ObjectToWorld,v.vertex);
			_MainTex_ST.zw*=_Time.y;
			o.uv = TRANSFORM_TEX(v.uv, _MainTex);
			o.normal=UnityObjectToWorldNormal(v.normal);
			UNITY_TRANSFER_FOG(o,o.vertex);
			return o;//这里只是让贴图动起来
		}

		v2f_two vert_two(appdata_base v)
		{
			v2f_two o;
			o.wPos=mul(unity_ObjectToWorld,v.vertex);//模型坐标转成世界坐标
			o.normal=UnityObjectToWorldNormal(v.normal);
			v.vertex.xyz+=v.normal*0.01;
			//o.vertex=mul(UNITY_MATRIX_M,v.vertex);//unity_ObjectToWorld  其实就是UNITY_MATRIX_M矩阵.
			o.vertex=mul(unity_ObjectToWorld,v.vertex);

			float3 lightDir=normalize(UnityWorldSpaceLightDir(o.wPos));
			float Ndotl=min(0,dot(o.normal,lightDir.xyz));
			o.vertex.xyz+=lightDir*Ndotl*_TrailLength;//NdotL大于0的部分突出,即受光面
			o.vertex=mul(UNITY_MATRIX_VP, o.vertex);//将坐标或者方向从世界空间到裁剪空间

			return o;
		}

		fixed4 frag_one (v2f_one i) : SV_Target
		{
			float nor=dot(i.normal,normalize(UnityWorldSpaceLightDir(i.wPos)));//光照系数(0~1)
			fixed4 col = tex2D(_MainTex, i.uv);
			float _front=saturate(nor*_SmoothRange);//_SmoothRange为1比较合适
			col*=lerp(_BackColor,_LightColor0,_front);
			col+=_LightColor*min(1-_front,col.a);//计算背面的颜色
			UNITY_APPLY_FOG(i.fogCoord, col);
			return col;
		}

		fixed4 frag_two (v2f_two i) : SV_Target
		{
			float nor=dot(i.normal,normalize(UnityWorldSpaceLightDir(i.wPos)));
			fixed4 col=_TrailColor*(pow(1.5*_TrailColor.a-abs(nor),_TrailPower));//abs计算输入值的绝对值。pow幂
			return col;
		}
		ENDCG
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
			#pragma vertex vert_one
			#pragma fragment frag_one
			// make fog work
			#pragma multi_compile_fog
			ENDCG
		}

		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			ZWrite Off
			Cull Off
			Blend SrcAlpha OneMinusSrcAlpha
			CGPROGRAM
			#pragma vertex vert_two
			#pragma fragment frag_two
			ENDCG
		}
	}
	Fallback "Diffuse"
}

原文章把两个Pass重复成四个,是因为原文后面两个Pass用来处理多个光源,而我的就一个光源就没必要写那么多了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值