Three.js图片纹理如何实现缩放适配并居中显示?
图片适配相框区域问题
我尝试将图片适配到相框及类似区域中,只有部分与图片尺寸相近的相框能正常显示,多数情况下无法正确适配。
原图

异常适配效果




当前代码(仅适配尺寸相近的相框)
var texture = null; var material = null const loader = new THREE.TextureLoader() texture = await loader.load(media, async img => { if(invertX) { texture.wrapS = THREE.RepeatWrapping; texture.repeat.x = - 1; } if(invertY) { texture.flipY = false; } material = new THREE.MeshBasicMaterial({ map: texture }); elm.material = material; });
尝试过的无效代码片段
// const planeGeom = new THREE.PlaneGeometry(1,1)//(16, 9) // const planeAspect = planeGeom.parameters.width / planeGeom.parameters.height; // const imageAspect = texture.image.width / texture.image.height; // const aspect = imageAspect / planeAspect; // 无效 // let imgRatio = img.image.width / img.image.height; // let planeGeom = new THREE.PlaneGeometry(1,1)//16, 9) // let planeRatio = planeGeom.parameters.width / planeGeom.parameters.height; // texture.wrapS = THREE.RepeatWrapping; // // texture.repeat.x = planeRatio / imgRatio; // texture.offset.x = -0.5 * ((planeRatio / imgRatio) - 1); // 同样无效 // const aspectOfPlane = planeGeom.parameters.width / planeGeom.parameters.height; // const aspectOfImage = image.width / image.height; // let yScale = 1; // let xScale = aspectOfPlane / aspectOfImage; // if (xScale > 1) { // 无法覆盖,改用x轴基准 // xScale = 1; // yScale = aspectOfImage / aspectOfPlane; // } // texture.repeat.set(xScale, yScale); // texture.offset.set((1 - xScale) / 2, (1 - yScale) / 2); // 另一次尝试,还是不行 // var repeatX, repeatY; // texture.wrapS = THREE.RepeatWrapping; // texture.wrapT = THREE.RepeatWrapping; // if (img.image.height < img.image.width) { // repeatX = planeGeom.parameters.width * img.image.height / (planeGeom.parameters.height *img.image.width); // repeatY = 1; // texture.repeat.set(repeatX, repeatY); // texture.offset.x = (repeatX - 1) / 2 * -1; // } else { // repeatX = 1; // repeatY = planeGeom.parameters.width * img.image.width / (planeGeom.parameters.height * img.image.height); // texture.repeat.set(repeatX, repeatY); // texture.offset.y = (repeatY - 1) / 2 * -1; // }
解决方案:自动缩放居中适配
核心是对比图片与相框平面的宽高比,通过调整纹理的repeat和offset参数,实现类似CSS object-fit的适配效果,以下提供两种常用适配方案:
方案1:覆盖式适配(填满相框,裁剪超出部分)
var texture = null; var material = null; const loader = new THREE.TextureLoader(); texture = await loader.load(media, async (img) => { // 保留原翻转逻辑 if(invertX) { texture.wrapS = THREE.RepeatWrapping; texture.repeat.x = -1; } if(invertY) { texture.flipY = false; } // 获取图片和相框平面的宽高比 const imageAspect = img.width / img.height; const planeGeom = elm.geometry; // elm为你的相框网格对象 const planeAspect = planeGeom.parameters.width / planeGeom.parameters.height; let repeatX, repeatY; let offsetX = 0, offsetY = 0; // 计算适配比例 if (imageAspect > planeAspect) { // 图片更宽,按高度适配,裁剪左右 repeatY = 1; repeatX = imageAspect / planeAspect; offsetX = (1 - repeatX) / 2; } else { // 图片更高,按宽度适配,裁剪上下 repeatX = 1; repeatY = planeAspect / imageAspect; offsetY = (1 - repeatY) / 2; } // 设置纹理参数,避免重复显示 texture.wrapS = THREE.ClampToEdgeWrapping; texture.wrapT = THREE.ClampToEdgeWrapping; texture.repeat.set(repeatX, repeatY); texture.offset.set(offsetX, offsetY); // 创建并应用材质 material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide // 可选,根据相框是否需要双面显示 }); elm.material = material; });
方案2:包含式适配(完整显示图片,留白填充)
如果需要完整展示图片,仅调整比例计算逻辑即可:
// 替换方案1中的比例计算部分 if (imageAspect > planeAspect) { // 图片更宽,按宽度适配,上下留白 repeatX = 1; repeatY = planeAspect / imageAspect; offsetY = (1 - repeatY) / 2; } else { // 图片更高,按高度适配,左右留白 repeatY = 1; repeatX = imageAspect / planeAspect; offsetX = (1 - repeatX) / 2; }
内容的提问来源于stack exchange,提问作者Caner
相关产品推荐
相关产品推荐

