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
相关产品推荐
相关产品推荐

