欢迎来到我的博客
又开始疯狂摸鱼了,药丸药丸!!!真是是间歇性踌躇满志,持续性混吃等死啊。
本篇文章用两种比较简单的方法实现了体积光,因为简单,所以瑕疵还是有的。
上图是百度百科的丁达尔效应那弄来的图片,太美了…这个光照,然后看看代码实现的
这…这是什么鬼…
看看第二种
唔…本篇博客到此结束,再见…
下面是代码,第一种方法参照了本篇博客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用来处理多个光源,而我的就一个光源就没必要写那么多了。