[HLSL CODE] Eye Adaptation

share shaders here
  • Author
  • Message
Offline
*sensei*
Posts: 372
Joined: 28 Jul 2013, 23:26

[HLSL CODE] Eye Adaptation

Hi all,

Based on article of Rim van Wersch: http://www.xnainfo.com/content.php?content=28
I found this adaptation to give good results with ENB adaptation method. I take little credit for this as it's basically a direct port but it works very well, so I thought I'd share because setting up proper adaptation is a major pain with setting up ENB code part.

GUI Elements
CONTROL Description
Adaptation: Min - controls how much to brighten the screen when average screen luminance is low. 0.0 brightens to max
Adaptation: Max - controls how much to darken the screen when average screen luminance is high. 100.0 darkens to max
Adaptation Min should be lower than Max, obviously.
Middle Grey - controls if the image is high or low key
Max Luminosity - controls blowing out highlights due to HDR. Lowering this will allow more pixels to blow out when intensity is too high

Code: Select all

bool Section_Adapt <
	string UIName =  "------Eye Adaptation--------";
> = {false};
float minAdaptE <
	string UIName="Exterior Adaptation: Min";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=10.0;
	float UIStep=0.001;
> = {0.025};
float maxAdaptE <
	string UIName="Exterior Adaptation: Max";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=10.0;
	float UIStep=0.001;
> = {0.11};
float minAdaptI <
	string UIName="Interior Adaptation: Min";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=10.0;
	float UIStep=0.001;
> = {0.025};
float maxAdaptI <
	string UIName="Interior Adaptation: Max";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=10.0;
	float UIStep=0.001;
> = {0.11};
float middleGrayE <
	string UIName="Exterior Adaptation: Middle Grey";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=2.0;
	float UIStep=0.001;
> = {0.6};
float middleGrayI <
	string UIName="Interior Adaptation: Middle Grey";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=2.0;
	float UIStep=0.001;
> = {0.6};
float maxLumaE <
	string UIName="Max Exterior Luminosity";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=16.0;
	float UIStep=0.001;
> = {16.0};
float maxLumaI <
	string UIName="Max Interior Luminosity";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=16.0;
	float UIStep=0.001;
> = {16.0};
Helper function
Simply returns weighted average of luminosity coefficient for HD monitors.

Code: Select all

float grayValue(float3 gv)
{
	return dot( gv, float3(0.2125, 0.7154, 0.0721) );
}
Pixelshader part - Ideally Adaptation (HDR) should be placed before bloom, and finely tuned so that HDR doesn't destroy bloom or destroys the base image so you'd only see bloom. Also make sure you aren't using both Skyrim and ENB adaptation at the same time (that's just bad on many levels).

Code: Select all

	////////////////////////////////////
	//         Eye Adaptation         //
	////////////////////////////////////
	//Based on work by Rim van Wersch, sorta
	float minAdapt		= lerp( minAdaptE, minAdaptI, EInteriorFactor );
	float maxAdapt		= lerp( maxAdaptE, maxAdaptI, EInteriorFactor );
	float middleGray	= lerp( middleGrayE, middleGrayI, EInteriorFactor );
	float maxLuma		= lerp( maxLumaE, maxLumaI, EInteriorFactor );
	
	float EyeAdapt		= grayValue( tex2D( _s4, 0.5 ).xyz );
	float pixelLuma		= grayValue( color.xyz );
	EyeAdapt			= clamp( EyeAdapt, minAdapt, maxAdapt );
	
	float scaledLuma	= ( pixelLuma * middleGray ) / EyeAdapt;
	float compLuma		= ( scaledLuma * ( 1.0f + ( scaledLuma / ( maxLuma * maxLuma )))) / ( 1.0f + scaledLuma );
	
	color.xyz			*= compLuma;
ENB Adaptation in GUI should allow min value 0.0 and max value >= 1.0
Adaptation time should be set to whatever time you prefer (low or high)
Adaptation sensitivity is up to you, but should be somewhat around middle (0.5). I prefer a value of 0.67 which seems to give quite reliable results.
Force min/max values should be set to TRUE

Cheers.
Last edited by prod80 on 30 Aug 2014, 12:31, edited 2 times in total.

Offline
User avatar
*blah-blah-blah maniac*
Posts: 1938
Joined: 05 Mar 2012, 02:08

Re: [HLSL CODE] Eye Adaptation

You might want to do something like this;

Code: Select all

color.xyz *= compLuma / grayValue( color.xyz );
So it doesn't shift the colors around, making it look like the contrast of the image have been increased by a lot.

Offline
*sensei*
Posts: 372
Joined: 28 Jul 2013, 23:26

Re: [HLSL CODE] Eye Adaptation

Actually it doesn't shift the colors around, it's a simple scalar. I don't see why divide something by Luma coefficient again which has already been divided by it... The whole point is to scale with difference between weighted average of scene and pixel. I didn't get any shifting because of it.

