CelestiaProject / Celestia

Real-time 3D visualization of space.
https://celestiaproject.space
GNU General Public License v2.0
1.85k stars 310 forks source link

Gamma correction for shading model #834

Open Askaniy opened 4 years ago

Askaniy commented 4 years ago

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:

Askaniy commented 4 years ago

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

mmontag commented 3 years ago

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.

375gnu commented 3 years ago

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

Askaniy commented 3 years ago

Nice!

375gnu commented 3 years ago

@Askaniy aren't bodies to bright?

Askaniy commented 3 years ago

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

375gnu commented 3 years ago

@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

Askaniy commented 3 years ago

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.

375gnu commented 3 years ago

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.

Askaniy commented 3 years ago

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.

375gnu commented 3 years ago

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 commented 2 years ago

image image

Strange artifacts on quad borders with enabled sRGB correction.

Askaniy commented 2 years ago

@375gnu was the atmosphere turned on on Saturn?

Askaniy commented 2 years ago

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.

375gnu commented 2 years ago

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

375gnu commented 1 year ago

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 commented 1 year ago

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.

Askaniy commented 1 year ago

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.

375gnu commented 1 year ago

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 commented 1 year ago

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

Askaniy commented 1 year ago

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.

375gnu commented 1 year ago

image

There is a progress moving stuff to fragment shaders.