169 lines
7.2 KiB
PostScript
169 lines
7.2 KiB
PostScript
|
///////////////////////////////////////////////////////
|
||
|
// BEEF'S SHADER BASED NIGHT VISION EFFECT //
|
||
|
///////////////////////////////////////////////////////
|
||
|
// Huge credit TO LVutner from Anomaly Discord, who //
|
||
|
// literally taught me everything I know, to Sky4Ace //
|
||
|
// who's simple_blur function I've adapted for this //
|
||
|
// shader, and to Meltac, who provided some advice //
|
||
|
// and inspiration for developing this shader. //
|
||
|
///////////////////////////////////////////////////////
|
||
|
// Note: You are free to distribute and adapt this //
|
||
|
// Shader and any components, just please provide //
|
||
|
// credit to myself and/or the above individuals. I //
|
||
|
// have provided credit for individual functions and //
|
||
|
// their original authors where applicable. - BEEF //
|
||
|
///////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////
|
||
|
// STEP 0 - GLOBAL DEFINITIONS AND INCLUDES
|
||
|
///////////////////////////////////////////////////////
|
||
|
|
||
|
#include "night_vision.h"
|
||
|
#include "common.h"
|
||
|
|
||
|
float3 bokeh_pass_3 (float image, float2 tc)
|
||
|
{
|
||
|
float Pi = 6.28318530718; float blur_directions = 8.0; float blur_quality = 4.0; float blur_radius = 5; float3 color = 0.0f; float3 color_average = 0.0f;
|
||
|
float light_avgs = 0.0f; float weight = 0.0f; float total_weight = 0.0f;
|
||
|
for(float i=1.0; i<=blur_quality; i++) { for( float d=0.0; d<Pi; d+=Pi/blur_directions) {
|
||
|
color = s_blur_8.SampleLevel(smp_rtlinear, tc + (float2(cos(d),sin(d))*blur_radius*i/screen_res.xy),0).rgb;
|
||
|
color += s_blur_4.SampleLevel(smp_rtlinear, tc + (float2(cos(d),sin(d))*blur_radius*i/screen_res.xy),0).rgb;
|
||
|
if (color.g > 0.0f) { color.g *= 1.0f; light_avgs += 1.0f;} else {light_avgs += 0.5;} color_average += color; } } image = color_average.g / light_avgs;
|
||
|
return image;
|
||
|
}
|
||
|
|
||
|
|
||
|
float4 main(p_screen I) : SV_Target
|
||
|
{
|
||
|
///////////////////////////////////////////////////////
|
||
|
// STEP 0 - LOCAL DEFINITIONS
|
||
|
///////////////////////////////////////////////////////
|
||
|
|
||
|
// TC vars
|
||
|
float2 corrected_texturecoords = aspect_ratio_correction(I.tc0);
|
||
|
|
||
|
///////////////////////////////////////////////////////
|
||
|
// STEP 0 - MAIN SAMPLES
|
||
|
///////////////////////////////////////////////////////
|
||
|
float3 image = s_image.Sample(smp_rtlinear, I.tc0).xyz;
|
||
|
///////////////////////////////////////////////////////
|
||
|
// STEP 0 - MAIN FUNCTION
|
||
|
///////////////////////////////////////////////////////
|
||
|
float3 half_res_blur = s_blur_2.Sample(smp_rtlinear, I.tc0).rgb;
|
||
|
|
||
|
float lua_param_nvg_num_tubes = frac(shader_param_8.x) * 10.0f;
|
||
|
if (compute_lens_mask(corrected_texturecoords, lua_param_nvg_num_tubes) == 1) // see if we're inside the lens mask
|
||
|
{
|
||
|
image.r = max(max(image.r, image.g), image.b);
|
||
|
// GRAB SAMPLES FOR NVG SHADER
|
||
|
float3 eighth_res_bloom = s_blur_8.Sample(smp_rtlinear, I.tc0).rgb;
|
||
|
float3 quarter_res_bloom = s_blur_4.Sample(smp_rtlinear, I.tc0).rgb;
|
||
|
|
||
|
float4 jitter = float4(
|
||
|
frac(sin(dot(I.tc0, float2(12.0, 78.0) + (timers.x) )) * 12345.0),
|
||
|
frac(sin(dot(I.tc0-fmod(I.tc0,float2(3.0,3.0)/screen_res.xy), float2(12.0, 78.0) + (timers.x) )) * 22738.0),
|
||
|
frac(sin(dot(I.tc0-fmod(I.tc0,float2(3.0,3.0)/screen_res.xy), float2(12.0, 78.0) + (timers.x) )) * 78372.0),
|
||
|
frac(sin(dot(I.tc0, float2(12.0, 78.0) + (timers.x) )) * 37857.0));
|
||
|
|
||
|
//float depth = s_position.Load(int3(I.tc0 * screen_res.xy,0),0).z; // Sample the depth buffer in a better way
|
||
|
//float depth = pow(blurred_depth(I.tc0),2)*1000;
|
||
|
float depth = blurred_depth(I.tc0);
|
||
|
|
||
|
//image.r = lerp(half_res_blur.r,image.r,0.6f);
|
||
|
image = pow(image,0.85);
|
||
|
|
||
|
image = lerp(image,half_res_blur,clamp(1-smoothstep(0,15,depth),0.2,1)); // NEAR BLUR
|
||
|
|
||
|
if (depth < 1000)
|
||
|
{
|
||
|
float light_att = pow(1.0f-(smoothstep(5,300,depth)),0.5); // Distance from full brightness to full black
|
||
|
if ((image.r+image.g) < 0.9f)
|
||
|
{
|
||
|
image.r *= (light_att+0.1f); //Apply light attenuation (plus offset to prevent sky turning black)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GLITCH EFFECT -- TO DO
|
||
|
float lua_param_glitch_power = fmod(shader_param_8.z,1.0f);
|
||
|
if (lua_param_glitch_power > 0.0f)
|
||
|
{
|
||
|
image = lerp(image, glitchEffect(image, I.tc0, lua_param_glitch_power),0.9);
|
||
|
}
|
||
|
|
||
|
// APPLY BLOOM / WASHOUT
|
||
|
float addon = eighth_res_bloom.g + quarter_res_bloom.g;
|
||
|
addon = uprise_zero(addon, 0.7, 1.0);
|
||
|
addon = bokeh_pass_3(addon, I.tc0);
|
||
|
image = image + (float3)addon * gen_3_bloom_multiplier;
|
||
|
|
||
|
// APPLY CRT EFFECT
|
||
|
image = lerp(image,make_crt_ified(half_res_blur, I.tc0),gen_3_crt_effect_factor); // Adds a CRT effect that I think looks better than draw_scanlines
|
||
|
|
||
|
// APPLY NOISE
|
||
|
float lua_param_nvg_gain_current = floor(shader_param_8.y) / 10.0f;
|
||
|
image.r += jitter.y * (gen_3_nvg_noise_factor * (pow(lua_param_nvg_gain_current,0.5) )); // Add the noise to the image
|
||
|
|
||
|
// APPLY SCINTILLATION EFFECT
|
||
|
float scintillation_current = gain_dynamic_value(gen_3_scintillation_threshold_lowgain, gen_3_scintillation_threshold_highgain, lua_param_nvg_gain_current);
|
||
|
if (jitter.z > (gen_3_scintillation_constant - ( (1.0-gen_3_scintillation_constant) * (lua_param_nvg_gain_current - 1.0f) ) ) && image.r < scintillation_current)
|
||
|
{ image.r = scintillation_current; }
|
||
|
|
||
|
|
||
|
// APPLY IMAGE COLOR CORRECTION AND MAKE BRIGHT SPOTS WHITE
|
||
|
image.rgb = saturate(image.r) * gen_3_saturation_color;
|
||
|
image.r = uprise(image.r, gen_3_saturation_color.r * 0.99, gen_3_saturation_color.r);
|
||
|
image.g = uprise(image.g, gen_3_saturation_color.g * 0.99, gen_3_saturation_color.g);
|
||
|
image.b = uprise(image.b, gen_3_saturation_color.b * 0.99, gen_3_saturation_color.b);
|
||
|
|
||
|
// LOWERING CONTRAST
|
||
|
float contrast_current = gain_dynamic_value(gen_3_lowest_contrast_lowgain, gen_3_lowest_contrast_highgain, lua_param_nvg_gain_current);
|
||
|
image.r = low_up(image.r, contrast_current * gen_3_saturation_color.r);
|
||
|
image.g = low_up(image.g, contrast_current * gen_3_saturation_color.g);
|
||
|
image.b = low_up(image.b, contrast_current * gen_3_saturation_color.b);
|
||
|
|
||
|
// APPLY VIGNETTE
|
||
|
float lua_param_vignette_current = floor(shader_param_8.z) / 100.0f;
|
||
|
float vignette = calc_vignette(lua_param_nvg_num_tubes, I.tc0, lua_param_vignette_current);
|
||
|
image = clamp(image,0.0,1.0);
|
||
|
image *= vignette;
|
||
|
|
||
|
// RETURN THE RESULTING IMAGE
|
||
|
return float4(image, 1.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////
|
||
|
// OUTSIDE NVG CIRCLES OF EFFECT - If the absolute distance from screen center is farther than circle_radius, then we'll run the other shader effects below
|
||
|
///////////////////////////////////////////////////////
|
||
|
else
|
||
|
{
|
||
|
float lua_param_nvg_mode = frac(shader_param_8.w) * 10;
|
||
|
|
||
|
if (abs(lua_param_nvg_mode-0.0) <= 0.01) // mode 0 - blur
|
||
|
{
|
||
|
image = half_res_blur;
|
||
|
image = clamp(image,0.0,1.0);
|
||
|
}
|
||
|
else if (abs(lua_param_nvg_mode-1.0) <= 0.01) // mode 1 - black
|
||
|
{
|
||
|
image = float3(0.0,0.0,0.0);
|
||
|
}
|
||
|
else if (abs(lua_param_nvg_mode-2.0) <= 0.01) // mode 2 - image overlay
|
||
|
{
|
||
|
image = clamp(image,0.0,1.0);
|
||
|
}
|
||
|
else if (abs(lua_param_nvg_mode-3.0) <= 0.01) // mode 3 - no changes (clear vision)
|
||
|
{
|
||
|
image = clamp(image,0.0,1.0);
|
||
|
float vignette = calc_vignette(lua_param_nvg_num_tubes, I.tc0, -gen_3_out_vignette);
|
||
|
image *= vignette;
|
||
|
}
|
||
|
|
||
|
// RETURN THE RESULTING IMAGE
|
||
|
return float4(image, 1.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|