Offline
User avatar
*blah-blah-blah maniac*
Posts: 1938
Joined: 05 Mar 2012, 02:08

Re: [HLSL CODE] Eye Adaptation

Well this is the result I get.

Vanilla, for reference;
Image

Your posted example;
Image

And with the alteration;
Image


With the alteration the tonemapping function results in a correct tonemapped image, while your initial result does something else to the scene.

In any case if you want to have the adaptation "limited" so it doesn't over expose the scene than the simple Reinhard function does a better job with that.

Like this;

Code: Select all

float EyeAdapt = grayValue( tex2D( _s4, 0.5 ).xyz );
float toneMappedLuminance = adaptedLum / (adaptedLum + 1);
  color.xyz *= toneMappedLuminance / adaptedLum;
And then you use your Uncharted2D for the controllable tonemapping of the rendering instead.

But if the example you posted here is what you like, then that's that.

Offline
*sensei*
Posts: 372
Joined: 28 Jul 2013, 23:26

Re: [HLSL CODE] Eye Adaptation

Well, actually I disagree because first off; It's intended for eye adaptation in which when scene is bright darker colors should become darker but light colors should be less affected (at least to maintain dynamic range they should remain bright not dimmed). I do not intend to do any adjustments other than darkening/brightening the scene in a believable way with this so in all honesty I do not intend to map them to something close to vanilla (which is something that went through the entire pipeline, while this is just an adaptation code part, nothing entire).

Your shot with adjustment, while it does map colors, it is not what this is intended for... there's actually less dynamic range in that shot, which is exactly what I don't want (or like).

After this code I run it past Bloom (further emphasizing highlights and bleeding into darker area's and AGCC followed by Filmic tonemapping to finish it up, and so far the results have been great.

But of course it's all what one wants, though for adaptation code these few lines do the job pretty well and can get pretty believable results. Clamps should be set low... go into night and determine to what point to darken the image (min) and pop in a fire dragon, let him spit his flames and setup the max value (which won't be that far from min) setup sun intensity and the likes accordingly and you will have a working adaptation which isn't annoying in no time.

I just shared here for others, to try and tweak and whatever they want.

Offline
User avatar
*blah-blah-blah maniac*
Posts: 530
Joined: 30 Jan 2012, 13:18

Re: [HLSL CODE] Eye Adaptation

Lol, y'all got those complex tonemap/adaptation while mine consists of 4 lines of code...I should do something...

Offline
User avatar
*blah-blah-blah maniac*
Posts: 1938
Joined: 05 Mar 2012, 02:08

Re: [HLSL CODE] Eye Adaptation

prod80;
Got it.
I have been messing around tweaking with it and it makes the adaptation behave a lot better than what it used to do.


Marty McFly;
Actually they are no more complex than what is already inside Boris file, some of it at least.
It has just been re-purposed, more or less anyway.

Seeing any similarities

Code: Select all

From Boris PP;
color.xyz = (color.xyz * (1.0 + color.xyz / lumamax)) / (color.xyz + EToneMappingCurveV2);

From Prod80 Adaptation;
float compLuma = ( scaledLuma * ( 1.0f + ( scaledLuma / ( maxLuma * maxLuma )))) / ( 1.0f + scaledLuma );

Offline
*sensei*
Posts: 372
Joined: 28 Jul 2013, 23:26

Re: [HLSL CODE] Eye Adaptation

I have readjusted the scales, I put 0-100 for minmax for testing, didn't remove them... 0-1 minmax makes a lot more sense. But changed to 0-10

@Jawz; yes it does... while it does work with reinhard tonemap function (which it is basically) it's not meant for that. Or at least not in the way what ENB adaptation is doing.
@Marty; as Jawz says, it's close to the same as what is in the default file, just behaves better.

Offline
User avatar
*blah-blah-blah maniac*
Posts: 1938
Joined: 05 Mar 2012, 02:08

Re: [HLSL CODE] Eye Adaptation

Been looking over certain ENBSeries parts a bit closer and found that the adaptation actually have a viable average luminance channel in it already - tex2D( _s4, 0.5 ).y. Same grey values are achieved as with the max(max(inColor.x, inColor.y), inColor.z). Most likely not the same as using any coefficient values, but that is more likely caused by the fact that it encodes Rec.709 or Rec.601 values from whatever source Boris uses in ENBSeries originally.

At least as far as I've been able to tell from comparing in game pictures as well as looking at histograms of said images.
Please feel free to correct any of my assumptions here.

Offline
*sensei*
Posts: 373
Joined: 07 Mar 2013, 10:14

Re: [HLSL CODE] Eye Adaptation

Sounds about right to me...
I always use Rec. 709 values on all grey conversions... the other one is just off. Especially noticeable on textures with high red components.

This is something that I kinda notice on SweetFX using presets.. since that still use the other one on many of its functions.. at least the older versions of SweetFX does. I have seen presets with it changed for other games and if I do not recall wrong then also a few for skyrim.
Post Reply