Shader "Unlit/volumeLight" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 HLSLINCLUDE #pragma multi_compile _ _MAIN_LIGHT_SHADOWS //接受阴影 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE //产生阴影 #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _SHADOWS_SOFT //软阴影 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl" //#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" TEXTURE2D( _MainTex); SAMPLER(sampler_MainTex); TEXTURE2D( _LightMar); SAMPLER(sampler_LightMar); float4 _MainTex_TexelSize; float4 _MainTex_ST; //步进次数 int _StepCount; //最大步进距离 float _MaxStepDest; static half dither[16] = { 1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0, 13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0, 4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0, 16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0 }; struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; }; float Remap(float x,float inMin,float inMax,float toMin,float toMax) { return (x-inMin)/(inMax-inMin)*(toMax-toMin)+toMin; } Varyings vert(Attributes v) { Varyings o = (Varyings)0; o.positionCS = TransformObjectToHClip(v.positionOS.xyz); o.uv =v.uv; //TRANSFORM_TEX(v.uv, _MainTex); return o; } float _Strength; half4 fragBlend(Varyings i) : SV_Target { float4 color= SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv); float4 light= SAMPLE_TEXTURE2D(_LightMar,sampler_LightMar, i.uv); color=color*light*2*_Strength+color+light*0.1*_Strength; return color; } float space_sigma; float range_sigma ; //高斯模糊->双边过滤 half4 fragBlur(Varyings input) : SV_Target { float weight_sum = 0; float3 color_sum = 0; float3 color_origin = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); float3 color = 0; //float space_sigma=2; //float range_sigma =5; for(int i = -3; i < 3; i++){ for(int j = -3; j < 3; j++){ //空域高斯-uv加权 float2 varible = input.uv + float2(i * _MainTex_TexelSize.x, j * _MainTex_TexelSize.y)*3; float space_factor = i * i + j * j; space_factor = (-space_factor) / (2 * space_sigma* space_sigma); float space_weight = 1/(space_sigma * space_sigma * 2 * PI) * exp(space_factor); //值域高斯-颜色加权 float3 color_neighbor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, varible); float3 color_distance = (color_neighbor - color_origin); float value_factor = color_distance.r * color_distance.r ; value_factor = (-value_factor) / (2 * range_sigma * range_sigma); float value_weight = (1 / (2 * PI * range_sigma)) * exp(value_factor); weight_sum += space_weight * value_weight; color_sum += color_neighbor * space_weight * value_weight; } } color=lerp(color,color_sum / weight_sum,step(0,weight_sum)); return float4(color,1); } half4 fragBlurFast(Varyings i) : SV_Target { float2 size=_MainTex_TexelSize.xy*1; float4 result=(SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(1,1)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(-1,-1)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(-1,1)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(1,-1)*size)); return result*0.25; } half4 fragBlurFast2(Varyings i) : SV_Target { float2 size=_MainTex_TexelSize.xy*1; float4 result=(SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(0,1)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(0,-1)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(-1,0)*size)+ SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv+int2(1,0)*size)); return result*0.25; } float Getshadow(float3 posWorld) { float4 shadowCoord = TransformWorldToShadowCoord(posWorld); float shadow = MainLightRealtimeShadow(shadowCoord); return shadow; } //AABB包围盒,一个射线可以得到,打到以某一点为中心的xyz平面上的新射线点 float2 rayBoxDst(float3 boundsMin,float3 boundsMax,float3 rayOrigin ,float3 rayDir) { //t是分正负方向的 float3 t0 = (boundsMin - rayOrigin) / rayDir; float3 t1 = (boundsMax - rayOrigin) / rayDir; float3 tmin = min(t0, t1); float3 tmax = max(t0, t1); //左右上下的面因取最小值得到的都是负值,必然取到正面的值 float dstA = max(max(tmin.x, tmin.y), tmin.z); float dstB = min(tmax.x, min(tmax.y, tmax.z)); float dstToBox = max(0, dstA); float dstInsideBox = max(0, dstB - dstToBox); //返回摄像机到包围盒的距离,穿过包围盒内部的距离 return float2(dstToBox, dstInsideBox); } float RandomRange(float2 Seed, float Min, float Max) { float randomno = frac(sin(dot(Seed, float2(12.9898, 78.233)))*43758.5453); float Out = lerp(Min, Max, randomno); return Out; } float3 _BoundMin; float3 _BoundMax; float _J; half4 frag (Varyings i) : SV_Target { _J=24; float depth=SampleSceneDepth(i.uv); float3 wpos=ComputeWorldSpacePosition(i.uv, depth,UNITY_MATRIX_I_VP); //世界空间下从当前点指向摄像机的方向 float3 dir= normalize(_WorldSpaceCameraPos-wpos); float l1=length(_WorldSpaceCameraPos-wpos); float2 result=rayBoxDst(_BoundMin,_BoundMax,_WorldSpaceCameraPos.xyz,-dir); float dstToBox=result.x; float dstInSideBox=result.y; //主要dir的方向不然得到的点是错的 float3 startPos=_WorldSpaceCameraPos.xyz-dir*dstToBox-dir*dstInSideBox; //float3 endPos=_WorldSpaceCameraPos.xyz-dir*dstToBox.x; float l2=dstToBox+dstInSideBox; uint index = (uint(i.uv.x*_ScreenSize.x) % 4) * 4 + uint(i.uv.y*_ScreenSize.y) % 4; float jitter =Remap( dither[index],0,1,0.5,1);//*RandomRange(i.uv,0.96,1.04) //在AABB包围盒中就使用固定间隔步进,按固定次数步进(视觉效果比按固定距离步进性能更好) float d=0; float3 currpos=0; int Count=24; if(l1>l2) { d=dstInSideBox/_J*RandomRange(i.uv,0.97,1.03);//*RandomRange(i.uv,0.96,1.04); Count=dstInSideBox/d; currpos=startPos; } else { float l=l1-dstToBox; d=l/_J*RandomRange(i.uv,0.97,1.03);//*RandomRange(i.uv,0.96,1.04); Count=l/d; currpos=wpos; } //穿过AABB包围盒的距离为0时说明光线没有穿过体积光区域,不需要进行后续计算 if( dstToBox>l1 || dstInSideBox==0) return 0; float total=0; UNITY_LOOP for(int j=0;j1) break; float shadow=Getshadow(currpos); total+=shadow*1/Count; //添加抖动 uint index = (uint(i.uv.x*_ScreenSize.x) % 4) * 4 + uint(i.uv.y*_ScreenSize.y) % 4; float jitter = Remap( dither[index],0,1,0.5,1);//dither[index]; currpos+=dir*d;//*jitter; } //total=saturate(total)*pow(min(dstInSideBox*0.3,2),1); total=(total/5*Count*d); total=min(total,4); return total.xxxx; } ENDHLSL //光线步进 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag ENDHLSL } //高斯模糊-双边过滤 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment fragBlur ENDHLSL } //合并 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment fragBlend ENDHLSL } //快速模糊 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment fragBlurFast ENDHLSL } //快速模糊 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment fragBlurFast2 ENDHLSL } } }