Search code examples
javascriptencodingthree.jslightinggltf

How can I properly encode a GLTF while also preserving the encoding of other meshes and textures?


I'm building a web ar app that allows users to wear GLTF head models. (https://www.head5.camera/) In order to get the correct lighting on the GLTF, I have set renderer.outputEncoding = THREE.sRGBEncoding and this works great BUT it also adjusts the lighting of my THREE.VideoTexture from my video stream. Is there a way to encode just the GLTF but preserve the LinearEncoding? of the rest of the scene. Any help is much appreciated.

Here's an example of what I mean:

Head5 photo with light background

The background is lighter than it is supposed to be because it is also being encoded.


Solution

  • Output encoding is a renderer-level setting and cannot be changed for specific objects or materials. Because you can only have one renderer.outputEncoding, it's necessary that you stick consistently to either a gamma workflow or a linear workflow (background reading).

    THREE.GLTFLoader configures materials and textures with the assumption that you're using a linear workflow, and that requires renderer.outputEncoding = THREE.sRGBEncoding (or equivalent post-processing). It sounds like the rest of your scene is configured for a gamma workflow. To make those consistent you'll probably want to traverse the whole scene (including both glTFs and any other models / textures) and configure the colorspace of the relevant textures.

    scene.traverse((object) => {
      if (object.isMesh) {
        const material = object.material;
        if (material.map) material.map.encoding = THREE.sRGBEncoding;
        if (material.emissiveMap) material.emissiveMap.encoding = THREE.sRGBEncoding;
        if (material.sheenColorMap) material.sheenColorMap.encoding = THREE.sRGBEncoding;
        if (material.specularColorMap) material.specularColorMap.encoding = THREE.sRGBEncoding;
      }
    });
    

    With those changes, sRGB output encoding for a "linear workflow" will look correct. You can also do the opposite – switching these textures to THREE.LinearEncoding — if you want to use linear output encoding for a "gamma workflow". That might be easier if you have a lot of other content in the scene.