Three.js网格图片纹理适配问题:如何保持图片比例不拉伸?
问题描述
我在Blender中创建的GLTF文件里定义了一个固定尺寸的网格区域,用于展示用户上传的产品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
相关产品推荐
相关产品推荐

