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

Color in GLTF-File #804

Closed
MarcusGT076 opened this issue Jan 20, 2025 · 6 comments
Closed

Color in GLTF-File #804

MarcusGT076 opened this issue Jan 20, 2025 · 6 comments

Comments

@MarcusGT076
Copy link

Hello together,

i have a problem with the colors on import. When i import a gltf file into unity i have a slight different color value as in the gltf file.
As example the red value in the baseColorValue in the gltf-file is : 0.7647669911384583,
in unity it has a color value on red channel in the material with : 0.8884587.

Where did the difference come from ? How are the colors are calculated in unity that i can reproduce the color value exact as it is in unity ?
I dont want to read out the color value from unity itself, because i want to take it from the .gltf file itself for visualize it in html.

Cheers,
Marcus

@hybridherbst
Copy link
Collaborator

hybridherbst commented Jan 20, 2025

Hey, color interpretation in Unity depends on the set color space in Unity, which slot that color is on, and potentially other factors. The data can end up being different to what is in the glTF file, because colors are always stored in srgb-linear in glTF, but not in Unity ("it depends"). However, the appearance should always be correct, since we're taking care of the appropriate conversions on both import and export.

Do you have a file where you get a visual difference before/after import? If so, would be great if you could upload it here, and include Unity version, SRP version, Unity color space setting, and repro steps :) Thanks!

@MarcusGT076
Copy link
Author

Hey,

I will try to explain the situation. I am loading a GLTF file at runtime in Unity in the browser. I have created an HTML, JavaScript, and CSS UI where you can select colors. To adjust the color from the input field, I get the color value directly from the material of the object in the GLTF file from its JSON to visualize exactly the color of the object in Unity. Therefore, I don’t want to communicate with Unity back and forth when I already have the color available in the JSON of the GLTF file.

However, this value is not the same as in Unity. I realized that in Unity, the colors from the imported model are color-corrected, while in the GLTF file they are not. When I take the RGB values from the GLTF file, the color in Unity appears darker and does not match its import. Yes, I had already suspected that this is a problem with color correction itself. My thought was that there might be a calculation for color correction, or does Unity handle this on its own?

My Unity version is 2022.2.1f1, and I am using the built-in render pipeline.

Cheers,
Marcus

@hybridherbst
Copy link
Collaborator

Thanks for the details – I'll have to ask again, does the imported file (without your color modifications from the web UI) look correct? Depending on how Unity is configured (render pipeline, color space setting) values are converted internally in Unity to make the appearance of the color look as intended by the author.
Almost always, when you're editing a color, you have to be aware of the color space of the color field, and its intended purpose. So it is unavoidable that for some cases, you need to convert the color from linear to srgb space or vice versa.

The (slightly simplified but accurate enough) conversion is simple, you can use Math.Pow(color.rgb, 2.2) and Math.Pow(color.rgb, 1/2.2) for the respective conversions.

Here is an example:

This material has (visually) the same color in the base color and emissive slots.
Image

Let's take a look at the values:
Base Color: RGB(212,124,35) == (0.831, 0.486, 0.137)
In Unity, base color (for URP) is stored as gamma-corrected sRGB value.
Image

Emissive Color: RGB(168,51,4) == (0.658, 0.202, 0.017)
In Unity, emissive color (for URP) is stored as linear value.
Image

Note that the math checks out with the conversions mentioned above:

  • Math.Pow((0.831, 0.486, 0.137), 2.2) == (0.658, 0.202, 0.017)
  • Math.Pow((0.658, 0.202, 0.017), 1/2.2) == (0.831, 0.486, 0.137)

The reason for this is that in Unity, base colors are stored as sRGB colors (already gamma-corrected), while emissive colors are stored as linear colors. So, they look the same, but actually when you want to set these colors from the outside – to match an expected visual appearance – one of them needs to be converted differently to the other.

If you look around various places in Unity where colors are handled, it's all over the place for legacy reasons – for example, particle system color fields are super random in how they use and specify color, and how it's displayed. Here's the same resulting color shown on the "Particles/Standard Unlit" material – note how the color field and the visual appearance of the color don't even match!
Image

Now, in glTF things are simpler, without those legacy differences – by specification, all colors inside a glTF file are stored in linear space, and not gamma-corrected.

TL;DR: when you're adjusting colors in Unity from the outside, you have to convert in either direction depending on what you're using the color for, if your goal is to have the same visual appearance.

Hope that helps!

@hybridherbst
Copy link
Collaborator

@MarcusGT076 can this issue be closed? Did my explanation above help?

@MarcusGT076
Copy link
Author

Hey there,

yes thank you for your detailed answer :) At least it was possible to take the color from the GLTF-File itself and recalculate its colors.
But it was a little bit weared. Its not exact 2.2 in the calculation, it was something about 2.4 to get the exact color information from the GLTF File.

Thanks for youre help!
Cheers
Marcus

@hybridherbst
Copy link
Collaborator

Sounds good!

The exact conversion depends on a number of factors, like which colorspace the monitor you're at is in, which colorspace your color picker is in, and so on.

Also, pow(2.2) is an approximation; the exact math is a bit more involved:
https://entropymine.com/imageworsener/srgbformula/

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

No branches or pull requests

2 participants