HDR Rendering (Average Luminance)

Started by
30 comments, last by Medo Mex 8 years, 4 months ago

If I'm not mistaken, timeGetTime() returns milliseconds. The shader wants seconds (elapsedTime should be under 1 for that pow function, IIRC), so try dividing your elapsed time result by 1000 to give you the result in seconds and pass that instead.

As for the first frame, I don't think it's a problem. You can try clearing it after creation to some half-lum value just in case, if you're worried about it.

Advertisement

@Styves: Now all I see is white screen.

In the DirectX SDK Sample I see that they are assigning DXUTGetElapsedTime() to this variable.

Well... hmm... at least DXUTGetElapsedTime() returns units in Seconds, so we're on the right track.

Did you clear the previous texture after creation like I mentioned? If so, maybe your time is truncated to 0 and it's only using the original cleared values (if that value is black your division will result in insanely high exposures, making the image white)?

I'm just throwing ideas around now, you'll probably have to tinker a bit and debug to see where your problem might be.

@Styves: You meant that I should multiply the elapsedTime with 1000?

I tried to multiply it with 1000, now it's not flashing anymore, in tone mapping shader I tried to change g_fMiddleGray to 1.8f instead of 0.72f and in the terrain and sky shader I multiply the final color by higher number like the following:


terrainPixelColor *= 15.8;
return terrainPixelColor;

I'm not sure if what I'm doing is correct and here is how the scene look like now:

I feel that there is something not right, the scene is not highly detailed as expected, is that HDR image?

[attachment=30175:Is that HDR 3.png]

Here is the tone mapping shader:


// Tone mapping
float4 color = Tex[0].Sample( SampleType, IN.TexCoord );
float fAdaptedLum = Tex[1].Sample( SampleType, float2( 0.5, 0.5 ));
float g_fMiddleGray = 1.8f; // I changed this value
color.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f);
color.rgb /= (1.0f+color);
return color;

Nah, I meant divide. timeGetTime() will return milliseconds (assuming we're talking about the windows function). The unit there is milliseconds (so a value of 10 = 10 milliseconds). What you want is seconds (so 0.01 seconds). DXUTGetElapsedTime() already returns a float containing the time in seconds (in fact, if you can, why not try testing with that function as input?).

As far as I can tell from what you've told me (and what I'm expecting out of the code), it should look like this:


shaderConstBuffer.timeElapsed = (float)TimeElapsed / 1000.0;

(If you did the above but forgot cast to float (and did 1000 instead of 1000.0), you may have truncated your value to 0). smile.png

IMO I would ignore the middle gray value and remove the terrain multiplication for now (just use 1.0 for g_fMiddleGray). If your setup is correct you should still see an image, then you can tweak the value until it suits you.

@Styves: I can only see very bright scene (everything is white actually)

@Styves: Here is what I'm doing in C++ to calculate the adapted luminance:
1. Set elapsedTime in Pixel Shader constant buffer to timeElapsed / 1000.0f
2. Set shader texture array [0] to lastAdaptionTexture (which was calculated from the last call to this function
3. Set shader texture array [1] to average luminance (which was calculated by downsampling the scene to 1x1 every frame)
4. Render to texture
5. Set lastAdaptionTexture to the texture we got from step 4
Correct me if anything is wrong
What I see is that if I divide timeElapsed by a low number for example timeElapsed / 20.0f I can see the scene but it's too bright
But if I divide by 1000.0f, the whole scene turn white
If I render the adapted luminance to the screen to see how it looks like I see a black screen.
So basically doing timeElapsed / 1000.0f turn the adapted luminance texture black.
Any idea what's wrong?

Seems to me like the time is probably right, but your textures aren't combined properly. Dividing the timeElapsed by 20.0f instead of 1000.0f might give you a less bright result, but if that result is still constant then there's probably something wrong with your textures. It should change slowly over time.


4. Render to texture

What texture are you rendering to? How are you setting lastAdaptionTexture to the texture from step 4?

@Styves: I have two 1x1 textures:

1. Average luminance

2. Adapted luminance

When I render the average luminance on the screen, I see it's getting dark when I look at dark areas and getting bright when I look at bright area, but when I render adapted luminance, I see black screen all the time, so based on that I think that the problem is with adapted luminance calculation.

How are you setting lastAdaptionTexture to the texture from step 4?

I have RenderTextureClass that I'm using to render to texture in it, this class create 1x1 texture on initialization to render the scene to it, after that I simply add the following line:


lastAdaptionTexture = renderTextureClass->GetTexture();

I tried to use the average luminance for tone mapping instead of adapted luminance and used the following tone mapping:

http://www.justinmclaine.com/shader---reinhard-tonemapping.html

Now, I get the following results after multiplying the sky with 1.2f and multiplying the terrain with 0.5f:

[attachment=30185:Is that HDR 5.png]

And this is under the terrain:

[attachment=30186:Is that HDR 9.png]

In the above images I'm NOT using adapted luminance, instead using directly the average luminance.

I have two questions:

1. Is that HDR Image? If this is HDR how do I improve it? I notice that the screenshot under the terrain looks better than above the terrain

2. If the problem is with the adapted luminance calculation, do you have any clue how to fix it?


I have RenderTextureClass that I'm using to render to texture in it, this class create 1x1 texture on initialization to render the scene to it, after that I simply add the following line:
lastAdaptionTexture = renderTextureClass->GetTexture();

That probably explains it, I had a hunch. It sounds like you're trying to read and write to the same texture at the same time - make sure this isn't the case, because it won't work. You need to have 3 textures in flight at the same time, current adapted lum (render target texture), last adapted lum (result of the previous frame), and average lum. The current one is the one you send to your tone map shader.

It should look something like this:

1. Set elapsedTime in the pixel shader to timeElapsed / 1000.0f

2. Set texture 0 to lastAdaptionTexture (adaptionTexture[!lum_idx])

3. Set texture 1 to average lum texture

4. Render to currentAdaptionTexture (adaptionTexture[lum_idx])

5. Use currentAdaptionTexture for tone mapping
6. Swap idx for next frame so that you toggle between the two textures (lum_idx = !lum_idx)
Where adaptionTexture is an array (2 textures) and lum_idx is some member variable or some static or something that you init to 0. There are other ways to do it but this is the easiest to explain, I think (and keeps you away from an unnecessary texture copy).


Is that HDR Image? If this is HDR how do I improve it? I notice that the screenshot under the terrain looks better than above the terrain

I don't know what you mean by "HDR image" or why the second image looks "better". happy.png I'm not really sure what you're after, actually. HDR on it's own isn't a magic bullet to improve visual quality - it only provides more precision/range for your color values (better/unbounded lighting without clamping colors to 255,255,255). You need to make use of that range if you want something out of it, otherwise you're not really going to see anything different other than the adaption and maybe some contrast changes from the tone mapper (which I think are slightly washing out the top image, which might be what is making you think it looks worse).

I'd say if you want it to look "better" you should add lighting... and probably some bloom. Oh, and lose the multipliers. :)

This topic is closed to new replies.

Advertisement