filter: Add Khronos PBR Neutral tonemapping operator
Closes #1661 Fixes #1659 Co-authored-by: Raytopia <54505044+raytopianprojects@users.noreply.github.com>
This commit is contained in:
parent
822d35d15b
commit
42e2659636
|
|
@ -99,9 +99,15 @@ void fshader(out float4 o_color : COLOR,
|
|||
"""
|
||||
|
||||
|
||||
class ToneMap:
|
||||
ACES = object()
|
||||
PBR_NEUTRAL = object()
|
||||
|
||||
|
||||
class FilterConfig:
|
||||
pass
|
||||
|
||||
|
||||
class CommonFilters:
|
||||
|
||||
""" Class CommonFilters implements certain common image postprocessing
|
||||
|
|
@ -279,16 +285,19 @@ class CommonFilters:
|
|||
|
||||
text = "//Cg\n"
|
||||
if "HighDynamicRange" in configuration:
|
||||
text += "static const float3x3 aces_input_mat = {\n"
|
||||
text += " {0.59719, 0.35458, 0.04823},\n"
|
||||
text += " {0.07600, 0.90834, 0.01566},\n"
|
||||
text += " {0.02840, 0.13383, 0.83777},\n"
|
||||
text += "};\n"
|
||||
text += "static const float3x3 aces_output_mat = {\n"
|
||||
text += " { 1.60475, -0.53108, -0.07367},\n"
|
||||
text += " {-0.10208, 1.10813, -0.00605},\n"
|
||||
text += " {-0.00327, -0.07276, 1.07602},\n"
|
||||
text += "};\n"
|
||||
tonemap = configuration["HighDynamicRange"]
|
||||
if tonemap is ToneMap.ACES:
|
||||
text += "static const float3x3 aces_input_mat = {\n"
|
||||
text += " {0.59719, 0.35458, 0.04823},\n"
|
||||
text += " {0.07600, 0.90834, 0.01566},\n"
|
||||
text += " {0.02840, 0.13383, 0.83777},\n"
|
||||
text += "};\n"
|
||||
text += "static const float3x3 aces_output_mat = {\n"
|
||||
text += " { 1.60475, -0.53108, -0.07367},\n"
|
||||
text += " {-0.10208, 1.10813, -0.00605},\n"
|
||||
text += " {-0.00327, -0.07276, 1.07602},\n"
|
||||
text += "};\n"
|
||||
|
||||
text += "void vshader(float4 vtx_position : POSITION,\n"
|
||||
text += " out float4 l_position : POSITION,\n"
|
||||
|
||||
|
|
@ -381,10 +390,30 @@ class CommonFilters:
|
|||
if ("ExposureAdjust" in configuration):
|
||||
text += " o_color.rgb *= k_exposure;\n"
|
||||
|
||||
# With thanks to Stephen Hill!
|
||||
if ("HighDynamicRange" in configuration):
|
||||
text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n"
|
||||
text += " o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n"
|
||||
if "HighDynamicRange" in configuration:
|
||||
tonemap = configuration["HighDynamicRange"]
|
||||
if tonemap is ToneMap.ACES:
|
||||
# With thanks to Stephen Hill!
|
||||
text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n"
|
||||
text += " o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n"
|
||||
elif tonemap is ToneMap.PBR_NEUTRAL:
|
||||
text += " const float start_compression = 0.8 - 0.04;\n"
|
||||
text += " const float desaturation = 0.15;\n"
|
||||
|
||||
text += " float x = min(o_color.r, min(o_color.g, o_color.b));\n"
|
||||
text += " float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n"
|
||||
text += " o_color.rgb -= offset;\n"
|
||||
|
||||
text += " float peak = max(o_color.r, max(o_color.g, o_color.b));\n"
|
||||
|
||||
text += " if (peak >= start_compression) {\n"
|
||||
text += " const float d = 1.0 - start_compression;\n"
|
||||
text += " float new_peak = 1.0 - d * d / (peak + d - start_compression);\n"
|
||||
text += " o_color.rgb *= new_peak / peak;\n"
|
||||
text += " float g = 1.0 - 1.0 / (desaturation * (peak - new_peak) + 1.0);\n"
|
||||
|
||||
text += " o_color.rgb = lerp(o_color.rgb, new_peak * float3(1, 1, 1), g);\n"
|
||||
text += "}\n"
|
||||
|
||||
if ("GammaAdjust" in configuration):
|
||||
gamma = configuration["GammaAdjust"]
|
||||
|
|
@ -662,10 +691,10 @@ class CommonFilters:
|
|||
return self.reconfigure(old_enable, "SrgbEncode")
|
||||
return True
|
||||
|
||||
def setHighDynamicRange(self):
|
||||
def setHighDynamicRange(self, tonemap=ToneMap.ACES):
|
||||
""" Enables HDR rendering by using a floating-point framebuffer,
|
||||
disabling color clamping on the main scene, and applying a tone map
|
||||
operator (ACES).
|
||||
operator (ACES or Khronos PBR Neutral).
|
||||
|
||||
It may also be necessary to use setExposureAdjust to perform exposure
|
||||
compensation on the scene, depending on the lighting intensity.
|
||||
|
|
@ -673,8 +702,11 @@ class CommonFilters:
|
|||
.. versionadded:: 1.10.7
|
||||
"""
|
||||
|
||||
fullrebuild = (("HighDynamicRange" in self.configuration) is False)
|
||||
self.configuration["HighDynamicRange"] = 1
|
||||
fullrebuild = "HighDynamicRange" not in self.configuration or \
|
||||
self.configuration["HighDynamicRange"] is not tonemap
|
||||
if tonemap is not ToneMap.ACES and tonemap is not ToneMap.PBR_NEUTRAL:
|
||||
raise ValueError("Invalid value for tonemap")
|
||||
self.configuration["HighDynamicRange"] = tonemap
|
||||
return self.reconfigure(fullrebuild, "HighDynamicRange")
|
||||
|
||||
def delHighDynamicRange(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue