Mortars, Mag Check Reload, bNVGs, fake shadows
BIN
BepInEx/plugins/BorkelRNVG/Assets/CommonAssets/noise.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/CommonAssets/pixel_mask.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 39 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/MaskTextures/mask_anvis.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 50 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/MaskTextures/mask_pnv.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/MaskTextures/mask_thermal.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
|
|
@ -0,0 +1,8 @@
|
||||||
|
replacement textures for NVG/Thermal overlays
|
||||||
|
|
||||||
|
copy & paste these into:
|
||||||
|
Assets/NVG/[nvg of your choice]
|
||||||
|
or
|
||||||
|
Assets/Thermal/[thermal of your choice]
|
||||||
|
|
||||||
|
be sure to rename to mask.png and replace the original file
|
||||||
19
BepInEx/plugins/BorkelRNVG/Assets/NVG/gpnvg/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"itemId": "5c0558060db834001b735271",
|
||||||
|
"category": "GPNVG-18",
|
||||||
|
"gain": 2.5,
|
||||||
|
"noiseIntensity": 0.2,
|
||||||
|
"noiseSize": 0.1,
|
||||||
|
"maskSize": 0.96,
|
||||||
|
"red": 152,
|
||||||
|
"green": 214,
|
||||||
|
"blue": 252,
|
||||||
|
"gatingType": "AutoGating",
|
||||||
|
"gatingSpeed": 0.3,
|
||||||
|
"minBrightness": 0.2,
|
||||||
|
"maxBrightness": 1,
|
||||||
|
"minBrightnessThreshold": 0,
|
||||||
|
"maxBrightnessThreshold": 0.15,
|
||||||
|
"edgeDistortion": 0.02,
|
||||||
|
"edgeDistortionStart": 0.04
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/gpnvg/lens.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/gpnvg/mask.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
19
BepInEx/plugins/BorkelRNVG/Assets/NVG/n15/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"itemId": "5c066e3a0db834001b7353f0",
|
||||||
|
"category": "N-15",
|
||||||
|
"gain": 2.1,
|
||||||
|
"noiseIntensity": 0.25,
|
||||||
|
"noiseSize": 0.15,
|
||||||
|
"maskSize": 1.0,
|
||||||
|
"red": 60,
|
||||||
|
"green": 235,
|
||||||
|
"blue": 100,
|
||||||
|
"gatingType": "AutoGain",
|
||||||
|
"gatingSpeed": 0.3,
|
||||||
|
"minBrightness": 0.2,
|
||||||
|
"maxBrightness": 1,
|
||||||
|
"minBrightnessThreshold": 0,
|
||||||
|
"maxBrightnessThreshold": 0.15,
|
||||||
|
"edgeDistortion": 0.1,
|
||||||
|
"edgeDistortionStart": 0.2
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/n15/lens.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/n15/mask.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
19
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv10t/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"itemId": "5c0696830db834001d23f5da",
|
||||||
|
"category": "PNV-10T",
|
||||||
|
"gain": 1.6,
|
||||||
|
"noiseIntensity": 0.3,
|
||||||
|
"noiseSize": 0.2,
|
||||||
|
"maskSize": 1.0,
|
||||||
|
"red": 60,
|
||||||
|
"green": 210,
|
||||||
|
"blue": 60,
|
||||||
|
"gatingType": "Off",
|
||||||
|
"gatingSpeed": 0.3,
|
||||||
|
"minBrightness": 0.2,
|
||||||
|
"maxBrightness": 1,
|
||||||
|
"minBrightnessThreshold": 0,
|
||||||
|
"maxBrightnessThreshold": 0.15,
|
||||||
|
"edgeDistortion": 0.15,
|
||||||
|
"edgeDistortionStart": 0.3
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv10t/lens.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv10t/mask.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
19
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv57e/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"itemId": "67506ca81f18589016006aa6",
|
||||||
|
"category": "PNV-57E",
|
||||||
|
"gain": 1.2,
|
||||||
|
"noiseIntensity": 0.35,
|
||||||
|
"noiseSize": 0.2,
|
||||||
|
"maskSize": 1.0,
|
||||||
|
"red": 80,
|
||||||
|
"green": 215,
|
||||||
|
"blue": 60,
|
||||||
|
"gatingType": "Off",
|
||||||
|
"gatingSpeed": 0.3,
|
||||||
|
"minBrightness": 0.2,
|
||||||
|
"maxBrightness": 1,
|
||||||
|
"minBrightnessThreshold": 0,
|
||||||
|
"maxBrightnessThreshold": 0.15,
|
||||||
|
"edgeDistortion": 0.55,
|
||||||
|
"edgeDistortionStart": 0.5
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv57e/lens.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pnv57e/mask.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
19
BepInEx/plugins/BorkelRNVG/Assets/NVG/pvs14/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"itemId": "57235b6f24597759bf5a30f1",
|
||||||
|
"category": "PVS-14",
|
||||||
|
"gain": 2.4,
|
||||||
|
"noiseIntensity": 0.2,
|
||||||
|
"noiseSize": 0.1,
|
||||||
|
"maskSize": 1,
|
||||||
|
"red": 95,
|
||||||
|
"green": 210,
|
||||||
|
"blue": 255,
|
||||||
|
"gatingType": "AutoGating",
|
||||||
|
"gatingSpeed": 0.3,
|
||||||
|
"minBrightness": 0.2,
|
||||||
|
"maxBrightness": 1,
|
||||||
|
"minBrightnessThreshold": 0,
|
||||||
|
"maxBrightnessThreshold": 0.15,
|
||||||
|
"edgeDistortion": 0.02,
|
||||||
|
"edgeDistortionStart": 0.04
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pvs14/lens.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/NVG/pvs14/mask.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
|
@ -0,0 +1,251 @@
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/Shaders/pein_shaders
Normal file
BIN
BepInEx/plugins/BorkelRNVG/Assets/Sounds/gatingKnob.wav
Normal file
BIN
BepInEx/plugins/BorkelRNVG/Assets/Sounds/gatingKnob_alt.wav
Normal file
10
BepInEx/plugins/BorkelRNVG/Assets/Thermal/t7/config.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"itemId": "5c110624d174af029e69734c",
|
||||||
|
"category": "T-7 Thermal",
|
||||||
|
"isFpsStuck": true,
|
||||||
|
"minFps": 60,
|
||||||
|
"maxFps": 60,
|
||||||
|
"isPixelated": true,
|
||||||
|
"isNoisy": false,
|
||||||
|
"isMotionBlurred": false
|
||||||
|
}
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/Assets/Thermal/t7/lens.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
BepInEx/plugins/BorkelRNVG/Assets/Thermal/t7/mask.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
303
BepInEx/plugins/BorkelRNVG/Assets/prebake_lens_masks.py
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
r"""
|
||||||
|
Prebake lens textures for edge distortion.
|
||||||
|
|
||||||
|
Output encoding per pixel (RGBA):
|
||||||
|
- R,G: direction to edge (encoded from [-1, 1] to [0, 255])
|
||||||
|
- B: normalized edge distance in [0, 255] where:
|
||||||
|
0 = near border
|
||||||
|
255 = far from border (or no hit in scan range)
|
||||||
|
- A: original alpha from source texture
|
||||||
|
|
||||||
|
This script reproduces the old shader-style directional scan:
|
||||||
|
- For each inside-mask pixel, cast rays in N directions.
|
||||||
|
- First ray hit against outside-mask gives distance sample.
|
||||||
|
- Direction is weighted average of hit directions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Iterable, List, Sequence, Tuple
|
||||||
|
# pip install pillow
|
||||||
|
# python .\prebake_lens_masks.py --input-dir .\LensTextures --output-dir .\LensTextures_prebaked --num-directions 8 --max-steps 450 --threshold 0.5
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="Prebake lens masks for NVG distortion.")
|
||||||
|
parser.add_argument("--input-dir", type=Path, default=Path("LensTextures"))
|
||||||
|
parser.add_argument("--output-dir", type=Path, default=Path("LensTextures_prebaked"))
|
||||||
|
parser.add_argument(
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
default=0.5,
|
||||||
|
help="Inside-mask threshold in [0,1] after alpha processing.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-invert-alpha",
|
||||||
|
action="store_true",
|
||||||
|
help="Use alpha directly. Default uses (1-alpha), matching your shader.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--max-steps",
|
||||||
|
type=int,
|
||||||
|
default=450,
|
||||||
|
help="Raymarch steps (old shader equivalent).",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--num-directions",
|
||||||
|
type=int,
|
||||||
|
default=16,
|
||||||
|
help="Direction count. Use 8 for old behavior, 16+ for higher quality.",
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def clamp01(v: float) -> float:
|
||||||
|
if v < 0.0:
|
||||||
|
return 0.0
|
||||||
|
if v > 1.0:
|
||||||
|
return 1.0
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def to_u8(v: float) -> int:
|
||||||
|
return int(max(0, min(255, round(v))))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_dirs(count: int) -> List[Tuple[float, float]]:
|
||||||
|
dirs: List[Tuple[float, float]] = []
|
||||||
|
for i in range(count):
|
||||||
|
a = (2.0 * math.pi * i) / count
|
||||||
|
dirs.append((math.cos(a), math.sin(a)))
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
|
||||||
|
def bilinear_sample(mask: Sequence[float], w: int, h: int, u: float, v: float) -> float:
|
||||||
|
u = clamp01(u)
|
||||||
|
v = clamp01(v)
|
||||||
|
|
||||||
|
x = u * w - 0.5
|
||||||
|
y = v * h - 0.5
|
||||||
|
|
||||||
|
x0 = int(math.floor(x))
|
||||||
|
y0 = int(math.floor(y))
|
||||||
|
x1 = x0 + 1
|
||||||
|
y1 = y0 + 1
|
||||||
|
|
||||||
|
if x0 < 0:
|
||||||
|
x0 = 0
|
||||||
|
if y0 < 0:
|
||||||
|
y0 = 0
|
||||||
|
if x1 >= w:
|
||||||
|
x1 = w - 1
|
||||||
|
if y1 >= h:
|
||||||
|
y1 = h - 1
|
||||||
|
|
||||||
|
fx = x - x0
|
||||||
|
fy = y - y0
|
||||||
|
|
||||||
|
i00 = y0 * w + x0
|
||||||
|
i10 = y0 * w + x1
|
||||||
|
i01 = y1 * w + x0
|
||||||
|
i11 = y1 * w + x1
|
||||||
|
|
||||||
|
s00 = mask[i00]
|
||||||
|
s10 = mask[i10]
|
||||||
|
s01 = mask[i01]
|
||||||
|
s11 = mask[i11]
|
||||||
|
|
||||||
|
sx0 = s00 + (s10 - s00) * fx
|
||||||
|
sx1 = s01 + (s11 - s01) * fx
|
||||||
|
return sx0 + (sx1 - sx0) * fy
|
||||||
|
|
||||||
|
|
||||||
|
def prebake_one(
|
||||||
|
src_path: Path,
|
||||||
|
out_dir: Path,
|
||||||
|
threshold: float,
|
||||||
|
invert_alpha: bool,
|
||||||
|
max_steps: int,
|
||||||
|
dirs: Sequence[Tuple[float, float]],
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
except ImportError as exc:
|
||||||
|
raise RuntimeError("Missing dependency: Pillow. Install with: pip install pillow") from exc
|
||||||
|
|
||||||
|
img = Image.open(src_path).convert("RGBA")
|
||||||
|
w, h = img.size
|
||||||
|
src = list(img.getdata())
|
||||||
|
|
||||||
|
alpha: List[int] = [px[3] for px in src]
|
||||||
|
mask: List[float] = []
|
||||||
|
inside: List[bool] = []
|
||||||
|
|
||||||
|
for a_u8 in alpha:
|
||||||
|
a = a_u8 / 255.0
|
||||||
|
m = (1.0 - a) if invert_alpha else a
|
||||||
|
mask.append(m)
|
||||||
|
inside.append(m > threshold)
|
||||||
|
|
||||||
|
du = 1.0 / w
|
||||||
|
dv = 1.0 / h
|
||||||
|
dir_count = len(dirs)
|
||||||
|
n = w * h
|
||||||
|
out: List[Tuple[int, int, int, int]] = [(0, 0, 0, 0)] * n
|
||||||
|
|
||||||
|
inside_count = 0
|
||||||
|
for y in range(h):
|
||||||
|
base = y * w
|
||||||
|
v0 = (y + 0.5) * dv
|
||||||
|
|
||||||
|
for x in range(w):
|
||||||
|
i = base + x
|
||||||
|
a_u8 = alpha[i]
|
||||||
|
|
||||||
|
if not inside[i]:
|
||||||
|
out[i] = (0, 0, 0, a_u8)
|
||||||
|
continue
|
||||||
|
|
||||||
|
inside_count += 1
|
||||||
|
u0 = (x + 0.5) * du
|
||||||
|
|
||||||
|
nearest_norm = 1.0
|
||||||
|
accum_x = 0.0
|
||||||
|
accum_y = 0.0
|
||||||
|
accum_w = 0.0
|
||||||
|
|
||||||
|
for dx, dy in dirs:
|
||||||
|
hit_norm = 1.0
|
||||||
|
ray_u = u0
|
||||||
|
ray_v = v0
|
||||||
|
step_u = dx * du
|
||||||
|
step_v = dy * dv
|
||||||
|
|
||||||
|
hit = False
|
||||||
|
for step in range(1, max_steps + 1):
|
||||||
|
ray_u += step_u
|
||||||
|
ray_v += step_v
|
||||||
|
m = bilinear_sample(mask, w, h, ray_u, ray_v)
|
||||||
|
if m <= threshold:
|
||||||
|
hit_norm = step / float(max_steps)
|
||||||
|
hit = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not hit:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if hit_norm < nearest_norm:
|
||||||
|
nearest_norm = hit_norm
|
||||||
|
|
||||||
|
wdir = 1.0 - hit_norm
|
||||||
|
wdir *= wdir
|
||||||
|
accum_x += dx * wdir
|
||||||
|
accum_y += dy * wdir
|
||||||
|
accum_w += wdir
|
||||||
|
|
||||||
|
if accum_w > 1e-8:
|
||||||
|
inv = 1.0 / accum_w
|
||||||
|
ex = accum_x * inv
|
||||||
|
ey = accum_y * inv
|
||||||
|
el = math.hypot(ex, ey)
|
||||||
|
if el > 1e-8:
|
||||||
|
ex /= el
|
||||||
|
ey /= el
|
||||||
|
else:
|
||||||
|
ex = 0.0
|
||||||
|
ey = 0.0
|
||||||
|
else:
|
||||||
|
ex = 0.0
|
||||||
|
ey = 0.0
|
||||||
|
|
||||||
|
r = to_u8((ex * 0.5 + 0.5) * 255.0)
|
||||||
|
g = to_u8((ey * 0.5 + 0.5) * 255.0)
|
||||||
|
b = to_u8(clamp01(nearest_norm) * 255.0)
|
||||||
|
out[i] = (r, g, b, a_u8)
|
||||||
|
|
||||||
|
print(f"[{src_path.name}] row {y + 1}/{h}", end="\r")
|
||||||
|
|
||||||
|
print(f"[{src_path.name}] rows done: {h}/{h} ")
|
||||||
|
|
||||||
|
out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
out_path = out_dir / f"{src_path.stem}.png"
|
||||||
|
out_img = Image.new("RGBA", (w, h))
|
||||||
|
out_img.putdata(out)
|
||||||
|
out_img.save(out_path)
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
"source": str(src_path),
|
||||||
|
"output": str(out_path),
|
||||||
|
"size": [w, h],
|
||||||
|
"inside_threshold": threshold,
|
||||||
|
"invert_alpha_used": invert_alpha,
|
||||||
|
"max_steps": max_steps,
|
||||||
|
"direction_count": dir_count,
|
||||||
|
"inside_pixels": inside_count,
|
||||||
|
"encoding": {
|
||||||
|
"R": "edge direction X encoded from [-1,1] -> [0,255]",
|
||||||
|
"G": "edge direction Y encoded from [-1,1] -> [0,255]",
|
||||||
|
"B": "nearest edge distance normalized [0,1] by max_steps",
|
||||||
|
"A": "original alpha",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
(out_dir / f"{src_path.stem}_prebaked.json").write_text(
|
||||||
|
json.dumps(meta, indent=2), encoding="utf-8"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
print(f"[OK] {src_path.name} -> {out_path.name}")
|
||||||
|
|
||||||
|
|
||||||
|
def iter_pngs(folder: Path) -> Iterable[Path]:
|
||||||
|
for p in sorted(folder.glob("*.png")):
|
||||||
|
if p.is_file():
|
||||||
|
yield p
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
input_dir: Path = args.input_dir
|
||||||
|
output_dir: Path = args.output_dir
|
||||||
|
threshold: float = float(args.threshold)
|
||||||
|
invert_alpha: bool = not args.no_invert_alpha
|
||||||
|
max_steps: int = int(args.max_steps)
|
||||||
|
num_directions: int = int(args.num_directions)
|
||||||
|
|
||||||
|
if not input_dir.exists():
|
||||||
|
raise FileNotFoundError(f"Input dir not found: {input_dir}")
|
||||||
|
if not (0.0 <= threshold <= 1.0):
|
||||||
|
raise ValueError("--threshold must be in [0,1]")
|
||||||
|
if max_steps <= 0:
|
||||||
|
raise ValueError("--max-steps must be > 0")
|
||||||
|
if num_directions < 4:
|
||||||
|
raise ValueError("--num-directions must be >= 4")
|
||||||
|
|
||||||
|
dirs = generate_dirs(num_directions)
|
||||||
|
pngs = list(iter_pngs(input_dir))
|
||||||
|
if not pngs:
|
||||||
|
print(f"No PNG files found in: {input_dir}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"Prebake config: dirs={len(dirs)}, max_steps={max_steps}, "
|
||||||
|
f"threshold={threshold}, invert_alpha={invert_alpha}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for src in pngs:
|
||||||
|
prebake_one(
|
||||||
|
src_path=src,
|
||||||
|
out_dir=output_dir,
|
||||||
|
threshold=threshold,
|
||||||
|
invert_alpha=invert_alpha,
|
||||||
|
max_steps=max_steps,
|
||||||
|
dirs=dirs,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Done. Wrote {len(pngs)} textures to: {output_dir}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
BIN
BepInEx/plugins/BorkelRNVG/BorkelRNVG.dll
Normal file
BIN
BepInEx/plugins/CloudSix/Assets/customclouds
Normal file
BIN
BepInEx/plugins/CloudSix/Assets/volumetricclouds
Normal file
BIN
BepInEx/plugins/CloudSix/CloudSix.dll
Normal file
BIN
BepInEx/plugins/MortarStrikes.dll
Normal file
BIN
BepInEx/plugins/ReduceFakeInteriorShadow.dll
Normal file
BIN
BepInEx/plugins/ozen-MagCheckInterrupt.Net.dll
Normal file
BIN
BepInEx/plugins/ozen-MagCheckInterrupt.dll
Normal file
BIN
SPT/user/mods/BorkelRNVGServer/BorkelRNVGServer.dll
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
place in "BRNVG_N-15Adapter\bundles\assets\content\items\equipment\customizable\gpnvg"
|
||||||
24
SPT/user/mods/BorkelRNVGServer/bundles.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"manifest": [
|
||||||
|
{
|
||||||
|
"key": "assets/content/items/equipment/customizable/gpnvg/nvg_l3_gpnvg-18_anvis.bundle",
|
||||||
|
"dependencyKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "assets/content/items/equipment/nvg_pvs14/pvs14_textures.bundle",
|
||||||
|
"dependencyKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "assets/content/items/equipment/customizable/pvs_14/nvg_pvs_14.bundle",
|
||||||
|
"dependencyKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "assets/content/items/equipment/customizable/nvg_armasight_n-15/nvg_armasight_n-15.bundle",
|
||||||
|
"dependencyKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "assets/content/items/equipment/customizable/nvg_alfa_pnv-10t/nvg_alfa_pnv-10t.bundle",
|
||||||
|
"dependencyKeys": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||