Skip to content

Commit cd435ec

Browse files
committed
filter: Support HDR in CommonFilters (using ACES tonemap)
1 parent f7375e2 commit cd435ec

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

direct/src/filter/CommonFilters.py

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from panda3d.core import Filename
2828
from panda3d.core import AuxBitplaneAttrib
2929
from panda3d.core import Texture, Shader, ATSNone
30+
from panda3d.core import FrameBufferProperties
3031
import os
3132

3233
CARTOON_BODY="""
@@ -177,7 +178,15 @@ def reconfigure(self, fullrebuild, changed):
177178
self.textures[tex].setWrapU(Texture.WMClamp)
178179
self.textures[tex].setWrapV(Texture.WMClamp)
179180

180-
self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits)
181+
fbprops = None
182+
clamping = None
183+
if "HighDynamicRange" in configuration:
184+
fbprops = FrameBufferProperties()
185+
fbprops.setFloatColor(True)
186+
fbprops.setSrgbColor(False)
187+
clamping = False
188+
189+
self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping)
181190
if (self.finalQuad == None):
182191
self.cleanup()
183192
return False
@@ -255,6 +264,17 @@ def reconfigure(self, fullrebuild, changed):
255264
texcoordSets = list(enumerate(texcoordPadding.keys()))
256265

257266
text = "//Cg\n"
267+
if "HighDynamicRange" in configuration:
268+
text += "static const float3x3 aces_input_mat = {\n"
269+
text += " {0.59719, 0.35458, 0.04823},\n"
270+
text += " {0.07600, 0.90834, 0.01566},\n"
271+
text += " {0.02840, 0.13383, 0.83777},\n"
272+
text += "};\n"
273+
text += "static const float3x3 aces_output_mat = {\n"
274+
text += " { 1.60475, -0.53108, -0.07367},\n"
275+
text += " {-0.10208, 1.10813, -0.00605},\n"
276+
text += " {-0.00327, -0.07276, 1.07602},\n"
277+
text += "};\n"
258278
text += "void vshader(float4 vtx_position : POSITION,\n"
259279
text += " out float4 l_position : POSITION,\n"
260280

@@ -301,6 +321,10 @@ def reconfigure(self, fullrebuild, changed):
301321
if ("VolumetricLighting" in configuration):
302322
text += " uniform float4 k_casterpos,\n"
303323
text += " uniform float4 k_vlparams,\n"
324+
325+
if ("ExposureAdjust" in configuration):
326+
text += " uniform float k_exposure,\n"
327+
304328
text += " out float4 o_color : COLOR)\n"
305329
text += "{\n"
306330
text += " o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"])
@@ -332,6 +356,14 @@ def reconfigure(self, fullrebuild, changed):
332356
text += " }\n"
333357
text += " o_color += float4(vlcolor * k_vlparams.z, 1);\n"
334358

359+
if ("ExposureAdjust" in configuration):
360+
text += " o_color.rgb *= k_exposure;\n"
361+
362+
# With thanks to Stephen Hill!
363+
if ("HighDynamicRange" in configuration):
364+
text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n"
365+
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"
366+
335367
if ("GammaAdjust" in configuration):
336368
gamma = configuration["GammaAdjust"]
337369
if gamma == 0.5:
@@ -391,6 +423,11 @@ def reconfigure(self, fullrebuild, changed):
391423
self.ssao[0].setShaderInput("params1", config.numsamples, -float(config.amount) / config.numsamples, config.radius, 0)
392424
self.ssao[0].setShaderInput("params2", config.strength, config.falloff, 0, 0)
393425

426+
if (changed == "ExposureAdjust") or fullrebuild:
427+
if ("ExposureAdjust" in configuration):
428+
stops = configuration["ExposureAdjust"]
429+
self.finalQuad.setShaderInput("exposure", 2 ** stops)
430+
394431
self.update()
395432
return True
396433

@@ -578,6 +615,47 @@ def delSrgbEncode(self):
578615
return self.reconfigure(old_enable, "SrgbEncode")
579616
return True
580617

618+
def setHighDynamicRange(self):
619+
""" Enables HDR rendering by using a floating-point framebuffer,
620+
disabling color clamping on the main scene, and applying a tone map
621+
operator (ACES).
622+
623+
It may also be necessary to use setExposureAdjust to perform exposure
624+
compensation on the scene, depending on the lighting intensity.
625+
626+
.. versionadded:: 1.10.7
627+
"""
628+
629+
fullrebuild = (("HighDynamicRange" in self.configuration) is False)
630+
self.configuration["HighDynamicRange"] = 1
631+
return self.reconfigure(fullrebuild, "HighDynamicRange")
632+
633+
def delHighDynamicRange(self):
634+
if ("HighDynamicRange" in self.configuration):
635+
del self.configuration["HighDynamicRange"]
636+
return self.reconfigure(True, "HighDynamicRange")
637+
return True
638+
639+
def setExposureAdjust(self, stops):
640+
""" Sets a relative exposure adjustment to multiply with the result of
641+
rendering the scene, in stops. A value of 0 means no adjustment, a
642+
positive value will result in a brighter image. Useful in conjunction
643+
with HDR, see setHighDynamicRange.
644+
645+
.. versionadded:: 1.10.7
646+
"""
647+
old_stops = self.configuration.get("ExposureAdjust")
648+
if old_stops != stops:
649+
self.configuration["ExposureAdjust"] = stops
650+
return self.reconfigure(old_stops is None, "ExposureAdjust")
651+
return True
652+
653+
def delExposureAdjust(self):
654+
if ("ExposureAdjust" in self.configuration):
655+
del self.configuration["ExposureAdjust"]
656+
return self.reconfigure(True, "ExposureAdjust")
657+
return True
658+
581659
#snake_case alias:
582660
del_cartoon_ink = delCartoonInk
583661
set_half_pixel_shift = setHalfPixelShift
@@ -599,3 +677,7 @@ def delSrgbEncode(self):
599677
del_gamma_adjust = delGammaAdjust
600678
set_srgb_encode = setSrgbEncode
601679
del_srgb_encode = delSrgbEncode
680+
set_exposure_adjust = setExposureAdjust
681+
del_exposure_adjust = delExposureAdjust
682+
set_high_dynamic_range = setHighDynamicRange
683+
del_high_dynamic_range = delHighDynamicRange

direct/src/filter/FilterManager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from panda3d.core import Camera
2323
from panda3d.core import OrthographicLens
2424
from panda3d.core import AuxBitplaneAttrib
25+
from panda3d.core import LightRampAttrib
2526
from direct.directnotify.DirectNotifyGlobal import *
2627
from direct.showbase.DirectObject import DirectObject
2728

@@ -124,7 +125,7 @@ def getScaledSize(self, mul, div, align):
124125

125126
return winx,winy
126127

127-
def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None):
128+
def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None, clamping=None):
128129

129130
""" Causes the scene to be rendered into the supplied textures
130131
instead of into the original window. Puts a fullscreen quad
@@ -207,6 +208,9 @@ def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0,
207208
#cs.setShaderAuto()
208209
if (auxbits):
209210
cs.setAttrib(AuxBitplaneAttrib.make(auxbits))
211+
if clamping is False:
212+
# Disables clamping in the shader generator.
213+
cs.setAttrib(LightRampAttrib.make_identity())
210214
self.camera.node().setInitialState(cs.getState())
211215

212216
quadcamnode = Camera("filter-quad-cam")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy