I’m trying to make an autoexposure feature for the viewport like real time games do, they also call it eye adaptation.
I think i am at a good point, but the script here runs in infinite loop:
import bpy
import bgl
def function(self, context):
print("function")
shading = context.area.spaces.active.shading.type
if shading in ["MATERIAL" ,"RENDERED"]:
# buffer for viewport info
viewport = bgl.Buffer(bgl.GL_INT, 4)
# store viewport info
bgl.glGetIntegerv(bgl.GL_VIEWPORT, viewport)
# width and height of the viewport
width = int(viewport[2]/2)
height = int(viewport[3]/2)
bgl.glDisable(bgl.GL_DEPTH_TEST)
# buffer for pixels
buffer = bgl.Buffer(bgl.GL_BYTE, 3)
# read viewport pixels
bgl.glReadPixels(width, height, 1, 1, bgl.GL_RGB, bgl.GL_BYTE, buffer)
avg = (buffer[0]+buffer[1]+buffer[2])/3
mul = 0.5/avg
bpy.context.scene.view_settings.exposure = mul
class VIEW3D_OT_TestDraw(bpy.types.Operator):
bl_idname = "view3d.test_draw"
bl_label = "Test Draw"
def modal(self, context, event):
print("modal")
args = (self, context)
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_add(function, args, 'WINDOW', 'PRE_VIEW')
return {'CANCELLED'}
def invoke(self, context, event):
print("invoke")
args = (self, context)
self._handle = bpy.types.SpaceView3D.draw_handler_add(function, args, 'WINDOW', 'PRE_VIEW')
return {'RUNNING_MODAL'}
def register():
bpy.utils.register_class(VIEW3D_OT_TestDraw)
def unregister():
bpy.utils.unregister_class(VIEW3D_OT_TestDraw)
if __name__ == "__main__":
register()
Put this code in the Blender’s python text editor, run it, search for the “Test Draw” operator in the viewport and click it.
Then go in the rendered mode (in EEVEE) and look at the terminal output… it infinitely prints “function”, that means it is always calling the function “function(self, context)”.
That happens because at the end of the function i am changing the Filmic exposure, that changes the viewport pixels, that triggers the call of the function and so on… infinite loop.
I am making use of bpy.types.SpaceView3D.draw_handler_add to trigger the call to change the exposure of the scene, but when the exposure changes, i need to disable the draw handler for a moment because otherwise as you can see it triggers another call to the function.
Surely i’m using something wrongly, this is why i’m asking your help here.