# sRGB ruining our renders?

• @bagginsbill

Yes, that answered the question directly. Cheers
BTW, thanks for the major exposition/history talk. It helped me understand the maths when it finally came. I hate maths, but I can deal with it when I know what it's trying to do (I think in images, not numbers).

• Excellent explanation, thank you!

Is your shader then the 1st formula on your tone-mapping page, represented by the blue line?

• @bagginsbill I'm admiring you knowledge and the energy you spend to share it.. I will try to experiment all that at the end of week.

• @bagginsbill Thank you for taking the time to explain, in simple terms the whole tone mapping issue and it's possible solutions. I have in the last 5 minutes got more understanding of colour mapping than I've picked up in the last 10 years.

Amanda

• Excellent explanation, thank you!

Is your shader then the 1st formula on your tone-mapping page, represented by the blue line?

Yes, at least the brightness part is. The saturation is a separate curve, similar but upside down. It starts at 1 and approaches (but never quite reaches) 0 using an exponential function. Which, coincidentally, is another kind of tone mapping (!) so today I'll show you that one.

A note about the 2nd formula on the tone-mapping page Reinhard graph. The 2nd formula, which produces the red line, is the same function, even though the formula is different. There is no curve that one can produce and the other cannot. They're the same family of curves. They differ only in how I parameterized them. The blue one is parameterized such that you can directly move the median, and the curve will move in response. The red one is parameterized such that you can directly move the curve, and the median will move in response. See the difference? For learning purposes it is good to see both mechanisms.

• I've added another tone mapping function to my tone mapping page.

This is the Exponential Tone Map function. It's actually built into FireFly since Poser 8. But mine is parameterized for use of the median paramter, m, just like I did for the Reinhard function.

Since they share the same parameter in this form, we can directly compare them. The interactive graph will let you adjust m and see how the Exponential curve behaves vs. the Reinhard curve.

We find that Exponential produces brighter brights (values above m) and darker darks (values below m). In other words, it produces more contrast, or we could say that Reinhard produces less contrast.

I'm going to be talking about contrast some more later. It turns out there are many ways to build contrast control into any tone map function. However, each curve we get from various tone mappers is still unique and having them all in our toolkit is useful.

Here is a direct comparison of Exponential vs. Reinhard, with the same median, m = .5.

Here is a "difference" render that shows where each produces more light than the other. Exponential has brighter brights, Reinhard has brighter darks.

• @bagginsbill

This is really awesome stuff and made even better by the example renders you're presenting!

On .exr - Poser natively renders to that, right? IOW, it appears that is what all Poser's render caches are. (Rendered .exr files are always in Poser's cache whenever I do a cleanup) So, an export to the openexr format should be 1:1, with no lossy conversion issues and the best format for post-work?

On post editing - I think the forum has a time-limit for editing.

On building contrast in tone mapping - I look forward to seeing that!

• @bagginsbill Thank you so much for your input on this topic. I have several tone mapping programs that I use for developing RAW camera images, of course, but I always thought I would be doing LDR for rendered images. This is very exciting news as far as rendering to .exr and tone mapping from there. I think this will change the way I set a scene up from the beginning, with tone mapping in mind from the get go. And to think of all the times I've rendered the same scene over again, just to change the lighting a little, you can totally change the way a image looks with a program designed for HDR.

• @bagginsbill: thanks for working on this. I know next to nothing about math. This helps out enormously!

I had forgot that CS6 has a tonemapping function built in when you convert EXR files to 8 bit. Works pretty well. I will admit that I still need to learn the right way to use the controls. For this one I set gamma to 2.2 and then pushed up the exposure till I thought it looked good. I messed with a couple of the other sliders in the same fashion. More reading will need to be done.

• Hi,

If anyone wants to play along with @bagginsbill I've created a prop that is correctly UV mapped and has @bagginsbill's shader on it. The prop is just a plain square but has height and width properties, just set those to the value of your image and then scale to fit whilst keeping the correct dimensions, the origin is at 0,0 so it scales right and up. Just unzip to any runtime of your choice.

BB Tone Mapping Prop

