spt/BepInEx/plugins/BorkelRNVG/Assets/Shaders/CustomNightVision.shader

251 lines
7.9 KiB
GLSL

// 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"
}