diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index d24b25b791..18e62afc22 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -27,6 +27,7 @@ from panda3d.core import LVecBase4, LPoint2 from panda3d.core import Filename from panda3d.core import AuxBitplaneAttrib from panda3d.core import Texture, Shader, ATSNone +from panda3d.core import FrameBufferProperties import os CARTOON_BODY=""" @@ -177,7 +178,15 @@ class CommonFilters: self.textures[tex].setWrapU(Texture.WMClamp) self.textures[tex].setWrapV(Texture.WMClamp) - self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits) + fbprops = None + clamping = None + if "HighDynamicRange" in configuration: + fbprops = FrameBufferProperties() + fbprops.setFloatColor(True) + fbprops.setSrgbColor(False) + clamping = False + + self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping) if (self.finalQuad == None): self.cleanup() return False @@ -255,6 +264,17 @@ class CommonFilters: texcoordSets = list(enumerate(texcoordPadding.keys())) 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" text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" @@ -301,6 +321,10 @@ class CommonFilters: if ("VolumetricLighting" in configuration): text += " uniform float4 k_casterpos,\n" text += " uniform float4 k_vlparams,\n" + + if ("ExposureAdjust" in configuration): + text += " uniform float k_exposure,\n" + text += " out float4 o_color : COLOR)\n" text += "{\n" text += " o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"]) @@ -332,6 +356,14 @@ class CommonFilters: text += " }\n" text += " o_color += float4(vlcolor * k_vlparams.z, 1);\n" + 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 ("GammaAdjust" in configuration): gamma = configuration["GammaAdjust"] if gamma == 0.5: @@ -391,6 +423,11 @@ class CommonFilters: self.ssao[0].setShaderInput("params1", config.numsamples, -float(config.amount) / config.numsamples, config.radius, 0) self.ssao[0].setShaderInput("params2", config.strength, config.falloff, 0, 0) + if (changed == "ExposureAdjust") or fullrebuild: + if ("ExposureAdjust" in configuration): + stops = configuration["ExposureAdjust"] + self.finalQuad.setShaderInput("exposure", 2 ** stops) + self.update() return True @@ -578,6 +615,47 @@ class CommonFilters: return self.reconfigure(old_enable, "SrgbEncode") return True + def setHighDynamicRange(self): + """ Enables HDR rendering by using a floating-point framebuffer, + disabling color clamping on the main scene, and applying a tone map + operator (ACES). + + It may also be necessary to use setExposureAdjust to perform exposure + compensation on the scene, depending on the lighting intensity. + + .. versionadded:: 1.10.7 + """ + + fullrebuild = (("HighDynamicRange" in self.configuration) is False) + self.configuration["HighDynamicRange"] = 1 + return self.reconfigure(fullrebuild, "HighDynamicRange") + + def delHighDynamicRange(self): + if ("HighDynamicRange" in self.configuration): + del self.configuration["HighDynamicRange"] + return self.reconfigure(True, "HighDynamicRange") + return True + + def setExposureAdjust(self, stops): + """ Sets a relative exposure adjustment to multiply with the result of + rendering the scene, in stops. A value of 0 means no adjustment, a + positive value will result in a brighter image. Useful in conjunction + with HDR, see setHighDynamicRange. + + .. versionadded:: 1.10.7 + """ + old_stops = self.configuration.get("ExposureAdjust") + if old_stops != stops: + self.configuration["ExposureAdjust"] = stops + return self.reconfigure(old_stops is None, "ExposureAdjust") + return True + + def delExposureAdjust(self): + if ("ExposureAdjust" in self.configuration): + del self.configuration["ExposureAdjust"] + return self.reconfigure(True, "ExposureAdjust") + return True + #snake_case alias: del_cartoon_ink = delCartoonInk set_half_pixel_shift = setHalfPixelShift @@ -599,3 +677,7 @@ class CommonFilters: del_gamma_adjust = delGammaAdjust set_srgb_encode = setSrgbEncode del_srgb_encode = delSrgbEncode + set_exposure_adjust = setExposureAdjust + del_exposure_adjust = delExposureAdjust + set_high_dynamic_range = setHighDynamicRange + del_high_dynamic_range = delHighDynamicRange diff --git a/direct/src/filter/FilterManager.py b/direct/src/filter/FilterManager.py index c20cbed139..88b151ec89 100644 --- a/direct/src/filter/FilterManager.py +++ b/direct/src/filter/FilterManager.py @@ -22,6 +22,7 @@ from panda3d.core import WindowProperties, FrameBufferProperties from panda3d.core import Camera from panda3d.core import OrthographicLens from panda3d.core import AuxBitplaneAttrib +from panda3d.core import LightRampAttrib from direct.directnotify.DirectNotifyGlobal import * from direct.showbase.DirectObject import DirectObject @@ -124,7 +125,7 @@ class FilterManager(DirectObject): return winx,winy - def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None): + def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None, clamping=None): """ Causes the scene to be rendered into the supplied textures instead of into the original window. Puts a fullscreen quad @@ -207,6 +208,9 @@ class FilterManager(DirectObject): #cs.setShaderAuto() if (auxbits): cs.setAttrib(AuxBitplaneAttrib.make(auxbits)) + if clamping is False: + # Disables clamping in the shader generator. + cs.setAttrib(LightRampAttrib.make_identity()) self.camera.node().setInitialState(cs.getState()) quadcamnode = Camera("filter-quad-cam")