View Full Version : automatic exposure control
Vexator
04-16-2008, 01:32 PM
i'd like to add automatic exposure control to my renderer. afaik i need the average brightness of the scene. so i render the scene to a texture and then blit it to a texture half the size of the preceding one until i arrive at one which is 1x1.
how can i compute the exposure now? in a paper on this topic i found this:
Automatic exposure control aims to adjust the average brightness of the scene. The idea is that the average brightness of the scene should be around 0.5 because the displayable intensity range is from zero to one. If the average brightness is known, the exposure value can be determined with
Exposure = 0.5 / Average_Brightness;
Keep in mind that you wish the exposure to slowly adapt and not change instantaneously. To do this, you could use the following code:
Exposure = lerp(Exposure, 0.5 / Average_Brightness, Exposure_Adjust_Speed);
does this make sense? it gives chaotic results for me, with the screen sometimes being plain white or black. any ideas?
thanks! :)
ZbuffeR
04-17-2008, 05:22 AM
Try to clamp your Average_Brightness within a reasonable range, ie. 0.3-0.7, to avoid extreme results.
Vexator
04-17-2008, 05:26 AM
yeah that sounds like a good idea. and then? i mean i do not want the exposure to change immediately, but to adjust slowly. do i have to call
Exposure = lerp(Exposure, 0.5 / Average_Brightness, Exposure_Adjust_Speed);
several times, in a loop or so? i'm not really sure how this lerp function is supposed to do that.
CatDog
04-17-2008, 05:50 AM
No, you need to call it once per frame.
Before this, calculate Average_Brightness for the frame to be rendered. "Exposure" has to be the exposure of the *last* frame. The result is the exposure of the *current* frame, that you use to adjust the brightness when rendering the current frame. And you will need it for the *next* frame, of course.
Exposure_Adjust_Speed has to be in range 0..1, where 1 results in immediate changes and lower values add the delay.
CatDog
Vexator
04-17-2008, 11:05 AM
k does this make sense?
i still have to setup a 1x1 texture to save the computed exposure for use in the next frame..
// get scene
vec4 Scene = texture2D( u_Texture0, v_Coordinates );
// average brightness of this frame
vec3 Color = texture2D( u_Texture4, vec2(0.5, 0.5) ).rgb;
float AverageBrightness = clamp( max(max(Color.r, Color.g), Color.b), 0.3, 0.7 );
// exposure of previous frame
float PreviousExposure = texture2D( ... );
// compute exposure
float Exposure = lerp( PreviousExposure , 0.5/AverageBrightness, 0.5 );
// perform tone-mapping
Scene.rgb *= Exposure*( Exposure/u_MaximumBrightness+1.0 )/( Exposure+1.0 );
AnselmG
04-17-2008, 11:37 AM
you could also use the geometry shader to quickly generate a historgram of your scene, extracting min, max and average and then doing a complete color level adjustment. However, maybe this is much more as you need....
Vexator
06-09-2008, 11:18 AM
ok i tried something else..
i compute the exposure from 9 samples of the current scene:
#define SAMPLE_COUNT 9
static unsigned int Pixels[SAMPLE_COUNT][2] =
{
iWidth*0.50, iHeight*0.50,
iWidth*0.25, iHeight*0.50,
iWidth*0.75, iHeight*0.50,
iWidth*0.50, iHeight*0.25,
iWidth*0.50, iHeight*0.75,
iWidth*0.25, iHeight*0.25,
iWidth*0.25, iHeight*0.75,
iWidth*0.75, iHeight*0.25,
iWidth*0.75, iHeight*0.75
};
Vector3D kAveragedSamples;
unsigned char Samples[SAMPLE_COUNT][4];
for( unsigned int i = 0; i < SAMPLE_COUNT; i++ )
{
glReadPixels( Pixels[i][0], Pixels[i][1], 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &Samples[i][0] );
kAveragedSamples += ( Vector3D(Samples[i][0], Samples[i][1], Samples[i][2])/255.0f )/SAMPLE_COUNT;
}
AverageBrightness = max( max(kAveragedSamples.x, kAveragedSamples.y), kAveragedSamples.z );
fExposure = 0.5/AverageBrightness;
fExposure = fPreviousExposure+( fExposure-fPreviousExposure )*0.02;
fPreviousExposure = fExposure;
then, in the final stage, i multiply the scene by this value:
Scene.rgb *= u_Exposure*( u_Exposure/u_MaximumBrightness+1.0 )/( u_Exposure+1.0 );
it works, but i'm not sure if the average brightness is computed correctly.. even for very bright scenes, the value is pretty low (< 0.4) and sometimes a little shift of the camera causes a very different value. this results bright scenes being even brigther, but if i set an upper limit for the exposure, then dark scenes will only be lightened up a bit. any ideas?
yooyo
06-10-2008, 02:35 AM
Try with:
TargetExposure = 0.5 / Average_Brightness;
Exposure = Exposure + (TargetExposure - Exposure) * 0.1;
Calculate TargetExposure every frame based on histogram or 1x1 mipmap. Then calculate Exposure using above math.
In short, using above formula, Exposure will slowly get close to TargetExposure, but never reach that value. If you have static frame, it will change exposure by 10% every frame.
Vexator
06-10-2008, 08:41 AM
thanks, but isn't that exactly what i'm doing already?
yooyo
06-10-2008, 02:04 PM
yes.. right... I didnt read this thread carefully.
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.