• @morkonan - Yep exporting to OpenEXR has no flaws. It may be that HDR also has no flaws but I haven't bothered checking it in more detail. Speed and size are not factors to me so I just go with EXR.

@ribroast - You're welcome. I think it is possible to make nice renders without following up with tone mapping, but there are so many more options when you do and it's just less guesswork.

@ghostship - Your image lighting is perfect, IMO!

@amethystpendant - Very nice - thanks for that. I'm using it now, as well. However, I may make another one because I'm doing these multi-segment images now and it would be convenient to have a third dial which is how many copies am I rendering.

• I've been experimenting with contrast controls. I came up with a bunch of different formulations. After much math and test rendering, I've come to the conclusion that the first and simplest one I used is the best.

I can't find how to use superscripts for math exponents in this site, so I'm going to use Python notation for exponents.

a ** b

Means a raised to the power b. Some examples: 2 ** 5 is 2 to the 5th power which is 32, x ** 2 is x squared, x ** n is x to the nth power, b ** x is b to the xth power, etc.

OK here's how I do contrast.

Power has an interesting property. For all x between 0 and 1 (0 < x < 1) and for all c > 0, the function

f(x) = x ** c

has two stationary points. The curve of this function always passes through (0, 0) and (1, 1). The curve pivots around these two stationary points.

When c is 1, the curve is actually x ** 1, which is just x (a straight line). In other words, the value c = 1 is a neutral value.

When c > 1, then all values to the left of (1, 1) are smaller, and all values to the right of (1, 1) are bigger. If you think of x as a luminance, then c > 1 increases contrast.

When c < 1, then all values to the left of (1, 1) are bigger (but STILL less than 1) and all values to the right of (1, 1) are smaller (but STILL more than 1). If you think of x as a luminance, then c < 1 decreases contrast.

A further refinement will make this a perfect building block.

In the context of our exponential tone mappings, the parameter, m, is very special. This is the mid-point of the curve and I find it is most convenient for contrast to pivot around that point.

If I re-scale the x value, dividing by m (x/m) then the power function changes. Suppose we define this new contrast function, C, like this:

C(x) = (x / m) ** c

Now the first pivot (0, 0) is unchanged, but the second pivot is now at point (m, 1) instead of (1, 1). See for yourself:

C(m) = (m / m) ** c
C(m) = 1 ** c
C(m) = 1

Neat. C(m) is a constant no matter what value we supply for c, and in fact it is 1.

So now let's take any tone map function and replace all occurrences of x/m with C(x).

Recall the Exponential tone map is

E(x) = 1 - .5 ** (x/m)

replace (x/m) with C(x) = (x/m) ** c and we get

E(x) = 1 - .5 ** ( (x/m) ** c )

Interesting - here's a series of images using E(x) with various values of c from .8 to 1.2.

Here's another with a darker mapping.

• I've updated the tone mapping page with a new graph. This one lets you see and manipulate the Exponential tone map with contrast.

There's a purple dot in the new graph. This defines a point, (a, b), that the curve must pass through. Drag it around to change the point and see that the curve passes through the purple dot no matter where you put it.

If you scroll down the equations on the left, you'll find the calculation of the parameter c from the point (a, b). You don't need to know how to do that calculation, but that is the formula. More important is that it displays the necessary value of c so that the curve has that amount of contrast.

• I haven't graphed or rendered this yet, but the Reinhard curve can be adjust the same way, after a little refinement.

Recall that the Reinhard curve function is

R(x) = x / (m + x)

Now I said the construction of the contrast adjustment is to find x/m and replace it with C(x). But - we haven't got that anywhere! Well - we can easily fix that.

R(x) = x / (m + x)
{ Divide top and bottom by m }
R(x) = (x/m) / ((m + x) / m)
{ Distribute the divide by m in the denominator into the m+x }
R(x) = (x/m) / (m/m + x/m)
{ m/m is just 1 }
R(x) = (x/m) / (1 + x/m)

In this form we can now easily replace all occurrences of x/m with C(x)

R(x) = ((x/m) ** c) / (1 + ((x/m) ** c))

Voila.

• I'd show more but I have to go work on my tax prep.