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

Three.js中缩放网格时如何保持纹理尺寸不变?

解决Three.js中Mesh缩放时纹理保持固定尺寸的问题

核心问题

默认情况下Three.js会把纹理的0-1 UV范围铺满整个Mesh表面,所以Mesh尺寸变化时,纹理必然跟着拉伸。要让纹理保持64x64的固定显示尺寸,得通过调整纹理的重复模式和重复参数,把纹理的显示单位和Mesh的物理尺寸绑定起来。

具体步骤

1. 配置纹理基础属性

先修改你的材质创建函数,给纹理开启重复包裹模式,这是后续调整的前提:

function _createMaterial(url: string): THREE.MeshBasicMaterial {
    let material = new THREE.MeshBasicMaterial();

    this.loader.load(url, (texture) => {
        texture.magFilter = THREE.NearestFilter;
        texture.minFilter = THREE.LinearMipMapLinearFilter;
        // 开启纹理重复模式,否则repeat参数无效
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        // 初始Mesh为64x64,repeat设为1,1刚好铺满
        texture.repeat.set(1, 1);
        material.setValues({ map: texture });
    });
    return material;
}

2. 动态调整纹理重复值

当Mesh尺寸(修改几何体参数或调整mesh.scale)变化时,重新计算纹理的repeat值,确保每个纹理单元保持64x64的大小:

// 每次Mesh尺寸变化时调用此函数
function updateTextureRepeat(mesh: THREE.Mesh, textureSize = 64) {
    const texture = (mesh.material as THREE.MeshBasicMaterial).map;
    if (!texture) return;

    let targetWidth, targetHeight;
    // 分两种场景处理尺寸计算
    if (mesh.geometry instanceof THREE.PlaneGeometry) {
        // 直接读取几何体的宽高参数
        targetWidth = mesh.geometry.parameters.width;
        targetHeight = mesh.geometry.parameters.height;
    } else {
        // 若通过scale缩放Mesh,基于初始基础尺寸计算实际大小(示例初始为64x64)
        const baseWidth = 64;
        const baseHeight = 64;
        targetWidth = baseWidth * mesh.scale.x;
        targetHeight = baseHeight * mesh.scale.y;
    }

    // 计算重复次数:Mesh实际尺寸 / 纹理固定尺寸
    texture.repeat.set(targetWidth / textureSize, targetHeight / textureSize);
    // 标记纹理需要更新,否则设置不会生效
    texture.needsUpdate = true;
}

3. 原理说明

  • 当Mesh宽为64时,repeat.x = 64/64 = 1,纹理完整显示一次,和初始正常效果一致;
  • 当Mesh宽为16时,repeat.x = 16/64 = 0.25,纹理只显示左半部分的1/4,且不会被拉伸;
  • 当Mesh宽为128时,repeat.x = 128/64 = 2,纹理横向重复两次,每个单元仍保持64的宽度,无变形。

额外提示

  • 如果使用自定义几何体,要确保UV坐标是标准的0-1映射(比如平面UV对应宽高方向);
  • 若想让小尺寸Mesh上的纹理居中显示,可添加texture.offset.set((1 - texture.repeat.x)/2, (1 - texture.repeat.y)/2)(仅当repeat小于1时生效);
  • 每次修改repeat或offset后,必须设置texture.needsUpdate = true,否则Three.js不会更新纹理缓存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:02:16