27
27
from panda3d .core import Filename
28
28
from panda3d .core import AuxBitplaneAttrib
29
29
from panda3d .core import Texture , Shader , ATSNone
30
+ from panda3d .core import FrameBufferProperties
30
31
import os
31
32
32
33
CARTOON_BODY = """
@@ -177,7 +178,15 @@ def reconfigure(self, fullrebuild, changed):
177
178
self .textures [tex ].setWrapU (Texture .WMClamp )
178
179
self .textures [tex ].setWrapV (Texture .WMClamp )
179
180
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 )
181
190
if (self .finalQuad == None ):
182
191
self .cleanup ()
183
192
return False
@@ -255,6 +264,17 @@ def reconfigure(self, fullrebuild, changed):
255
264
texcoordSets = list (enumerate (texcoordPadding .keys ()))
256
265
257
266
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 "
258
278
text += "void vshader(float4 vtx_position : POSITION,\n "
259
279
text += " out float4 l_position : POSITION,\n "
260
280
@@ -301,6 +321,10 @@ def reconfigure(self, fullrebuild, changed):
301
321
if ("VolumetricLighting" in configuration ):
302
322
text += " uniform float4 k_casterpos,\n "
303
323
text += " uniform float4 k_vlparams,\n "
324
+
325
+ if ("ExposureAdjust" in configuration ):
326
+ text += " uniform float k_exposure,\n "
327
+
304
328
text += " out float4 o_color : COLOR)\n "
305
329
text += "{\n "
306
330
text += " o_color = tex2D(k_txcolor, %s);\n " % (texcoords ["color" ])
@@ -332,6 +356,14 @@ def reconfigure(self, fullrebuild, changed):
332
356
text += " }\n "
333
357
text += " o_color += float4(vlcolor * k_vlparams.z, 1);\n "
334
358
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
+
335
367
if ("GammaAdjust" in configuration ):
336
368
gamma = configuration ["GammaAdjust" ]
337
369
if gamma == 0.5 :
@@ -391,6 +423,11 @@ def reconfigure(self, fullrebuild, changed):
391
423
self .ssao [0 ].setShaderInput ("params1" , config .numsamples , - float (config .amount ) / config .numsamples , config .radius , 0 )
392
424
self .ssao [0 ].setShaderInput ("params2" , config .strength , config .falloff , 0 , 0 )
393
425
426
+ if (changed == "ExposureAdjust" ) or fullrebuild :
427
+ if ("ExposureAdjust" in configuration ):
428
+ stops = configuration ["ExposureAdjust" ]
429
+ self .finalQuad .setShaderInput ("exposure" , 2 ** stops )
430
+
394
431
self .update ()
395
432
return True
396
433
@@ -578,6 +615,47 @@ def delSrgbEncode(self):
578
615
return self .reconfigure (old_enable , "SrgbEncode" )
579
616
return True
580
617
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
+
581
659
#snake_case alias:
582
660
del_cartoon_ink = delCartoonInk
583
661
set_half_pixel_shift = setHalfPixelShift
@@ -599,3 +677,7 @@ def delSrgbEncode(self):
599
677
del_gamma_adjust = delGammaAdjust
600
678
set_srgb_encode = setSrgbEncode
601
679
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
0 commit comments