{git
}
体积光的项目分享:github
https://github.com/Claymoreno1/GodRay
体积光的实现方法有不少种,这里列出三种经常使用的,此篇博客详细讲解了经过后处理径向模糊方式的体积光实现,其它方式提供了方法和详细连接,由于人家讲的已经够好了web
float4 frag(v2f i):SV_Target{ float4 col=tex2D(_MainTex,i.uv); float linearDepth=LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv)); col*=step(_StepColor.r+_StepColor.g,col.r+col.g)*step(_Depthfloor,linearDepth); return col; }
第一个pass结果:
第二步:径向模糊
径向模糊和高斯模糊的区别就在于一个是照着一条线采样求均值,另外一个是在像素周围采样利用权值计算均值。svg
float2 center=_LightPos.xy; float2 uv=i.uv-center;
当前点的像素颜色值,来自于从沿着这条向量采样的颜色均值函数
for(float j=0;j<_Level;j++){ col+=tex2D(_MainTex,uv*(1-0.01*j)+center); } col/=_Level;
float2 blur=_LightDir.xy*(_LightPos.xy-i.uv);//*step(0,_LightPos.y-i.uv.y); for(float j=0;j<_Level;j++){ col+=tex2D(_MainTex,i.uv); i.uv+=blur; } col/=_Level;
这个效果须要在OnRenderImage函数中对采样步长修改,反复Blit几回
blurtype为ture,方法2学习
if (blurtype) { for (int i = 0; i < LightIntencity; i++) { LightDirx_2 = LightDirx * (i * 2 + 2); LightDiry_2 = LightDiry * (i * 2 + 2); Graphics.Blit(midpic, midpic2, Volumelight, 1); LightDirx_2 = LightDirx * (i * 2 + 6); LightDiry_2 = LightDiry * (i * 2 + 6); Graphics.Blit(midpic2, midpic, Volumelight, 1); } } else { Graphics.Blit(midpic, midpic2, Volumelight, 2); Graphics.Blit(midpic2, midpic, Volumelight, 2); }
第三步:与源source图像相叠加,获得最后的效果
这一步和简单,LightIntencity是用来控制光的强度,固然,咱们也能够在第一步采样的时候只保留灰度,而后在这一步中,咱们用灰度乘咱们想要的光的颜色,能够更方便的控制体积光的效果。ui
float4 col=tex2D(_MainTex,i.uv); float4 col2=tex2D(_BlurTex,i.uv); return col+col2*_LightIntencity;
后处理体积光已经基本实现了,那么,咱们如何控制光照方向呢?
很简单,(数位板借出去了。。。我用鼠标作一个示意图好了)
这里个人模糊中心是左上角Cube所在的屏幕坐标
在Chan项目中的效果预览
如下是C#与ShaderLab的所有代码
C#this
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] public class Volumelight_1 : MonoBehaviour { public bool blurtype; public Material Volumelight; public Color StepColor; [Range(1,100)] public float Depthfloor; public Camera thiscamera; [Range(0.01f,.5f)] public float LightDirx; [Range(0.01f, .5f)] public float LightDiry; private Vector4 LightPos; public Transform lighttrans; [Range(0.5f,3.0f)] public float Blurtimes; [Range(0.01f,2f)] public float LightIntencity; [Range(1,20)] public float Level; private float LightDirx_2; private float LightDiry_2; private void OnEnable() { thiscamera = this.GetComponent<Camera>(); thiscamera.depthTextureMode |= DepthTextureMode.Depth; } [ImageEffectOpaque] private void OnRenderImage(RenderTexture source, RenderTexture dest) { RenderTexture midpic = RenderTexture.GetTemporary(source.width, source.height, 0); RenderTexture midpic2 = RenderTexture.GetTemporary(source.width, source.height, 0); Volumelight.SetColor("_StepColor", StepColor); Volumelight.SetFloat("_Depthfloor", Depthfloor); Graphics.Blit(source, midpic, Volumelight, 0); LightPos = thiscamera.WorldToViewportPoint(lighttrans.transform.position); Volumelight.SetVector("_LightPos", LightPos); //Volumelight.SetFloat("_LightIntencity", LightIntencity); Volumelight.SetFloat("_Level", Level); Volumelight.SetVector("_LightDir", new Vector4(LightDirx,LightDiry,0,0)); if (blurtype) { for (int i = 0; i < Blurtimes; i++) { LightDirx_2 = LightDirx * (i * 2 + 2); LightDiry_2 = LightDiry * (i * 2 + 2); Graphics.Blit(midpic, midpic2, Volumelight, 1); LightDirx_2 = LightDirx * (i * 2 + 6); LightDiry_2 = LightDiry * (i * 2 + 6); Graphics.Blit(midpic2, midpic, Volumelight, 1); } } else { Graphics.Blit(midpic, midpic2, Volumelight, 2); Graphics.Blit(midpic2, midpic, Volumelight, 2); } Volumelight.SetFloat("_LightIntencity", LightIntencity); Volumelight.SetTexture("_BlurTex", midpic); Graphics.Blit(source, dest, Volumelight, 3); RenderTexture.ReleaseTemporary(midpic); RenderTexture.ReleaseTemporary(midpic2); } }
ShaderLab:spa
Shader "myshaders/VolumeLight" { Properties { _MainTex("_MainTex",2D)="white"{} _StepColor("_StepColor",Color)=(1,1,1,1) _Depthfloor("_Depthfloor",float)=5 _LightPos("_LightPos",vector)=(0,0,0,0) _LightDir("_LightDir",vector)=(0,-1,0,0) _LightIntencity("_LightIntencity",float)=1 _Level("_Level",float)=8 _BlurTex("_BlurTex",2D)="white"{} } CGINCLUDE #include "UnityCG.cginc" struct v2a{ float2 uv:TEXCOORD0; float4 vertex:POSITION; }; struct v2f{ float2 uv:TEXCOORD0; float4 pos:SV_POSITION; }; float4 _StepColor;//颜色阈值 sampler2D _MainTex; sampler2D _BlurTex; float4 _MainTex_TexelSize; sampler2D _CameraDepthTexture; float _Depthfloor;//距离阈值 float _LightIntencity; float4 _LightDir; float _Level; float4 _LightPos; v2f vert(v2a v){ v2f o; o.pos=UnityObjectToClipPos(v.vertex); o.uv=v.uv; #if UNITY_UV_STARTS_AT_TOP if(_MainTex_TexelSize.y<0) o.uv.y=1-o.uv.y; #endif return o; } float4 frag_1(v2f i):SV_Target{ float4 col=tex2D(_MainTex,i.uv); float linearDepth=LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv)); col*=step(_StepColor.r+_StepColor.g,col.r+col.g)*step(_Depthfloor,linearDepth)*step(linearDepth,50); return col; } float4 frag_2_1(v2f i):SV_Target{ float4 col=float4(0,0,0,0); float2 blur=_LightDir.xy*(_LightPos.xy-i.uv);//*step(0,_LightPos.y-i.uv.y); for(float j=0;j<_Level;j++){ col+=tex2D(_MainTex,i.uv); i.uv+=blur; } col/=_Level; return col; } float4 frag_2_2(v2f i):SV_Target{ float2 center=_LightPos.xy; float2 uv=i.uv-center; float4 col=float4(0,0,0,0); for(float j=0;j<_Level;j++){ col+=tex2D(_MainTex,uv*(1-0.01*j)+center); } col/=_Level; return col; } float4 frag_3(v2f i):SV_Target{ float4 col=tex2D(_MainTex,i.uv); float4 col2=tex2D(_BlurTex,i.uv); return col+col2*_LightIntencity; } ENDCG SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag_1 ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag_2_1 ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag_2_2 ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag_3 ENDCG } } }