You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js中ExtrudeGeometry生成模型的纹理映射异常求助

解答

嘿,我来帮你搞定这个纹理问题!先看你的代码和效果,有两个关键问题需要处理:

1. 先修正代码里的基础错误

你在创建Shape的时候用了this.height,但在generate_box这个普通函数里,this并不指向函数的参数,这会导致Shape的顶点位置错误,甚至可能生成无效的几何体。直接改成传入的height参数就好:

const shape = new THREE.Shape();
shape.lineTo(0, height); // 把this.height改成height
shape.lineTo(width, height);
shape.lineTo(width, 0);

2. 解决ExtrudeGeometry的UV映射问题

这是核心问题:ExtrudeGeometry默认的UV生成逻辑是为复杂路径设计的,它会把纹理沿着挤出方向拉伸,导致长方体侧面的纹理变形。针对你的需求,有两种解决方案:

方案一:手动调整UV坐标(适合必须用ExtrudeGeometry的场景)

如果你的Shape以后可能不是简单矩形,需要保留ExtrudeGeometry,那我们可以手动遍历几何体的UV属性,为每个面计算正确的UV值:

let generate_box = (width, height, depth) => {
    let extrudeSettings = {
        depth: depth,
        bevelEnabled: false,
    }
    
    const shape = new THREE.Shape();
    shape.lineTo(0, height);
    shape.lineTo(width, height);
    shape.lineTo(width, 0);
    
    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
    
    // 获取UV和位置属性
    const uvAttribute = geometry.attributes.uv;
    const positions = geometry.attributes.position;
    
    // 遍历每个顶点,重新计算UV
    for (let i = 0; i < uvAttribute.count; i++) {
        const x = positions.getX(i);
        const y = positions.getY(i);
        const z = positions.getZ(i);
        
        // 处理顶部/底部面(z坐标接近±depth/2)
        if (Math.abs(z - depth/2) < 0.001 || Math.abs(z + depth/2) < 0.001) {
            uvAttribute.setXY(i, x / width, y / height);
        } 
        // 处理前后侧面(x坐标接近0或width)
        else if (Math.abs(x) < 0.001 || Math.abs(x - width) < 0.001) {
            uvAttribute.setXY(i, z / depth, y / height);
        } 
        // 处理左右侧面(y坐标接近0或height)
        else if (Math.abs(y) < 0.001 || Math.abs(y - height) < 0.001) {
            uvAttribute.setXY(i, x / width, z / depth);
        }
    }
    // 标记UV属性需要更新
    uvAttribute.needsUpdate = true;
    
    return geometry;
};

另外,你还可以根据需要设置纹理的重复模式,让纹理在面上重复显示:

material.map.wrapS = THREE.RepeatWrapping;
material.map.wrapT = THREE.RepeatWrapping;
// 比如让纹理在x方向重复2次,y方向不重复
// material.map.repeat.set(2, 1);

方案二:改用BoxGeometry(更简单高效)

如果你的需求只是创建一个普通长方体,那完全没必要用ExtrudeGeometry!BoxGeometry是Three.js专门为长方体设计的几何体,默认就会生成正确的UV映射,代码也更简洁:

import wood from "./wood_texture.jpg"

// 直接创建BoxGeometry,参数对应width, height, depth
let box_geo = new THREE.BoxGeometry(0.5, 2.2, 0.35);
let textureLoader = new THREE.TextureLoader();
let material = new THREE.MeshStandardMaterial({ 
    color: "rgb(248, 247, 247)", 
    map: textureLoader.load(wood) 
});

box_mesh = new THREE.Mesh(box_geo, material);
scene.add(box_mesh);

总结

  • 先修正this.height的错误,确保几何体形态正确
  • 如果是普通长方体,优先用BoxGeometry,省心又高效
  • 如果必须用ExtrudeGeometry,手动调整UV坐标就能得到你想要的纹理效果

内容的提问来源于stack exchange,提问作者Reza Aalaei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 17:01:48