GLTF/GLB files and renderer.gammaFactor

It is my understanding the gltf/glb is now the recommended file format for saving and loading Three.js objects. However, there are problems with getting the colors to display properly. One proposed fix is to add the following instruction:
renderer.gammaFactor = 2.2;

I had been using a factor of 1. Changing it to 2.2 does appear to correct the color by making things brighter. (Although I had to change the color, roughness and reflectiveness of the model textures to make them look right again.)

One side effect is that is makes everything in the scene brighter, including the skybox textures.

Is there any way to avoid this side effect?

I am using Blender to create the gltf/glb file, so perhaps there is a box to check to eliminate the need for the gammaFactor adjustment?.

Have you tried to define the Texture.encoding for your background texture? It should be cubeTexture.encoding = THREE.sRGBEncoding when using THREE.CubeTextureLoader.

cubeTexture.encoding = THREE.sRGBEncoding

I am using this routine to load the SkyBox - which I believe is from the Three.js manual:

var fpath = ‘sky/box/’ + sbname + ‘/’;
envMap = new THREE.CubeTextureLoader(loadingManager)
.setPath(fpath)
.load([‘px.jpg’, ‘nx.jpg’, ‘py.jpg’, ‘ny.jpg’, ‘pz.jpg’, ‘nz.jpg’]);
envMap.format = THREE.RGBFormat;
scene.background = envMap;

Where/how would I insert the THREE.sRGBEncoding directive in that routine?

Thanks.

Like so:

var fpath = 'sky/box/' + sbname + '/';
envMap = new THREE.CubeTextureLoader(loadingManager)
	.setPath(fpath)
	.load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
envMap.format = THREE.RGBFormat;
envMap.encoding = THREE.sRGBEncoding;
scene.background = envMap;

Works perfectly! Since gltf/glb is the recommended file format, I would suggest that they incorporate your improvement in the manual.
I gather that I should also use that command when loading my other external textures - the ones that are not part of the gltf/glb file.
Thanks!

1 Like

Correct. Normally, JPG and PNG textures used for diffuse, emissive and specular maps are encoded as sRGB. If you set the respective encoding to Texture.encoding, three.js is able to properly decode the color values in the shader (to linear space), compute the lighting and perform the final output encoding (sRGB, Gamma etc.) at the end of the rendering process.

1 Like

We’ve written a bit about it here:

https://threejs.org/docs/#examples/en/loaders/GLTFLoader

Suggestions for other relevant documentation would be welcome, but note that we’re still trying to figure out an easier/clearer way to help developers use a “linear workflow” (better for physically-based rendering) as opposed to a “gamma workflow” which is the current default elsewhere in threejs.

Related: https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html

Yes, the three.js documentation of both the gltf loader and the cubemap were very helpful. In the former, there was a reference to using THREE.sRGBEncoding for external textures. I was merely suggesting a corresponding entry in the discussion of the cubemap. But I can understand your reluctance to add more documentation if things are evolving so fast that much of what already exists will be changed.

One more question.
I have been experimenting with sky.js which appears to create a realistic (albeit empty) sky. When I used it with a lower setting you could clearly see the sun in the sky. However, the sun now appears as a bright haze. So I suspect that the increase in gammaFactor is also making this brighter.
I added “material.encoding = THREE.sRGBEncoding;” to sky.js, a line below the “var material” definition.
But that didn’t seem to help.
Any thoughts?

Since sky.js is implemented using a shader, it appears that I am going to have to modify the fragment shader by inserting something to convert the color value from rgb to srgb.

Yeah, that’s correct. Not all shaders in the examples have the same logic from the built-in materials. You can use one of the encoding functions from the following shader chunk in order to convert a color value from linear to something else (sRGB, Gamma etc.).

Okay, this may not be “best practices”, but I replaced the standard last line:

	'	gl_FragColor = vec4( retColor, 1.0 );',

with:
’ vec4 value = vec4( retColor, 1.0 );’,

	'	gl_FragColor = vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );',

I renamed the file Sky2.js and used it instead.

I’m not sure that it made as much difference as I had expected. I looked at the original Sky example again and found that raising the inclination did not create the effect I had seen before. However, that must have been because I was incorrectly using a gammaFactor of 1 and not converting to sRGB.

At least I learned a bit more about shaders, gammaFactor and sRGB.