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

Three.js网格图片纹理适配问题:如何保持图片比例不拉伸?

问题描述

我在Blender中创建的GLTF文件里定义了一个固定尺寸的网格区域,用于展示用户上传的产品Logo。该网格区域有特定宽高,用户可上传任意尺寸的图片,但目前上传的图片会随网格尺寸被拉伸,我需要保持图片原比例,缩小图片以适配网格区域,避免拉伸。

当前网格纹理效果

当前网格纹理效果

原始Logo图片

原始Logo图片

预期网格纹理效果

预期网格纹理效果

现有Three.js纹理代码

$scope.loadTexture(textureImage).then((texture) => {
    texture.encoding = THREE.sRGBEncoding;
    if (currentMesh.texture_rotation != undefined) {
        texture.rotation = currentMesh.texture_rotation;
    }

    texture.repeat.x = currentMesh.texture_repeat_x;
    texture.repeat.y = currentMesh.texture_repeat_y;
    texture.flipY = currentMesh.flipY;
    texture.anisotropy = currentMesh.anisotropy;
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

    node.material.map = texture;
    node.material.map.minFilter = currentMesh.texture_min_filter;
    node.material.map.magFilter = currentMesh.texture_mag_filter;
    node.material.needsUpdate = true;
});
解决方案

要实现图片保持原比例适配网格,核心是计算纹理的缩放比例和偏移量,让图片在网格内居中且不拉伸。

步骤1:计算适配比例

加载纹理后,对比图片宽高比与网格宽高比,取较小的缩放比例保证图片完全适配网格:

// 替换为你的网格实际宽高比,可从GLTF模型的几何体或预设值获取
const meshAspect = currentMesh.width / currentMesh.height; 
const imageAspect = texture.image.width / texture.image.height;

let scaleX = 1;
let scaleY = 1;

// 计算不拉伸的缩放比例
if (imageAspect > meshAspect) {
    scaleX = meshAspect / imageAspect;
} else {
    scaleY = imageAspect / meshAspect;
}

步骤2:调整纹理参数

将纹理的重复模式改为ClampToEdgeWrapping避免图片重复,同时设置缩放比例和居中偏移:

texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
texture.repeat.set(scaleX, scaleY);
// 计算居中偏移量
texture.offset.set((1 - scaleX) / 2, (1 - scaleY) / 2);

修改后的完整代码

$scope.loadTexture(textureImage).then((texture) => {
    texture.encoding = THREE.sRGBEncoding;
    if (currentMesh.texture_rotation != undefined) {
        texture.rotation = currentMesh.texture_rotation;
    }

    // 新增比例适配逻辑
    const meshAspect = currentMesh.width / currentMesh.height;
    const imageAspect = texture.image.width / texture.image.height;

    let scaleX = 1;
    let scaleY = 1;

    if (imageAspect > meshAspect) {
        scaleX = meshAspect / imageAspect;
    } else {
        scaleY = imageAspect / meshAspect;
    }

    texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
    texture.repeat.set(scaleX, scaleY);
    texture.offset.set((1 - scaleX) / 2, (1 - scaleY) / 2);

    // 保留原有配置
    texture.flipY = currentMesh.flipY;
    texture.anisotropy = currentMesh.anisotropy;

    node.material.map = texture;
    node.material.map.minFilter = currentMesh.texture_min_filter;
    node.material.map.magFilter = currentMesh.texture_mag_filter;
    node.material.needsUpdate = true;
});

注意事项

  • 若网格UV不是标准0-1范围,需先获取UV的实际宽高比调整计算逻辑;
  • 确保currentMesh.width和currentMesh.height能正确获取网格尺寸,可通过几何体boundingBox或GLTF模型的缩放参数计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:50:02