Skip to content

Gamma Correction in Future X3D

Michalis Kamburelis edited this page Sep 6, 2021 · 8 revisions

This is an attempt at explaining the "gamma correction" issue better. See also my previous page about this: Gamma correction in X3D and glTF.

What does "gamma correction" mean

  1. "Gamma correction" in the context of 3D rendering is important to make lighting calculations correct.

  2. Your monitor typically "transforms" the colors. The details of this transformation are in Gamma correction in X3D and glTF and resources linked from it.

    2.1. When you take a photo with a camera, or when you prepare an image in GIMP/Photoshop/Paint etc., you counteract this transformation, by making the RBG values transformed in the inverse way. So the RGB values in images like PNG/JPG do not correspond to physical values. They don't even "map linearly" to physical values, because the "transformation" is non-linear.

    2.2. To use the image as a texture (that multiplies e.g. the "diffuse" light factor), you need to get back physical value from images. Only then you can sum and multiply these values in a way that is physically correct.

    2.3. And at the end, once lighting calculations are done, you should again "inversely transform" the final color, because it has to be displayed on a computer screen, that will transform it..

    The points 2.2. and 2.3. are something that has to be implemented in a renderer in order to claim it "supports gamma correction". It's actually fairly easy, again I refer you to https://github.com/michaliskambi/x3d-tests/wiki/Gamma-correction-in-X3D-and-glTF .

  3. The "transformation" I talk about above is actually just component-wise power operation with a constant exponent. That is, "output = pow(input, CONSTANT)" or (inverse) "output = pow(input, 1 / CONSTANT)".

  4. In a perfect world, the point 2.2. above is implemented knowing the exact CONSTANT of the monitor where the image was prepared (authored) or the camera used to capture a photo. In practice, using the "CONSTANT = 2.2" is good enough, as it is so common.

    Similarly, in a perfect world, the point 2.3. above is implemented knowing the exact CONSTANT of the monitor where you render. In practice, using the "CONSTANT = 2.2" is good enough, as it is so common.

    So, "perfect gamma correction" implementation, in theory requires knowing your monitor specifics. But in practice, and in many actual implementations, just assuming "CONSTANT = 2.2" is good enough (and more visually correct than not doing any gamma correction).

  5. Historically many rendering engines didn't care about this. Because it was easier to ignore this issue (easier to implement, and faster to perform by GPUs, as you just avoid doing something). I suspect (proof welcome) that most X3D renderers except X3DOM and CGE do not apply gamma correction.

    Most new rendering systems support gamma correction, as an option.

    What should be the default? No gamma correction, or gamma correction sometimes, or gamma correction always?

  6. Using gamma correction with assets that have been prepared assuming "no gamma correction" means that colors are bad. Likewise, not using gamma correction with assets that have been prepared assuming "there is gamma correction" is bad.

  7. X3DOM applies gamma correction by default, always. https://doc.x3dom.org/tutorials/lighting/gamma/ says gammaCorrectionDefault=linear by default.

  8. Castle Game Engine (CGE) by default applies gamma correction on PhysicalMaterial, and does not apply gamma correction on Material or UnlitMaterial.

  9. What is better, X3DOM or CGE behavior or maybe something else? I have no idea:)

    9.1. The bad consequence of X3DOM approach is that it changes how X3D models look like (compared to other browsers that don't do gamma correction). Of course it can be adjusted (using the Environment X3D node).

    The advantage of X3DOM approach is consistency and correctness (with respect to how you should calculate lighting) -- you just do it always.

    9.2. The bad consequence of CGE approach is inconsistency. I apply gamma in case of some material nodes, I don't apply gamma in case of others. See https://castle-engine.io/manual_gamma_correction.php . Of course it can be adjusted (using the view3dscene menu item, or Pascal variable GammaCorrection = gcNever | gcPhysicalMaterial | gcAlways).

    The advantage of CGE approach is backward compatibility: by default, models with Phong Material render without gamma, which matches (I think) most other X3D browsers (except X3DOM), and it matches CGE behaviour before gamma correction was implemented.

  10. glTF says to apply gamma correction always. Thus, for perfect glTF compatibility, a renderer should apply gamma at least to PhysicalMaterial and UnlitMaterial. (For glTF compatibility, it doesn't matter what you do on Phong Material.)

Proposal for X3D spec

What to say in X3D spec? In my opinion, nothing, in X3D 4.0. We need to talk and figure out what is best. Opinion from other browser implementors is necessary to make a proper decision here, IMHO. I'm leaning toward (in X3D 4.1) this:

Environment {
  SFString gammaCorrectionDefault "DEFAULT" # ["DEFAULT", "NONE", "LINEAR"]
}

Or, to avoid confusing "gamma correction" term (see https://github.com/michaliskambi/x3d-tests/issues/5 ) maybe (inspired by Unity naming):

Environment {
  SFString renderingColorSpace "DEFAULT" # ["DEFAULT", "UNTRANSFORMED", "LINEAR"]
}

Where

  • DEFAULT - browser-specific behavior.

    This may be equivalent to UNTRANSFORMED or LINEAR. The X3D browser may also use browser-specific heuristic to decide whether to do gamma correction or not. E.g. browser can look at declared X3D version.

    Castle Game Engine / view3dscene by default use gamma correction on PBR materials. Despite gamma being unrelated to PBR or Phong lighting model choice, but it in practice reflects authors expectations -- authors of older models with Phong do not expect gamma. Of course one can (and should) request to just "always use gamma corection" (or PBR, Phong, unlit materials) or never.

  • UNTRANSFORMED - ignore the issues in this document and Gamma correction in X3D and glTF. Browser uses the values from textures without applying any conversion from sRGB to linear space. Then it puts the final colors values into framebuffer, without making a convertion from linear to monitor color space.

    The main rationale for this option is backward compatibility. There's a whole lot of X3D models prepared assuming that there's no gamma correction. Forcing gamma correction on them would change their look. Some authors may prefer to keep existing look (over doing more correct light calculation).

  • LINEAR - perform the gamma correct-rendering described in this document and Gamma correction in X3D and glTF. Browser transforms texture colors into linear space (by using sRGB texture format or applying the approximate conversion explicitly in shaders), and at the end transforms resulting colors into monitor space (by using sRGB framebuffer format or applying the approximate conversion explicitly in shaders).

So it is not a perfect solution (because we avoid specifying the default), but it allows authors to force/disable gamma correction if desired.

Discussion

  • Both John and Don make a simple wish: we should have a consistent rendering across all browsers, without the need for Environment node being used. So, this goes contrary to my idea "DEFAULT" == browser-specific behavior.

  • Patrick made a good case to show that having "selective" gamma makes it hard to use GL_SRGB(A) formats, https://www.khronos.org/opengl/wiki/Image_Format#sRGB_colorspace . This case would require 2 different texture datas then:

Shape {
  appearance Appearance {
    material Material {
      texture DEF tex ImageTexture {
        url "foo.png"
      }
    }
  }
  geometry Box {}
}

Shape {
  appearance Appearance {
    material PhysicalMaterial {
      baseTexture USE tex
    }
  }
  geometry Box {}
}
  • I make an argument that if we just say in the spec """X3D browsers should just apply gamma correction, always, unconditionally""" then we have lots of benefits (simplicity, consistency with glTF) but one big drawback -- we break compatibility in case of browsers that didn't implement gamma correction before. All the X3D models, tested on X3D browsers without gamma, will suddenly look different, as we would change how "Material" effectively looks (how it is mixed with a diffuse texture).

Moreover: per-texture specification

The color textures are by default assumed to be in sRGB color space, as this is most common.

But it would be nice to selectively (for particular textures) to say "this texture is already in linear space".

Clone this wiki locally