Celestia icon indicating copy to clipboard operation
Celestia copied to clipboard

Gamma correction for shading model

Open Askaniy opened this issue 3 years ago • 22 comments

Celestia uses the Lunar-Lambert photometric model, and (except for compatibility issues with specular maps) it works right for linear sensitivity to light (brightness is distributed in proportion to received photons). However, in a nutshell, human vision isn't linear and greatly increases the brightness of dark areas compared to bright ones. Evolutionarily, it probably matters. This is called gamma correction and the conversion from linear brightness (0 to 1), in the simplest cases, defined by this power-law expression: Visible = Linear^(1/2.2). More applied use in Python looks like this:

lambda x: 12.92*x if x < 0.0031308 else 1.055 * x**(1.0/2.4) - 0.055

So, I suggest a small change in the shading model that will be a really huge step in realism! Also, if it seems necessary, gamma correction control can be added to the settings.

To show roughly what it will look like, I took a gamma-corrected texture (on the left) and texture with linear brightness (on the right), then I added a gamma correction to the right side: jupiters Processing by Gordan Ugarkovic for comparison.

Notes:

  • A possible obstacle just noticed is the terminator line, where the angular size of the light source becomes more important. But as far as I know, Celestia does not take this into account;
  • The proposed changes don't concern texture gamma correction, only shading model gamma correction. Individual gamma correction for textures can be added and called by specifying a parameter in SSC, but this is a separate issue;
  • Monitors that use a gamma function to display image information aren't related to visual processing.

Askaniy avatar Aug 30 '20 12:08 Askaniy

First two rows of renders by Björn Johnson (at the bottom of this site) compare the current photometric model fairly accurately to what I suggest: renders

Askaniy avatar Oct 05 '20 15:10 Askaniy

Quite an improvement, in my subjective opinion. Celestia requires a tricky balance between accuracy and aesthetics, but I would call this an improvement for both sides.

mmontag avatar Dec 07 '20 06:12 mmontag

Modern hardware supports hardware gamma correction, so we can enable it easily. For older ones we can use fallback code in shaders. Or more likely we can use correction in glsl code in all cases as it allows control over gamma value. In glsl usually a simpler formula is used: pow(x, 1/gamma), where gamma is 2.2 usually, because it easier to compute and gives very close result usually.

That's what we have: Hardware sRGB enabled globally: gamma-earth gamma-jupiter

GLSL-based correction: gamma-earth-glsl gamma-jupiter-glsl

375gnu avatar Mar 07 '21 19:03 375gnu

Nice!

Askaniy avatar Mar 08 '21 12:03 Askaniy

@Askaniy aren't bodies to bright?

375gnu avatar Mar 08 '21 18:03 375gnu

@375gnu hmm. It looks like the gamma correction was applied to the final body render, not just the shading model. In what I suggested, the textures shouldn't change (see figure).

Askaniy avatar Mar 08 '21 19:03 Askaniy

@Askaniy, what about this one? Here the diffuse texture is converted from sRGB to linear and then final pixels are converted back to sRGB. gamma-jupiter-glsl-2

375gnu avatar Mar 08 '21 21:03 375gnu

Looks like the result is fine, but wouldn't it be more efficient to add gamma correction directly to the shading model? It should be a formula that calculates the brightness of each pixel. Also, there will be data loss in your method.

Askaniy avatar Mar 09 '21 07:03 Askaniy

This will be quite a nonstandard approach. Usual approach is (as I can tell from GL tutorials): 1) load textures in sRGB format and convert them to linear colospace, in modern desktop GL can be performed with HW support 2) work in linear colorspace 3) convert the final image to sRGB.

And why do you think we have data loss? GL colors are float so we can easily manipulate them.

375gnu avatar Mar 09 '21 18:03 375gnu

You are right, then there is no data loss. Although the method is not optimal for this task, it's easier to add features to it. For example, we can implement two new boolean flags for textures in SSC: GammaCorrection and BlendAlbedo. The first parameter allows users to specify the format of loaded textures (by default True), the second will be considered later.

Askaniy avatar Mar 09 '21 18:03 Askaniy

downside of shader based gamma correction - incorrect blending. it should be performed in linear space for proper results. with hw assisted sRGB pixels read from a framebuffer are converted to linear space and back to sRGB after blending.

375gnu avatar Mar 15 '21 10:03 375gnu

image image

Strange artifacts on quad borders with enabled sRGB correction.

375gnu avatar Nov 29 '21 20:11 375gnu

@375gnu was the atmosphere turned on on Saturn?

Askaniy avatar Nov 30 '21 10:11 Askaniy

If an atmosphere is not the problem, then the render engine is not providing enough quality of shadow transition for gamma correction. It makes previously invisible artifacts visible.

Not sure what to do. Maybe increase the polygon factor (polygons are sometimes visible on HiDPI displays too). I suppose my suggestion to dig into the shading model code could lead to a similar problem.

Askaniy avatar Nov 30 '21 10:11 Askaniy

It doesn't matter whether atmosphere is on or off.

375gnu avatar Nov 30 '21 11:11 375gnu

These artifacts are caused by the fact the Celestia uses per-primitive shading instead of per-pixel one. This decision was made because per-pixel calculations will slowdown rendering and without gamma correction results are almost indistinguishable.

Here is an example of a shader in q&d way updated to provide per-pixel shader: image vs original: image

cel://Follow/Sol:Saturn/2023-01-22T14:07:19.83472Z?x=II3d4kc9D/7//////////w&y=IDbhNRzU/QE&z=QK9zqxlz0gI&ow=-0.8751254&ox=-0.17094435&oy=-0.33854935&oz=-0.30052933&select=Sol:Saturn&fov=45.535126&ts=1.0&ltd=0&p=0&rf=134218242&nrf=64&lm=0&tsrc=0&ver=3

So we should:

  1. make gamma correction optional (especially as it's harder to implement it with GL ES).
  2. when gamma correction is disabled use per-primitive shading.
  3. investigate if precomputed scattering is applicable.

375gnu avatar Feb 12 '23 12:02 375gnu

But linear->sRGB conversion makes the border between lit and unlit parts too sharp. Such image image is then converted into the 1st one in the previous comment.

375gnu avatar Feb 13 '23 14:02 375gnu

I see. Is the linear part of gamma correction taken into account? Referring to the formula in the first post

Also, apparently, the texture is first converted to linear space. What if we add an option to the SSC to indicate that the texture is already in linear space? Often, add-on creators forget about gamma correction for textures, and this option will allow to quickly fix it.

Askaniy avatar Feb 13 '23 16:02 Askaniy

it doesn't matter whether we use a simple formula or a more complicate one. And the image you posted in the very beginning of the issue looks the same.

375gnu avatar Feb 13 '23 16:02 375gnu

It really looks like some textures should be treated as they are in linear space despite the presence of sRGB metadata.

375gnu avatar Feb 13 '23 16:02 375gnu

it doesn't matter whether we use a simple formula or a more complicate one. And the image you posted in the very beginning of the issue looks the same.

It should matter. To create the image, I used Photoshop, in which I used a simple formula. It seems that the complication of the formula is done specifically to make the border not so sharp.

Askaniy avatar Feb 13 '23 16:02 Askaniy

image

There is a progress moving stuff to fragment shaders.

375gnu avatar Jun 19 '23 06:06 375gnu