Move debanding into internal sky shader code so that it is applied after everything else.

This ensures that the debanding does not scale with exposure or any other effect.
This commit is contained in:
clayjohn 2022-09-13 10:39:04 -07:00
parent 22a09fef5d
commit 8fa76a5272
7 changed files with 73 additions and 46 deletions

View file

@ -104,6 +104,15 @@ uniform uint directional_light_count;
layout(location = 0) out vec4 frag_color;
#ifdef USE_DEBANDING
// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
vec3 interleaved_gradient_noise(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
return vec3(res, -res, res) / 255.0;
}
#endif
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
@ -168,4 +177,8 @@ void main() {
frag_color.rgb = color;
frag_color.a = alpha;
#ifdef USE_DEBANDING
frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy);
#endif
}

View file

@ -1715,6 +1715,7 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;

View file

@ -34,7 +34,7 @@
#include "core/version.h"
Mutex ProceduralSkyMaterial::shader_mutex;
RID ProceduralSkyMaterial::shader;
RID ProceduralSkyMaterial::shader_cache[2];
void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
sky_top_color = p_sky_top;
@ -147,7 +147,11 @@ float ProceduralSkyMaterial::get_sun_curve() const {
void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
_update_shader();
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
}
}
bool ProceduralSkyMaterial::get_use_debanding() const {
@ -161,7 +165,8 @@ Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
RID ProceduralSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
@ -169,7 +174,7 @@ RID ProceduralSkyMaterial::get_rid() const {
RID ProceduralSkyMaterial::get_shader_rid() const {
_update_shader();
return shader;
return shader_cache[int(use_debanding)];
}
void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
@ -241,21 +246,24 @@ void ProceduralSkyMaterial::_bind_methods() {
}
void ProceduralSkyMaterial::cleanup_shader() {
if (shader.is_valid()) {
RS::get_singleton()->free(shader);
if (shader_cache[0].is_valid()) {
RS::get_singleton()->free(shader_cache[0]);
RS::get_singleton()->free(shader_cache[1]);
}
}
void ProceduralSkyMaterial::_update_shader() {
shader_mutex.lock();
if (shader.is_null()) {
shader = RS::get_singleton()->shader_create();
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader, R"(
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
shader_type sky;
%s
uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
@ -269,14 +277,6 @@ uniform float ground_curve : hint_range(0, 1) = 0.02;
uniform float ground_energy = 1.0;
uniform float sun_angle_max = 30.0;
uniform float sun_curve : hint_range(0, 1) = 0.15;
uniform bool use_debanding = true;
// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
vec3 interleaved_gradient_noise(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
return vec3(res, -res, res) / 255.0;
}
void sky() {
float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
@ -332,11 +332,10 @@ void sky() {
ground *= ground_energy;
COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
if (use_debanding) {
COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
}
}
)");
)",
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();
}
@ -546,7 +545,11 @@ float PhysicalSkyMaterial::get_energy_multiplier() const {
void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
_update_shader();
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
}
}
bool PhysicalSkyMaterial::get_use_debanding() const {
@ -570,7 +573,8 @@ Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
RID PhysicalSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
@ -578,7 +582,7 @@ RID PhysicalSkyMaterial::get_rid() const {
RID PhysicalSkyMaterial::get_shader_rid() const {
_update_shader();
return shader;
return shader_cache[int(use_debanding)];
}
void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
@ -588,7 +592,7 @@ void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
}
Mutex PhysicalSkyMaterial::shader_mutex;
RID PhysicalSkyMaterial::shader;
RID PhysicalSkyMaterial::shader_cache[2];
void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
@ -642,21 +646,24 @@ void PhysicalSkyMaterial::_bind_methods() {
}
void PhysicalSkyMaterial::cleanup_shader() {
if (shader.is_valid()) {
RS::get_singleton()->free(shader);
if (shader_cache[0].is_valid()) {
RS::get_singleton()->free(shader_cache[0]);
RS::get_singleton()->free(shader_cache[1]);
}
}
void PhysicalSkyMaterial::_update_shader() {
shader_mutex.lock();
if (shader.is_null()) {
shader = RS::get_singleton()->shader_create();
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader, R"(
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
shader_type sky;
%s
uniform float rayleigh : hint_range(0, 64) = 2.0;
uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
@ -668,7 +675,6 @@ uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
uniform float exposure : hint_range(0, 128) = 1.0;
uniform bool use_debanding = true;
uniform sampler2D night_sky : source_color, hint_default_black;
@ -683,13 +689,6 @@ float henyey_greenstein(float cos_theta, float g) {
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
}
// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
vec3 interleaved_gradient_noise(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
return vec3(res, -res, res) / 255.0;
}
void sky() {
if (LIGHT0_ENABLED) {
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
@ -737,16 +736,15 @@ void sky() {
vec3 color = Lin + L0;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
if (use_debanding) {
COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
}
} else {
// There is no sun, so display night_sky and nothing else.
COLOR = texture(night_sky, SKY_COORDS).xyz;
COLOR *= exposure;
}
}
)");
)",
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();

View file

@ -55,7 +55,7 @@ private:
bool use_debanding = true;
static Mutex shader_mutex;
static RID shader;
static RID shader_cache[2];
static void _update_shader();
mutable bool shader_set = false;
@ -160,7 +160,7 @@ class PhysicalSkyMaterial : public Material {
private:
static Mutex shader_mutex;
static RID shader;
static RID shader_cache[2];
float rayleigh = 0.0f;
Color rayleigh_color;

View file

@ -907,6 +907,7 @@ void SkyRD::init() {
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;

View file

@ -153,6 +153,15 @@ layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
layout(location = 0) out vec4 frag_color;
#ifdef USE_DEBANDING
// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
vec3 interleaved_gradient_noise(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
return vec3(res, -res, res) / 255.0;
}
#endif
vec4 volumetric_fog_process(vec2 screen_uv) {
vec3 fog_pos = vec3(screen_uv, 1.0);
@ -252,4 +261,8 @@ void main() {
// For mobile renderer we're multiplying by 0.5 as we're using a UNORM buffer.
// For both mobile and clustered, we also bake in the exposure value for the environment and camera.
frag_color.rgb = frag_color.rgb * params.luminance_multiplier;
#ifdef USE_DEBANDING
frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy);
#endif
}

View file

@ -444,6 +444,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_half_res_pass") });
shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_quarter_res_pass") });
shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("disable_fog") });
shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_debanding") });
}
/************ FOG **************************/