three.js中如何从材质获取纹理偏移以计算面内纹理位置?
Three.js加载DAE模型时获取网格面对应纹理区域位置的实现方案
方案1:UV坐标映射计算(性能最优,推荐优先使用)
- 完成DAE模型加载后,先从模型场景中递归筛选到目标网格对象,可通过
name属性、几何尺寸等标识匹配,类型为THREE.Mesh - 获取目标面对应的顶点索引:如果是三角面,可通过
mesh.geometry.index.array拿到该面三个顶点的索引值;如果是导出的矩形面,可提取四个顶点的索引 - 用顶点索引读取UV属性:从
mesh.geometry.attributes.uv.array中提取对应顶点的UV坐标,UV坐标值域为[0,1],分别对应纹理图的横向、纵向相对位置 - 坐标转换计算:
- 纹理的实际像素尺寸可通过
texture.image.width、texture.image.height获取 - 纹理像素y轴与UV坐标y轴方向相反,某点对应纹理的像素坐标计算公式为:
x = u * 纹理宽度y = (1 - v) * 纹理高度 - 区域尺寸计算公式为:
区域宽度 = (u_max - u_min) * 纹理宽度区域高度 = (v_max - v_min) * 纹理高度
- 纹理的实际像素尺寸可通过
- 示例代码:
import { ColladaLoader } from 'three/addons/loaders/ColladaLoader.js'; const loader = new ColladaLoader(); loader.load('你的模型路径.dae', (collada) => { // 筛选目标网格,此处假设目标网格name属性为targetRect const targetMesh = collada.scene.getObjectByName('targetRect'); const geometry = targetMesh.geometry; // 读取UV属性 const uvAttribute = geometry.attributes.uv; // 读取网格绑定的纹理 const targetTexture = targetMesh.material.map; const texWidth = targetTexture.image.width; const texHeight = targetTexture.image.height; // 示例:提取第0个三角面的UV并转换为像素坐标 const faceVertexIndices = [ geometry.index.array[0], geometry.index.array[1], geometry.index.array[2] ]; const pixelPositions = faceVertexIndices.map(idx => { const u = uvAttribute.getX(idx); const v = uvAttribute.getY(idx); return { x: Math.round(u * texWidth), y: Math.round((1 - v) * texHeight) } }); console.log('面顶点对应纹理像素坐标:', pixelPositions); });
方案2:GPU离屏渲染拾取(适合仅能通过颜色识别区域的场景)
- 创建和目标纹理尺寸一致的
THREE.WebGLRenderTarget离屏渲染对象 - 自定义编码着色器材质:顶点着色器直接传递UV坐标到片元着色器,片元着色器将UV的u、v值编码为RGBA颜色输出
- 替换目标网格的原有材质为上述自定义材质,将网格渲染到离屏渲染目标
- 读取离屏渲染的像素缓冲区数据,遍历匹配红色矩形的颜色区域,解码对应像素的RGBA值得到UV坐标,再转换为纹理实际尺寸位置
- 该方案无需提前知道目标区域的顶点坐标,适合交互拾取、不规则区域识别场景,但性能低于方案1
常见问题排查
- 若计算出的坐标出现上下翻转,可调整纹理的
flipY属性:targetTexture.flipY = false,DAE模型导出时的UV设置不同可能会导致翻转不一致 - 如果网格存在多套纹理,确认读取的UV属性和纹理对应,部分模型会存在
uv2等多套UV通道
内容的提问来源于stack exchange,提问作者Mateusz Piwnicki
相关产品推荐
相关产品推荐

