ThreeJS加载透明PNG纹理出现黑背景,如何处理并实现纹理可移动?
问题解决方案
修复PNG纹理黑色背景问题
材质默认未开启透明通道,PNG的透明区域会被渲染为黑色,实例化MeshPhongMaterial时添加transparent: true配置即可启用alpha通道渲染,若透明边缘出现杂色,可额外添加alphaTest: 0.5过滤低透明度像素。
修复纹理横穿线条问题
该问题通常由非2的幂尺寸纹理的mipmap采样异常导致,加载纹理后添加以下配置即可解决:
const texture = new THREE.TextureLoader().load("assets/smile2.png"); // 关闭非必要的mipmap生成 texture.generateMipmaps = false; // 配置线性过滤避免采样异常 texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; // 若纹理出现上下颠倒可额外添加以下配置 // texture.flipY = false;
实现纹理背景匹配T恤底色
原有逻辑存在错误:先给模型设置发射色,又直接替换了子网格材质,导致选中的颜色失效。你可以直接将用户选择的颜色作为材质基础色,叠加透明笑脸纹理,纹理的透明区域会自动透出材质的基础色,也就是T恤底色,修改后的代码如下:
const colorSelection = { "pink": "#ff2d55", "purple": "#5856d6", "blue": "#007aff", "orange": "#ff9500", } const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); const renderer = new THREE.WebGLRenderer({ antialias: true }); const loader = new THREE.OBJLoader(); const myCanvas = document.getElementById("container"); const controls = new THREE.OrbitControls(camera, renderer.domElement); const axisHelper = new THREE.AxisHelper(5); const hlight = new THREE.AmbientLight (0x404040); const directionalLight = new THREE.DirectionalLight(0xffffff,0.4); // 提前加载纹理并配置参数 const texture = new THREE.TextureLoader().load("assets/smile2.png"); texture.generateMipmaps = false; texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; myCanvas.appendChild( renderer.domElement ); renderer.setSize( 800, 800 ); renderer.setClearColor ("darkgrey", 1); camera.position.set(200,300,200); controls.addEventListener("change", animate); function animate() { requestAnimationFrame( animate ); renderer.render( scene, camera ); }; // 场景与灯光配置 scene.add(axisHelper); scene.add(hlight); scene.add(directionalLight); directionalLight.position.set(0,1155,325); directionalLight.castShadow = true; // 提前缓存加载的T恤模型,避免重复请求 let tshirtModel = null; // 预加载模型 loader.load("assets/standard-t-shirt/source/tshirt.obj", function(obj) { obj.scale.set(0.4,0.4,0.4) obj.position.set(0,-500,0) tshirtModel = obj; }) function changeTextureColor(color) { if(!tshirtModel) return; // 生成对应颜色的纹理材质 const tshirtMat = new THREE.MeshPhongMaterial({ color: colorSelection[color], map: texture, transparent: true, alphaTest: 0.5 }); // 遍历更新所有子网格材质 tshirtModel.traverse((child) => { if (child instanceof THREE.Mesh) { child.material = tshirtMat; } }) // 避免重复添加模型 if(!scene.getObjectById(tshirtModel.id)) { scene.add(tshirtModel) } } document.querySelectorAll("button").forEach(colorBtn => colorBtn.addEventListener("click", function () { const userColor = this.id; changeTextureColor(userColor); }))
额外优化说明
原有逻辑每次点击按钮都会重新加载OBJ模型,会导致场景内模型重复叠加、资源浪费,上述代码已经做了预加载处理,仅请求一次模型,点击时仅更新材质属性,性能更高。
内容的提问来源于stack exchange,提问作者DavidL.theRabbitKing
相关产品推荐
相关产品推荐

