sRGB ruining our renders?


  • Poser Ambassadors

    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.

    0_1487872745621_Exponential vs Reinhard.jpg

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

    0_1487872781126_Exponential vs Reinhard diffs.jpg



  • @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.

    0_1487986080433_Natural Light.jpg



  • 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


  • Poser Ambassadors

    @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.


  • Poser Ambassadors

    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.

    0_1488121040639_Exponential with contrast.jpg

    Here's another with a darker mapping.

    0_1488121214820_EC2.jpg


  • Poser Ambassadors

    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.

    0_1488121486664_upload-b7af582b-5d2a-4ffb-9e54-3356b1b7eb70


  • Poser Ambassadors

    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.

    { Start with original function }
    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.


  • Poser Ambassadors

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