Skip to content

Conversation

@LeXXik
Copy link
Contributor

@LeXXik LeXXik commented Nov 12, 2025

Fixes #7473

gLTF stores vertex colors in linear space. The engine assumes they are in gamma and incorrectly transforms them.

New API:
StandardMaterial.vertexColorGamma
If true, shader will convert vertex colors to gamma space. true by default, e.g. for procedural or FBX models. gLTF stores vertex colors in linear space, so the parser will set this flag to false for imported GLB models. If you use vertex colors to
store other data, set this to false to avoid unwanted color space conversions.

Change:
Left: FBX (ok) < - > Right: GLB (not ok)

Before:

image

After:

image

Repro:

https://playcanvas.com/project/1284416/overview/vertex-color-issue

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

@LeXXik
Copy link
Contributor Author

LeXXik commented Nov 12, 2025

@mvaligursky here is an attempt to fix the vertex colors. The bottom cubes are now identical, where solid colors are used for cube sides in both FBX and GLB. The top ones differ a bit in interpolation, though. I think it is because FBX transforms the colors from gamma to linear, while in GLB we use the colors directly. Not sure, so marking this as draft. Please, check. You can run the repro project against this PR to see the result.

@mvaligursky
Copy link
Contributor

Yep this is definitely a solution I'd be happy with. We should document that new flag on StandardMaterial.

The way vertex colors work is that vertex shader gets them and outputs them as varyings to fragment shader - they get interpolated for each fragment. And then fragment shader handles gamma correction. This is not correct, as the interpolation can take place in linear or gamma space currently, but it should always be in linear space. This is why you see that interpolation difference I suspect.

So instead of handling gamma correction in fragment shader, this needs to be move to vertex shader. And fragment shader would simply consume vertex colors, always in linear space.

Risk - people that override diffuse / emissive chunks would need to remove gamma correction from there, so slight breaking change. We could update _validateMapChunk to detect gammaCorrectInputVec3 in those chunks and log a warning perhaps.

@Maksims
Copy link
Collaborator

Maksims commented Nov 13, 2025

We use color sometimes to contain our data in it, so gamma conversion while can be applied in some cases, in others in shader we would not want to apply it.
Especially if RGB contains mixed values, some to be gamma corrected (like emissive intensity), while others might have other meaning.
So as it is per texture (per slot) we would want to have it per chunk as well, so user can ensure data is not modified and gets to the shader as is, but then it is gamma corrected in relevant chunks when required only.

@mvaligursky
Copy link
Contributor

Your case should work well @Maksims - you'd use the flag on StandardMaterial to mark them as linear and no conversion would take place anywhere.

@LeXXik
Copy link
Contributor Author

LeXXik commented Nov 13, 2025

@Maksims right, but I think this PR addresses an issue, which would prevent your use-case today. Currently imported GLB models always convert vertex colors to gamma space, so it would mangle your data today.

@mvaligursky you were right, moving the gamma correction to vertex shader helped with interpolation (I've updated the screenshot). At the moment gammaPS is still added to the fragment shader, albeit not used. Do we want to remove it? I am not sure where it is added. Could be in separate PR.

I moved gamma correction to litmain. Let me know if you want it to be somewhere else.
Added docs to new material property and debug check for gamma correction in fragment shader.

@mvaligursky
Copy link
Contributor

gammaPS is still added to the fragment shader

leave it, I think this is added more or less globally, as multiple possible chunks use it.

@mvaligursky
Copy link
Contributor

Alright, another change request here, sorry and thanks.

Lets align with GLB spec:

  1. By default, assume vertex colors on the mesh are stored on linear space.
  2. StandardMaterial will have vertexColorGamma flag default to false. This flag is only used by users to manually mark they have vertices in gamma space.
  3. glb parser does not need to touch this flag.

The rest of the code stays. JSDocs on that flag should change to something like:

When set to true, the vertex shader converts vertex colors from gamma to linear space to ensure correct interpolation in the fragment shader. This flag is provided for backwards compatibility, allowing users to mark their materials to handle vertex colors in gamma space. Defaults to false, which indicates that vertex colors are stored in linear space.

@mvaligursky
Copy link
Contributor

mvaligursky commented Nov 14, 2025

Also, the validation should be perhaps specific to diffuse and emissive chunk only
and simply search for gammaCorrectInputVec3(saturate3(vVertexColor. or gammaCorrectInput(saturate(vVertexColor. strings and warn if in any of those.

I just want to avoid any false positives if possible.

@playcanvas playcanvas deleted a comment from RANA786G Nov 15, 2025
@playcanvas playcanvas deleted a comment from RANA786G Nov 15, 2025
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

Successfully merging this pull request may close these issues.

Vertex color issue

3 participants