UnityShader实现简单的体积光

本文介绍了在Unity中使用两种简单方法实现体积光效果的过程,包括代码实现细节和效果对比。通过调整参数如光照位置、强度和挤出因子,可以创建出逼真的光照氛围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

下面是代码,第一种方法参照了本篇博客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用来处理多个光源,而我的就一个光源就没必要写那么多了。

所支持的Unity版本 5.2.0 及以上版本 WebGL Showcase | WebGL压力测试|文档|论坛 这个插件允许您通过生成真正容积的程序束来大大改善场景的照明。 这是模拟聚灯和手电筒的密度,深度和音量的完美,简单而便宜的方法。 简单高效的体积照明解决方案兼容各种平台(Windows PC,Mac OS X,Linux,WebGL,iOS,Android,VR)! 即使在移动设备上,也能为您的聚灯和手电筒模拟密度,深度和体积的完美,简单且便宜的方式! 它通过自动高效地生成真正的体积程序束来渲染高质量的线效果,从而极大地改善了场景的照明。 特征: - 真正的体积效果:即使你在束中也能工作。 - 非常容易使用和集成/需要零设置。 - 程序生成:一切都是在引擎盖下动态计算的。 - 在任何地方添加无限束:替代解决方案通常只需要实时灯:此插件不需要。您可以制作烘烤的量,甚至可以在没有任何线的情况下添加束。 - 动态3D噪声功能,用于模拟动画体积雾/雾/烟雾效果。 - 体积粉尘颗粒功能可模拟高度详细的防尘灯和微尘效果。 - 动态遮挡:可以通过移动几何体来阻挡束。 - 您可以实时移动和旋转束。 - 触发区域功能:您可以跟踪通过束的对象。 - 完全动态:在游戏时间内从脚本,动画师或时间轴更改或动画每个属性。 - Super FAST:不需要任何后处理,命令缓冲区和计算着色器:即使在移动设备和WebGL等低性能平台上也能很好地工作。 - VR Ready:支持Normal和VR Single pass立体声。 - 平滑交叉并与几何和相机混合。 - 自定义截头圆锥几何体。 - 支持许多图形变体:延迟和前向渲染路径,Gamma和线性颜色空间,HDR颜色,多种混合模式。 - 调整分层图层和图层顺序,以使用2D精灵调整束渲染。 - 开箱即用的透视和正交相机。 - 支持Unity内置雾。 - WYSIWYG:在场景视图中立即可以看到每个修改:无需在编辑器和播放模式之间切换以查看您的更改。 - 完整源代可用/无DLL。束设置和处理通过功能强大的API完全暴露。 - 详细的文件。 - 支持从Unity 5.2到最新的2017.X和2018.X版本。 - 示例场景包括:展示演示。 请注意,此资产不是全屏后期处理/图像效果。这与Unity内置的Sun Shafts图像效果不相似。 相反,体积束将产生优化的几何形状和材料谱。这种技术有几个优点: - 更精细:独立精确定制每个束。 - 您可以在任何地方添加束,即使在没有线的地方也是如此。 - 当连接到聚灯时,它支持实时,烘焙和混合模式。 - 您可以渲染的束数量没有限制。 - 更容易与您自己的管道集成:无需与您自己的图像效果或后处理堆栈混合,没有命令缓冲区,不需要计算着色器功能。 - 运行得更快。没有后期处理添加到您的相机。 - 支持移动等低端平台。 如何使用它? 体积束设计非常易于使用。无需设置。您不必将多个对象链接在一起。您只需要使用一个简单的新组件。你可以通过2次点击添加一个新的束! 您可以通过调整一组用户友好的属性来精确定制每个束的渲染。为了获得更好看的效果,一些属性会自动绑定到附加的聚灯。 限制: 目前,此资产的当前版本有一些小的限制: - 此资产仅支持“聚灯”(形状像锥形的束)。不支持点光源线向各个方向平等)。 - “3D噪声”功能要求着色器功能等于或高于Shader Model 3.5 / OpenGL ES 3.0。 2012年之后发布的任何移动设备都应该支持它。 - 仅在Unity 5.5或更高版本上支持“体积粉尘颗粒”。 - “动态遮挡”功能计算遮挡的近似值,但尚不支持“部分遮挡”。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值