// Written by Arys Shader "Hidden/CustomNightVision" { Properties { // Nightvision properties _Color ("Color", Vector) = (0.596,0.839,0.988,1) _MainTex ("_MainTex", 2D) = "white" {} _Intensity ("_Intensity", Float) = 2.5 _Noise ("_Noise", 2D) = "white" {} _NoiseScale ("_NoiseScale", Vector) = (1,1.68,0,0) _NoiseIntensity ("_NoiseIntensity", Float) = 1 _NightVisionOn ("_NightVisionOn", Float) = 1 _LensDistortionOn ("_LensDistortionOn", Float) = 1 _EdgeDistortion ("_EdgeDistortion", Float) = 0.1 _EdgeDistortionStart ("_EdgeDistortionStart", Float) = 0.28 _NearBlurOn ("_NearBlurOn", Float) = 1 _NearBlurIntensity ("_NearBlurIntensity", Float) = 20 _NearBlurMaxDistance ("_NearBlurMaxDistance", Float) = 4 _NearBlurKernel ("_NearBlurKernel", Range(1,3)) = 3 // Texture mask properties _Mask ("_Mask", 2D) = "white" {} _InvMaskSize ("_InvMaskSize", Float) = 1 _InvAspect ("_InvAspect", Float) = 0.42 _CameraAspect ("_CameraAspect", Float) = 1.78 } SubShader { Pass { Cull Off ZWrite Off ZTest Always Fog { Mode Off } GpuProgramID 33735 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 sv_position : SV_Position0; float2 texcoord : TEXCOORD0; float2 texcoord1 : TEXCOORD1; float2 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; }; struct fout { float4 sv_target : SV_Target0; }; float2 _NoiseScale; float _NoiseIntensity; float _NightVisionOn; float _LensDistortionOn; float _EdgeDistortion; float _EdgeDistortionStart; float _NearBlurOn; float _NearBlurIntensity; float _NearBlurMaxDistance; float _NearBlurKernel; float4 _Color; float _Intensity; float4 _MainTex_TexelSize; float _InvMaskSize; float _InvAspect; float _CameraAspect; sampler2D _MainTex; sampler2D _Mask; sampler2D _Noise; UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); float ComputeNearFactor(float2 uv) { float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); float eyeDepth = LinearEyeDepth(rawDepth); return saturate(1.0 - eyeDepth / max(_NearBlurMaxDistance, 0.001)); } v2f vert(appdata_full v) { v2f o; float4 tmp0; float4 tmp1; float4 tmp2; tmp0 = v.vertex.yyyy * unity_ObjectToWorld._m01_m11_m21_m31; tmp0 = unity_ObjectToWorld._m00_m10_m20_m30 * v.vertex.xxxx + tmp0; tmp0 = unity_ObjectToWorld._m02_m12_m22_m32 * v.vertex.zzzz + tmp0; tmp0 = tmp0 + unity_ObjectToWorld._m03_m13_m23_m33; tmp1 = tmp0.yyyy * unity_MatrixVP._m01_m11_m21_m31; tmp1 = unity_MatrixVP._m00_m10_m20_m30 * tmp0.xxxx + tmp1; tmp1 = unity_MatrixVP._m02_m12_m22_m32 * tmp0.zzzz + tmp1; tmp1 = unity_MatrixVP._m03_m13_m23_m33 * tmp0.wwww + tmp1; o.sv_position = tmp1; if (_NightVisionOn == 0) { o.texcoord.xy = v.texcoord.xy; return o; } tmp0.x = v.texcoord.x - 0.5; tmp0.x *= _CameraAspect; tmp0.z = tmp0.x * _InvAspect; tmp0.w = v.texcoord.y; tmp0.xy = tmp0.zw - float2(-0.0, 0.5); tmp2.xy = _Time.xx * float2(14345.68, -12345.68); tmp2.xy = frac(tmp2.xy); o.texcoord1.xy = v.texcoord.xy * _NoiseScale + tmp2.xy; o.texcoord2.xy = tmp0.xy * _InvMaskSize.xx + float2(0.5, 0.5); o.texcoord.xy = v.texcoord.xy; tmp0.y = tmp0.y * unity_MatrixV._m21; tmp0.x = unity_MatrixV._m20 * tmp0.x + tmp0.y; tmp0.x = unity_MatrixV._m22 * tmp0.z + tmp0.x; tmp0.x = unity_MatrixV._m23 * tmp0.w + tmp0.x; o.texcoord3.z = -tmp0.x; tmp0.x = tmp1.y * _ProjectionParams.x; tmp0.w = tmp0.x * 0.5; tmp0.xz = tmp1.xw * float2(0.5, 0.5); o.texcoord3.w = tmp1.w; o.texcoord3.xy = tmp0.zz + tmp0.xw; return o; } fout frag(v2f inp) { fout o; float4 tmp0 = tex2D(_MainTex, inp.texcoord.xy); if (_NightVisionOn == 0) { o.sv_target = tmp0; return o; } float4 noise = tex2D(_Noise, inp.texcoord1.xy); float4 rawMask = tex2D(_Mask, inp.texcoord2.xy); // 1) NVG application mask (hard cutoff). const float nvgCutoff = 0.55; float nvgMask = step(rawMask.a, nvgCutoff); if (nvgMask <= 0.0) { o.sv_target = tmp0; return o; } // Prebaked mask format: // R,G = edge direction encoded from [-1,1] to [0,1] // B = distance-to-edge normalized [0,1] inside mask float2 edgeDir = rawMask.rg * 2.0 - 1.0; edgeDir.y = -edgeDir.y; float dirLen = length(edgeDir); if (dirLen > 1e-5) { edgeDir /= dirLen; } else { edgeDir = float2(0.0, 0.0); } float2 warpedUv = inp.texcoord.xy; if (_LensDistortionOn > 0.5) { float edgeDistance = saturate(rawMask.b); float edgeWidth = max(saturate(_EdgeDistortionStart), 0.001); float edgeBand = 1.0 - smoothstep(0.0, edgeWidth, edgeDistance); float edgeBias = 1.0 - edgeDistance; // 2) Distortion strength mask (smooth falloff). float distMask = nvgMask * edgeBand * edgeBias * edgeBias; warpedUv = inp.texcoord.xy - edgeDir * (_EdgeDistortion * 0.1 * distMask); warpedUv = clamp(warpedUv, 0.0, 1.0); } tmp0 = tex2D(_MainTex, warpedUv); // Depth-based near Gaussian blur (strong near camera, fades to zero at max distance). if (_NearBlurOn > 0.5) { float nearFactor = ComputeNearFactor(warpedUv); float2 spreadUv = _MainTex_TexelSize.xy * max(1.0, _NearBlurIntensity * 0.35); float nC = nearFactor; float nR = ComputeNearFactor(clamp(warpedUv + float2( spreadUv.x, 0.0), 0.0, 1.0)); float nL = ComputeNearFactor(clamp(warpedUv + float2(-spreadUv.x, 0.0), 0.0, 1.0)); float nU = ComputeNearFactor(clamp(warpedUv + float2(0.0, spreadUv.y), 0.0, 1.0)); float nD = ComputeNearFactor(clamp(warpedUv + float2(0.0, -spreadUv.y), 0.0, 1.0)); float nUR = ComputeNearFactor(clamp(warpedUv + float2( spreadUv.x, spreadUv.y), 0.0, 1.0)); float nUL = ComputeNearFactor(clamp(warpedUv + float2(-spreadUv.x, spreadUv.y), 0.0, 1.0)); float nDR = ComputeNearFactor(clamp(warpedUv + float2( spreadUv.x, -spreadUv.y), 0.0, 1.0)); float nDL = ComputeNearFactor(clamp(warpedUv + float2(-spreadUv.x, -spreadUv.y), 0.0, 1.0)); float nearSoft = ( nUL + 2.0 * nU + nUR + 2.0 * nL + 4.0 * nC + 2.0 * nR + nDL + 2.0 * nD + nDR ) / 16.0; float nearPeak = max(max(max(nL, nR), max(nU, nD)), max(max(nUL, nUR), max(nDL, nDR))); float nearFactorSpread = lerp(nearSoft, nearPeak, 0.35); float blurRadiusPx = _NearBlurIntensity * nearFactorSpread * nvgMask; if (blurRadiusPx > 0.001) { const int maxKernelRadius = 4; // 7x7 max int kernelRadius = clamp((int)round(_NearBlurKernel), 1, maxKernelRadius); float2 texel = _MainTex_TexelSize.xy; float sampleScale = blurRadiusPx / kernelRadius; float sigma = max(blurRadiusPx * 0.5, 0.75); float invTwoSigma2 = 0.5 / (sigma * sigma); float4 g = 0; float wsum = 0; [unroll] for (int ky = -maxKernelRadius; ky <= maxKernelRadius; ky++) { [unroll] for (int kx = -maxKernelRadius; kx <= maxKernelRadius; kx++) { if (abs(kx) > kernelRadius || abs(ky) > kernelRadius) { continue; } float2 k = float2(kx, ky); float w = exp(-dot(k, k) * invTwoSigma2); float2 suv = clamp(warpedUv + k * texel * sampleScale, 0.0, 1.0); g += tex2D(_MainTex, suv) * w; wsum += w; } } float4 blurred = g / max(wsum, 1e-5); float blurBlend = smoothstep(0.0, 0.35, nearFactorSpread); tmp0 = lerp(tmp0, blurred, blurBlend); } } noise *= _NoiseIntensity.xxxx; noise *= nvgMask; float4 tmp1 = tmp0; tmp1.x += tmp1.y; tmp1.x += tmp1.z; tmp1 = noise + tmp1.xxxx * _Color; tmp1 *= _Intensity.xxxx; tmp1 = saturate(tmp1 * 0.45); tmp0 = lerp(tmp0, tmp1, nvgMask); o.sv_target = tmp0; return o; } ENDCG } } Fallback "Hidden/Internal-BlackError" }