You need to enable JavaScript to run this app. Three.js ExtrudeGeometry 挤压几何体材质纹理不显示问题排查
优惠活动
大模型
产品
解决方案
定价
更多

Three.js ExtrudeGeometry 挤压几何体材质纹理不显示问题排查

Three.js ExtrudeGeometry 自定义形状挤压后纹理不渲染的修复方案

代码里的具体问题

  • Shape绘制存在硬逻辑bug
    初始化Shape时连续调用两次moveTo:第一次将画笔定位到walls[0].p1坐标后,未执行连线就再次调用moveTo定位到walls[0].p2,第一个点位完全被跳过,最终生成的闭合形状和预期墙体边界完全不符,挤压生成的几何体本身拓扑就是错误的。
    对应修复:将第二次moveTo改为lineTo,确保从第一个点位连线到第二个点位,再循环追加后续墙体点位。
  • ExtrudeGeometry默认UV尺度不匹配大坐标场景
    ExtrudeGeometry生成上下两个端面的UV时,会直接将Shape平面上的顶点XY坐标值作为UV值,不会自动将UV归一化到0-1的标准区间。由于你的Shape是基于实际墙体的世界坐标绘制,尺度通常达到几十甚至上百单位,生成的UV值远大于1,哪怕开启了RepeatWrapping,纹理的平铺密度也和预期偏差极大,视觉效果和纹理完全不渲染一致。
    对应修复:挤压生成几何体后,手动遍历几何体的UV属性,将UV值归一化到0-1区间,再配合设置的repeat参数调整平铺密度;也可以在绘制Shape时提前将所有点位平移到坐标原点附近,缩小Shape的整体包围盒尺度,让生成的UV值自然落在合理范围。
  • 纹理旋转设置遗漏核心参数
    给纹理设置90度旋转时,Three.js默认的纹理旋转中心是纹理坐标系的左上角,旋转后采样范围会直接偏移到有效像素外,导致采样结果为全黑或全透明。
    对应修复:设置纹理旋转属性时,同步通过texture.center.set(0.5, 0.5)将旋转中心调整到纹理中心,避免采样偏移。
  • 变量命名存在潜在冲突
    代码中将纹理实例命名为Texture,和Three.js内置的THREE.Texture类名重名,容易出现作用域覆盖的问题,建议改为小写开头的实例名避免冲突。

核心修复逻辑参考代码

// 修正Shape绘制逻辑
const shape = new THREE.Shape();
shape.autoClose = true;
shape.moveTo(walls[0].p1.x, -walls[0].p1.z);
shape.lineTo(walls[0].p2.x, -walls[0].p2.z); // 替换原错误的moveTo调用
for (var j = 1; j < walls.length; j++) {
    shape.lineTo(walls[j].p1.x, -walls[j].p1.z);
    shape.lineTo(walls[j].p2.x, -walls[j].p2.z);
}

const extrudeSettings = {
    steps: 1, 
    depth: 5, 
    bevelEnabled: false
};

// 初始化材质与纹理加载逻辑
const floor_material = new THREE.MeshPhongMaterial({ color: 0xaaaaaa });
const loader = new THREE.TextureLoader();

const grassTexture = loader.load("assets/textures/grassbw.jpg", texture => {
    // 纹理属性在加载成功后统一配置
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(60, 60);
    texture.center.set(0.5, 0.5); // 修正旋转中心
    texture.rotation = Math.PI / 2;
    floor_material.map = texture;
    floor_material.needsUpdate = true;
});

// 生成挤压几何体
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// 归一化UV坐标
geometry.computeBoundingBox();
const bbox = geometry.boundingBox;
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
    const u = uvAttribute.getX(i);
    const v = uvAttribute.getY(i);
    // 基于几何体包围盒将UV缩放到0-1区间
    const normalizedU = (u - bbox.min.x) / (bbox.max.x - bbox.min.x);
    const normalizedV = (v - bbox.min.y) / (bbox.max.y - bbox.min.y);
    uvAttribute.setXY(i, normalizedU, normalizedV);
}
uvAttribute.needsUpdate = true;

geometry.computeFaceNormals();
const mesh = new THREE.Mesh(geometry, floor_material);
mesh.receiveShadow = true;

补充提示:ExtrudeGeometry默认会生成两个材质组,索引0对应上下两个端面,索引1对应挤压形成的竖直侧面。如果需要给端面和侧面分别配置不同材质,可以在实例化Mesh时传入材质数组,无需修改几何体本身的UV逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 11:27:04