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

如何在Three.js中为加载的OBJ模型实现等尺寸棋盘格纹理统一显示

解决Three.js中OBJ模型棋盘格纹理尺寸不均的问题

这是个很常见的纹理映射问题,核心原因要么是OBJ模型自带的UV坐标没有统一规范,要么是纹理的重复/映射参数没适配模型的几何体特征。下面给你几个实用的解决思路,结合你的代码来调整:

1. 先调整纹理的基础参数

首先确保纹理支持重复映射,不然超出UV范围的部分会拉伸而不是重复。修改你的纹理加载代码:

texture = textureLoader.load(currentTextureUrl); // texture checker image
// 开启重复包裹模式
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// 设置重复次数,先尝试一个适中的值,比如(5,5),后续根据效果调整
texture.repeat.set(5, 5);
texture.needsUpdate = true; // 你之前写的onUpdate是错误属性,应该用needsUpdate

不过这个方法只适用于模型各部分缩放比例接近的情况,如果模型不同网格大小差异大,还是会出现棋盘格大小不一的问题,所以需要结合UV坐标的调整。

2. 基于几何体边界盒重新计算UV坐标

OBJ模型的每个网格可能有自己的尺寸,我们可以针对每个网格的边界盒(BoundingBox)来生成均匀的UV,让纹理在每个网格上的重复密度一致。修改你遍历模型的代码:

object.traverse(function(child) {
    if (child.type.toLowerCase() == "mesh" && child.material && child.geometry) { 
        const geom = child.geometry;
        // 计算几何体的边界盒
        geom.computeBoundingBox();
        const bbox = geom.boundingBox;
        const bboxSize = bbox.getSize(new THREE.Vector3());
        
        // 获取UV属性,重新计算每个顶点的UV值
        const uvAttribute = geom.attributes.uv;
        for (let i = 0; i < uvAttribute.count; i++) {
            // 基于顶点在边界盒内的相对位置计算UV,乘以重复次数控制棋盘格大小
            const u = (geom.attributes.position.getX(i) - bbox.min.x) / bboxSize.x * 5;
            const v = (geom.attributes.position.getY(i) - bbox.min.y) / bboxSize.y * 5;
            uvAttribute.setXY(i, u, v);
        }
        uvAttribute.needsUpdate = true; // 标记UV属性需要更新
        
        // 应用纹理到材质
        if (child.material.length) { 
            for (var i=0; i < child.material.length; i++) { 
                child.material[i].map = texture; 
                child.material[i].needsUpdate = true; 
            } 
        } else { 
            child.material.map = texture; 
            child.material.needsUpdate = true; 
        } 
    } 
});

这个方法的核心是让每个网格的UV都基于自身的尺寸来映射,这样不管网格多大,棋盘格的大小都会保持相对一致。你可以调整代码里的*5这个乘数来控制棋盘格的大小——数值越大,棋盘格越小。

3. 检查模型本身的UV(根源解决)

如果上面的方法效果还是不好,可能是你导出的OBJ模型本身UV没有正确展开。比如在Blender这类3D软件中,模型的UV可能被拉伸或者没有均匀分布,导致纹理映射异常。你可以:

  • 用Blender打开OBJ模型,切换到UV编辑器查看UV布局
  • 对模型重新进行UV展开(比如用智能UV展开功能),确保UV在UV编辑器里均匀分布
  • 重新导出OBJ模型,再导入Three.js中测试

修改后的完整加载流程示例

把上面的调整整合到你的代码里,大概是这样:

function loadModel() { 
    // 这里无需再处理纹理,因为我们在loader回调里已经完成了处理
    scene.add( object ); 
} 

manager = new THREE.LoadingManager( loadModel ); 
manager.onProgress = function ( item, loaded, total ) { 
    console.log( item, loaded, total ); 
}; 

textureLoader = new THREE.TextureLoader( manager ); 
texture = textureLoader.load(currentTextureUrl); 
// 配置纹理参数
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(5, 5);
texture.needsUpdate = true;

function onProgress( xhr ) { 
    if ( xhr.lengthComputable ) { 
        var percentComplete = xhr.loaded / xhr.total * 100; 
        console.log( 'model ' + Math.round( percentComplete, 2 ) + '% downloaded' ); 
    } 
} 

function onError() {} 

var loader = new THREE.OBJLoader( manager ); 
loader.load(modals.currentModal.objectFile, function ( obj ) { 
    object = obj;

    // 遍历模型处理每个网格的UV和纹理
    object.traverse(function(child) {
        if (child.type.toLowerCase() == "mesh" && child.material && child.geometry) { 
            const geom = child.geometry;
            geom.computeBoundingBox();
            const bbox = geom.boundingBox;
            const bboxSize = bbox.getSize(new THREE.Vector3());
            
            const uvAttribute = geom.attributes.uv;
            for (let i = 0; i < uvAttribute.count; i++) {
                const u = (geom.attributes.position.getX(i) - bbox.min.x) / bboxSize.x * 5;
                const v = (geom.attributes.position.getY(i) - bbox.min.y) / bboxSize.y * 5;
                uvAttribute.setXY(i, u, v);
            }
            uvAttribute.needsUpdate = true;
            
            if (child.material.length) { 
                for (var i=0; i < child.material.length; i++) { 
                    child.material[i].map = texture; 
                    child.material[i].needsUpdate = true; 
                } 
            } else { 
                child.material.map = texture; 
                child.material.needsUpdate = true; 
            } 
        } 
    });
}, onProgress, onError );

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:44:02