From 2bc2ab43a1c3994fd58dfa25e7db57cdd8551466 Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:12:11 +0000 Subject: [PATCH 1/6] Update leenkx/Shaders/std/tonemap.glsl --- leenkx/Shaders/std/tonemap.glsl | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/leenkx/Shaders/std/tonemap.glsl b/leenkx/Shaders/std/tonemap.glsl index 2d87c87..6258047 100644 --- a/leenkx/Shaders/std/tonemap.glsl +++ b/leenkx/Shaders/std/tonemap.glsl @@ -89,3 +89,52 @@ vec3 tonemapAgXFull(vec3 x) { x = clamp(x, 0.0, 1.0); return pow(x, vec3(1.0/2.2)); } + + +// Interleaved Gradient Noise (Pseudo-random, AKA Blue Noise style) +// Based on http://momentsingraphics.de/BlueNoise.html +float ditherBlueNoiseStyle(vec2 p) { + return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5453123); +} + +// White Noise Dithering +float ditherWhiteNoise(vec2 p) { + return fract(sin(dot(p, vec2(12.9898, 4.1414))) * 43758.5453); +} + +// Ordered Dithering (4x4 Bayer Matrix) +float ditherOrderedBayer4x4(ivec2 p) { + const float bayer[16] = float[16]( + 0.0, 8.0, 2.0, 10.0, + 12.0, 4.0, 14.0, 6.0, + 3.0, 11.0, 1.0, 9.0, + 15.0, 7.0, 13.0, 5.0 + ); + int index = (p.x % 4) * 4 + (p.y % 4); + return bayer[index] / 16.0; +} + +// Ordered Dithering (8x8 Bayer Matrix) +float ditherOrderedBayer8x8(ivec2 p) { + const float bayer8x8[64] = float[64]( + 0.0, 32.0, 8.0, 40.0, 2.0, 34.0, 10.0, 42.0, + 48.0, 16.0, 56.0, 24.0, 50.0, 18.0, 58.0, 26.0, + 12.0, 44.0, 4.0, 36.0, 14.0, 46.0, 6.0, 38.0, + 60.0, 28.0, 52.0, 20.0, 62.0, 30.0, 54.0, 22.0, + 3.0, 35.0, 11.0, 43.0, 1.0, 33.0, 9.0, 41.0, + 51.0, 19.0, 59.0, 27.0, 49.0, 17.0, 57.0, 25.0, + 15.0, 47.0, 7.0, 39.0, 13.0, 45.0, 5.0, 37.0, + 63.0, 31.0, 55.0, 23.0, 61.0, 29.0, 53.0, 21.0 + ); + int index = (p.x % 8) * 8 + (p.y % 8); + return bayer8x8[index] / 64.0; +} + + +//vec3 applyDither(vec3 color, vec2 screenCoord) { +// float quantizationLevels = 255.0; +// float noise = randomDither(screenCoord); +// float noiseOffset = (noise - 0.5) / quantizationLevels; +// vec3 ditheredColor = color + noiseOffset; +// return clamp(ditheredColor, 0.0, 1.0); +//} From 4805dd06a78aa10057caef65566f9b8fffe68f11 Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:14:52 +0000 Subject: [PATCH 2/6] Update leenkx/Shaders/compositor_pass/compositor_pass.frag.glsl --- .../compositor_pass/compositor_pass.frag.glsl | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/leenkx/Shaders/compositor_pass/compositor_pass.frag.glsl b/leenkx/Shaders/compositor_pass/compositor_pass.frag.glsl index 4dd8525..ac38670 100644 --- a/leenkx/Shaders/compositor_pass/compositor_pass.frag.glsl +++ b/leenkx/Shaders/compositor_pass/compositor_pass.frag.glsl @@ -625,4 +625,37 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5); #ifdef _CLUT fragColor = LUTlookup(fragColor, lutTexture); #endif + + +#ifdef _CDitheringBlueNoise + const float ditherStrength = ditherStrengthValue / 255.0; + float noise = ditherBlueNoiseStyle(gl_FragCoord.xy); + float noiseOffset = (noise - 0.5) * ditherStrength; + fragColor.rgb += noiseOffset; +#endif + +#ifdef _CDitheringWhiteNoise + const float ditherStrength = ditherStrengthValue / 255.0; + float noise = ditherWhiteNoise(gl_FragCoord.xy); + float noiseOffset = (noise - 0.5) * ditherStrength; + fragColor.rgb += noiseOffset; +#endif + +#ifdef _CDitheringOrderedBayer4x4 + const float ditherStrength = ditherStrengthValue / 255.0; + float noise = ditherOrderedBayer4x4(ivec2(gl_FragCoord.xy)); + float noiseOffset = (noise - 0.5) * ditherStrength; + fragColor.rgb += noiseOffset; +#endif + +#ifdef _CDitheringOrderedBayer8x8 + const float ditherStrength = ditherStrengthValue / 255.0; + float noise = ditherOrderedBayer8x8(ivec2(gl_FragCoord.xy)); + float noiseOffset = (noise - 0.5) * ditherStrength; + fragColor.rgb += noiseOffset; +#endif + + //fragColor.rgb = clamp(fragColor.rgb, 0.0, 1.0); + + } From 2c5c8d0e4f6ce2b0ad75ba098e7367796c9ca2fc Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:16:29 +0000 Subject: [PATCH 3/6] Update leenkx/blender/lnx/props_renderpath.py --- leenkx/blender/lnx/props_renderpath.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/leenkx/blender/lnx/props_renderpath.py b/leenkx/blender/lnx/props_renderpath.py index ee3fa75..27889fc 100644 --- a/leenkx/blender/lnx/props_renderpath.py +++ b/leenkx/blender/lnx/props_renderpath.py @@ -617,6 +617,20 @@ class LnxRPListItem(bpy.types.PropertyGroup): ('AgXSimple', 'AgX', 'AgX Implementation')], # ('AgXFull', 'AgX (Full)', 'AgX Full Implementation')], name='Tonemap', description='Tonemapping operator', default='Filmic', update=assets.invalidate_shader_cache) + lnx_dithering: EnumProperty( + items=[('Off', 'Off', 'Off'), + ('BlueNoise', 'Blue Noise', 'Blue Noise'), + ('WhiteNoise', 'White Noise', 'White Noise'), + ('OrderedBayer4x4', 'Ordered Bayer 4x4', 'Ordered Bayer 4x4'), + ('OrderedBayer8x8', 'Ordered Bayer 8x8', 'Ordered Bayer 8x8')], + name='Dithering', description='Dithering operator', default='Off') + lnx_dithering_strength: FloatProperty( + name="Dither Strength", + description="Strength of the dithering effect (applied as offset / 255.0)", + default=1.0, + min=0.0, + max=1000.0 + ) lnx_fisheye: BoolProperty(name="Fish Eye", default=False, update=assets.invalidate_shader_cache) lnx_vignette: BoolProperty(name="Vignette", default=False, update=assets.invalidate_shader_cache) lnx_vignette_strength: FloatProperty(name="Strength", default=0.7, update=assets.invalidate_shader_cache) From 8765e894f5fea81dd84f16fb84a1efc585eea03c Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:17:23 +0000 Subject: [PATCH 4/6] Update leenkx/blender/lnx/props_ui.py --- leenkx/blender/lnx/props_ui.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/leenkx/blender/lnx/props_ui.py b/leenkx/blender/lnx/props_ui.py index 7825268..13cd854 100644 --- a/leenkx/blender/lnx/props_ui.py +++ b/leenkx/blender/lnx/props_ui.py @@ -1974,6 +1974,11 @@ class LNX_PT_RenderPathCompositorPanel(bpy.types.Panel): layout.enabled = rpdat.rp_compositornodes layout.prop(rpdat, 'lnx_tonemap') + layout.prop(rpdat, 'lnx_dithering') + if rpdat.lnx_dithering != 'Off': + row = layout.row(align=True) + row.prop(rpdat, 'lnx_dithering_strength') + layout.separator() col = layout.column() From c3435b9533581037c7812239dec6dca2dec21ae0 Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:19:28 +0000 Subject: [PATCH 5/6] Update leenkx/blender/lnx/write_data.py --- leenkx/blender/lnx/write_data.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/leenkx/blender/lnx/write_data.py b/leenkx/blender/lnx/write_data.py index 9164514..415b331 100644 --- a/leenkx/blender/lnx/write_data.py +++ b/leenkx/blender/lnx/write_data.py @@ -677,6 +677,12 @@ const float waterDensity = """ + str(round(rpdat.lnx_water_density * 100) / 100) const float waterRefract = """ + str(round(rpdat.lnx_water_refract * 100) / 100) + """; const float waterReflect = """ + str(round(rpdat.lnx_water_reflect * 100) / 100) + """; """) + + if '_CDitheringStrength' in defs: + f.write( + f'const float ditherStrengthValue = {rpdat.lnx_dithering_strength};\n' + ) + if rpdat.rp_ssgi == 'SSAO' or rpdat.rp_ssgi == 'RTAO' or rpdat.rp_volumetriclight: f.write( """const float ssaoRadius = """ + str(round(rpdat.lnx_ssgi_radius * 100) / 100) + """; From 30e5acf9bf358f33291eed1053fd84b9187f5ce4 Mon Sep 17 00:00:00 2001 From: LeenkxTeam Date: Mon, 7 Apr 2025 21:20:53 +0000 Subject: [PATCH 6/6] Update leenkx/blender/lnx/make_renderpath.py --- leenkx/blender/lnx/make_renderpath.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/leenkx/blender/lnx/make_renderpath.py b/leenkx/blender/lnx/make_renderpath.py index 5576c99..cff51f1 100644 --- a/leenkx/blender/lnx/make_renderpath.py +++ b/leenkx/blender/lnx/make_renderpath.py @@ -217,8 +217,12 @@ def build(): if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False + # wrd.compo_defs += '' if rpdat.lnx_tonemap != 'Off': - wrd.compo_defs = '_CTone' + rpdat.lnx_tonemap + wrd.compo_defs += '_CTone' + rpdat.lnx_tonemap + if rpdat.lnx_dithering != 'Off': + wrd.compo_defs += '_CDithering' + rpdat.lnx_dithering + wrd.compo_defs += '_CDitheringStrength' if rpdat.rp_antialiasing == 'FXAA': wrd.compo_defs += '_CFXAA' if rpdat.lnx_letterbox: