经纬志
首页 / 实战手册 / three.js 渲染

贴图上下颠倒,字全是反的

先看结论

同一张地面标牌贴图,用 TextureLoader 加载是正的,换成 canvas 或二进制数据生成之后就倒过来了。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

贴图内容整体上下翻转,文字倒置,图像底部跑到顶部。 只有部分材质出问题:从 glTF 加载的模型正常,自己用 DataTexture 生成的那张贴图是反的。

原因

WebGL 的纹理坐标原点在左下角,而图片像素原点在左上角,所以需要一次 Y 轴翻转。 three.js 对不同来源的默认值不一样:

纹理来源flipY 默认值结果
TextureLoader 加载的图片true正常
CanvasTexturetrue正常
DataTexturefalse上下颠倒
glTF 内嵌纹理false按规范正常

把 DataTexture 当成普通图片纹理使用,就会拿到反图; 反过来给 glTF 的纹理手动设 flipY = true,会把本来正确的贴图弄反。

排查过程

逐张打印纹理来源与 flipY,对照材质:

mesh.material.map && console.log({
  name: mesh.material.map.name,
  flipY: mesh.material.map.flipY,
  colorSpace: mesh.material.map.colorSpace,
  imageHeight: mesh.material.map.image.height
});

解决方案

数据纹理按图片方式使用时,把 flipY 改成 true, 并记得置 needsUpdate:

var tex = new THREE.DataTexture(bytes, width, height, THREE.RGBAFormat);
tex.flipY = true;
tex.colorSpace = THREE.SRGBColorSpace;
tex.needsUpdate = true;

不想改纹理,也可以改几何的 UV。把 V 坐标取反,效果与翻转纹理一样, 适合只对某一块网格做修正:

var uv = geometry.attributes.uv;
for (var i = 0; i < uv.count; i++) {
  uv.setY(i, 1 - uv.getY(i));
}
uv.needsUpdate = true;

如果是 glTF 模型贴图反了,先怀疑导出环节把 UV 写反了, 不要在 three.js 里硬改 flipY,否则其他模型又会对不上:

// 仅针对单个材质,确认导出坐标系数 flip 之后再改
material.map.flipY = false;
material.map.needsUpdate = true;

验证

在地面放一个有文字的标牌,从正上方俯视,文字应为正读方向; 把 flipY 改回原值,画面应立刻倒置,说明该参数就是控制点。 同一张贴图在 TextureLoader 与 DataTexture 两种路径下显示一致。

判断方向的小技巧:贴一张左上角带明显色块的测试图。 色块出现在左下角,就是少了一次 Y 翻转;在同一位置重复出现,则是 UV 本身有问题。

引用本文

经纬志(2026)。《贴图上下颠倒,字全是反的》。https://www.jingweizhi.com/cookbook/three-texture-flipY.html(访问日期 2026-11-03)。