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

使用GLTFExporter导出OBJ时如何生成缺失的vt顶点纹理坐标?

解决缺失纹理坐标的OBJ模型生成UV并导出GLTF的问题

你遇到的核心问题是:仅仅给模型材质添加纹理并不会自动生成几何体层面的纹理坐标(UV)——Three.js渲染时可以临时处理,但GLTFExporter需要几何体中存在uv属性才能将纹理坐标写入导出的GLTF文件。下面是具体的解决方案:

步骤1:为模型几何体生成UV坐标

首先需要手动为每个Mesh的BufferGeometry添加uv属性。这里提供一个基于模型包围盒生成UV的通用函数,你可以根据模型的形状调整UV的计算逻辑(比如用X/Z轴而非X/Y轴):

function generateUVs(geometry) {
    // 计算模型的包围盒,用于归一化坐标
    geometry.computeBoundingBox();
    const boundingBox = geometry.boundingBox;
    const positionAttr = geometry.attributes.position;
    // 创建UV属性,每个顶点对应2个浮点数(u, v)
    const uvAttr = new THREE.Float32BufferAttribute(positionAttr.count * 2, 2);
    
    for (let i = 0; i < positionAttr.count; i++) {
        const x = positionAttr.getX(i);
        const y = positionAttr.getY(i);
        // 基于包围盒归一化X/Y坐标生成UV,适配ARCore OpenGL ES的纹理方向(v轴翻转)
        const u = (x - boundingBox.min.x) / (boundingBox.max.x - boundingBox.min.x);
        const v = 1 - ((y - boundingBox.min.y) / (boundingBox.max.y - boundingBox.min.y));
        
        uvAttr.setXY(i, u, v);
    }
    
    // 将UV属性添加到几何体
    geometry.setAttribute('uv', uvAttr);
    geometry.attributes.uv.needsUpdate = true;
}

步骤2:修改OBJ加载逻辑,生成UV后再赋值材质

在你的loadBlockObject函数中,遍历Mesh的时候调用上面的生成函数,确保几何体拥有UV属性:

function loadBlockObject() { 
    var texture = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); 
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping; 
    texture.repeat.set(4, 4);
    // 注意:如果ARCore渲染出现纹理倒置,可以设置texture.flipY = false
    texture.flipY = false;
    var material = new THREE.MeshStandardMaterial({ map: texture }); 
    var loader = new OBJLoader(); 
    loader.load('models/obj/walt/block.obj', function (obj) { 
        obj.traverse(function (child) { 
            if (child instanceof THREE.Mesh) { 
                // 先为几何体生成UV
                generateUVs(child.geometry);
                // 再赋值材质
                child.material = material; 
            } 
        }); 
        obj.scale.multiplyScalar(4); 
        obj.position.set(400, 0, 0); 
        scene1.add(obj); 

        // 这里可以添加GLTF导出逻辑
        exportToGLTF(obj);
    }); 
}

步骤3:正确配置GLTFExporter导出

添加导出函数,确保导出选项包含纹理和材质相关设置:

function exportToGLTF(model) {
    const exporter = new GLTFExporter();
    exporter.parse(
        model,
        function(gltfData) {
            // 处理导出的GLTF数据,比如保存为文件
            const jsonString = JSON.stringify(gltfData, null, 2);
            // 示例:下载导出的文件
            const blob = new Blob([jsonString], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'block_with_uv.gltf';
            a.click();
            URL.revokeObjectURL(url);
        },
        function(error) {
            console.error('GLTF导出失败:', error);
        },
        {
            embedImages: true, // 将纹理嵌入GLTF(否则需要单独保存纹理文件)
            onlyVisible: true,
            truncateDrawRange: true
        }
    );
}

关键说明

  • ARCore的SceneView基于OpenGL ES,其纹理坐标的v轴方向与Three.js默认相反,所以生成UV时我们将v值设为1 - 归一化值,或者直接设置texture.flipY = false来适配。
  • 如果你需要更贴合模型形状的UV(比如球面、圆柱面),可以修改generateUVs函数的坐标计算逻辑,比如针对不同拓扑的模型使用不同的UV映射方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:55:32