Fix glTF Texture flipY Issue in Three.js
This article explains how to resolve the common texture inversion (flipY) issue when loading glTF models in Three.js. You will learn why this coordinate mismatch occurs between WebGL and the glTF standard, and how to apply the correct code configurations to ensure your textures align perfectly on your 3D models.
Understanding the flipY Mismatch
The texture flipping issue arises because of a conflict between the
default coordinate systems of WebGL and the glTF format. By default,
WebGL (and Three.js Texture objects) expects the UV
coordinate origin (0,0) to be at the bottom-left corner of
an image. Conversely, the glTF specification defines the UV origin at
the top-left corner.
When you use the Three.js GLTFLoader, it automatically
configures all embedded and referenced textures inside the glTF file
with texture.flipY = false so that they render correctly.
However, if you manually load an external texture using
TextureLoader and assign it to a glTF material, Three.js
defaults to texture.flipY = true, causing the texture to
appear upside down on your model.
The Solution: Manually Setting flipY to False
To fix this issue when applying custom or external textures to a glTF
model, you must explicitly set the flipY property of your
texture to false before assigning it to the material.
Here is the standard implementation using
TextureLoader:
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// Initialize the texture loader
const textureLoader = new THREE.TextureLoader();
// Load the external texture
textureLoader.load('path/to/your/texture.jpg', (texture) => {
// Crucial step: Align the texture coordinate system with glTF standard
texture.flipY = false;
// Load the glTF model
const gltfLoader = new GLTFLoader();
gltfLoader.load('path/to/your/model.gltf', (gltf) => {
const model = gltf.scene;
// Traverse the model to find the mesh and apply the texture
model.traverse((child) => {
if (child.isMesh) {
child.material.map = texture;
child.material.needsUpdate = true;
}
});
});
});Working with Compressed Textures
If you are using compressed textures (such as KTX2 basis textures),
the flipY property might be read-only or pre-configured
during the encoding process. For compressed textures processed via
KTX2Loader, the loader automatically handles the layout.
Ensure you do not manually change flipY on compressed
textures unless you are manually overriding the UV transformation matrix
in your custom shaders.