Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

materials_unlit differences between renderers #1609

Closed
jjcasmar opened this issue May 9, 2019 · 9 comments
Closed

materials_unlit differences between renderers #1609

jjcasmar opened this issue May 9, 2019 · 9 comments

Comments

@jjcasmar
Copy link

jjcasmar commented May 9, 2019

I have implemented the KHR_materials_unlit extension in Kuesa renderer and I dont understand the differences between my implementation and the sample output.

In the sample, the orange box have a baseColorFactor of

         "baseColorFactor": [
                1,
                0.217637640824031,
                0,
                1
            ]

Picking the color of the sample output, it says its (255,127,0), which is around (1,0.5,0), far away from the value specified by the material.

Is the sample wrong? Am I understanding something incorrectly?
Kuesa renderer outputs exactly the color specified by the material.

@emackey
Copy link
Member

emackey commented May 9, 2019

The baseColorFactor is specified as a linear value, but the colors you're picking from sample output are in sRGB colorspace.

sRGB is often approximated by raising to the power of 2.2.

0.5 ** 2.2 = 0.217637640824031

@emackey
Copy link
Member

emackey commented May 9, 2019

If Kuesa is producing something like (255, 55, 0), then that's incorrect, and should be reported as a bug.

@jjcasmar
Copy link
Author

jjcasmar commented May 9, 2019

I dont get why is incorrect. The specification says the output color should be the baseColorFactorbaseColorTexturevertexColor, if any. In this case, the vertex doesnt have any color, so is just baseColorFactor*baseColorTexture, and as we dont have a texture, we just output the baseColorFactor. which is (1,0.2176,0) which is (255,55,0) approx.

What is wrong here?

@emackey
Copy link
Member

emackey commented May 9, 2019

So, let's see if I can explain something that makes sense here. I'll use the newly updated Sample Viewer as a bit of a guide.

The "color" textures (including base color and emissive, and excluding metal/rough and normal) are treated as sRGB, and are transformed into linear space prior to any calculations. Optionally, this transform may happen in hardware.

After that, the (linear) factor is multiplied in. The sample code looks like this.

#ifdef HAS_BASE_COLOR_MAP
    baseColor = SRGBtoLINEAR(texture2D(u_BaseColorSampler, getBaseColorUV())) * u_BaseColorFactor;
#else
    baseColor = u_BaseColorFactor;
#endif

So now, baseColor doesn't have a displayable sRGB color, it has some linear values that are good for doing lighting computations and other PBR calculations. These calculations are all applied in the linear space.

Optionally, some tone mapping is applied.

And finally, after all that, the fragment is converted from linear space back to sRGB, such that it can participate the normal way for the remainder of the graphics pipeline. The sample viewer calls this gamma correction, which I would claim is a misnomer, it's really the poor-man's linear to sRGB transfer function, undoing what was done in the first place. In the current viewer, this is implemented simply by setting the default final gamma correction to 2.2 instead of 1.0, but ideally I think this should be changed to hide the 2.2 from the user and make it clear that it's intended purpose is linear-to-sRGB.

Of course, an unlit material short-circuits most of the fancy PBR calculations. But it still includes the "gamma correction" which is acting as the viewer's only linear-to-sRGB transfer.

#ifdef MATERIAL_UNLIT
    gl_FragColor = vec4(gammaCorrection(baseColor.rgb), baseColor.a);
    return;
#endif

So the full sequence of events for unlit materials is:

  1. base color texture, if any, converted from sRGB to linear.
  2. color is multiplied, in linear space, with the base color factor, if any.
  3. color is converted from linear back to sRGB, and sent on its way.

Since baseColorFactor joins the party late, it misses out on the initial sRGB-to-linear, but is still subject to the reverse linear-to-sRGB at the end. Indeed, the sample model here was made by setting a color value in Blender of (255, 128, 0), and the exporter knows to adapt this color to linear space prior to writing out a factor. That's why an 0.217... number was written there instead of a simple 0.5.

Hopefully this is making some kind of sense.

@jjcasmar
Copy link
Author

Thanks, this clarifies all my doubts.

@zellski
Copy link
Contributor

zellski commented May 10, 2019

@emackey almost think we should copy-paste some of this excellent explaining into the spec...

@emackey
Copy link
Member

emackey commented May 10, 2019

@jjcasmar I'm not familiar with Kuesa, can you open a bug report with them on unlit colors? You can link here for the explanation. Thanks!

@jjcasmar
Copy link
Author

Kuesa is a project we are developing at KDAB. I have already fix the code supporting KHR_materials_unlit extension.

Not sure if I can post here the link to the repo, but if you want to have a look, just look for Kuesa here on github. It doesnt support yet completely glTF, althought we are nearly there.

I completely agree with zellski suggestion about copying part of the explanation directly to the spec document.

@emackey
Copy link
Member

emackey commented May 10, 2019

@jjcasmar Sounds like the project is in good hands! We have links to a lot of glTF projects in the main README.md file. At some point can you open a PR to add a link to Kuesa from there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants