ThreeJS纹理问题:如何避免纹理与模型颜色相乘且保留光照效果
解决ThreeJS中纹理与模型颜色相乘问题的方案
核心问题原因
MeshStandardMaterial默认会将纹理颜色与材质自身的color属性相乘,导致印花纹理被模型颜色“染色”。要避免这个问题,同时保留PBR光照效果,有两种实用方法:
方法一:分离材质+设置白色基底(最简单)
把瓶子主体和印花网格分开,给印花材质设置白色color——白色与任何颜色相乘都不会改变纹理本身的色彩,同时完全保留MeshStandardMaterial的光照反应。
修改后的代码
材质初始化
// 印花专用材质:白色基底避免纹理被染色 const printMaterial = new THREE.MeshStandardMaterial({ map: null, transparent: true, color: 0xffffff // 关键设置:白色不影响纹理原色 }); // 瓶子主体材质:单独设置瓶子颜色 const bottleMaterial = new THREE.MeshStandardMaterial({ color: 0x336699 // 示例:蓝色瓶子 });
纹理应用逻辑
function applyTexture(texture) { const printMesh = scene.getObjectByName('Print'); if (!printMesh) return; printMesh.traverse(child => { if (child.isMesh) { child.material.map = texture; child.material.needsUpdate = true; } }); }
方法二:自定义着色器钩子(保留光照的进阶方案)
如果需要更灵活的纹理混合逻辑(比如纹理透明区域显示材质颜色),可以用onBeforeCompile钩子修改MeshStandardMaterial的默认着色器,既避免颜色相乘,又完整保留PBR光照特性。
代码示例
const printMaterial = new THREE.MeshStandardMaterial({ map: null, transparent: true, color: 0xffffff }); // 修改默认着色器的颜色计算逻辑 printMaterial.onBeforeCompile(shader => { shader.fragmentShader = shader.fragmentShader.replace( 'vec4 diffuseColor = vec4( diffuse, opacity );', `vec4 diffuseColor = texture2D(map, vUv); // 纹理透明区域 fallback 到材质颜色 if (diffuseColor.a < 0.1) { diffuseColor = vec4(diffuse, opacity); }` ); });
关键注意事项
- 确保印花网格与瓶子主体网格是独立的,避免材质互相覆盖。
- 上传的印花图片建议用带透明通道的PNG格式,这样印花外的区域能透出瓶子颜色。
- 保持
transparent: true,确保纹理透明部分正常显示。
内容的提问来源于stack exchange,提问作者The Gmo
相关产品推荐
相关产品推荐

