Three.js中纹理特定三角区域跨纹理映射实现咨询及代码需求
在Three.js中实现纹理三角形区域到异形变体三角形的映射
完全可以实现,核心是用自定义着色器(ShaderMaterial)手动处理纹理坐标的变换——Three.js默认的UV映射是基于四边形的,要做三角形到三角形的映射,得靠仿射变换(如果是透视关系就用透视变换)来计算对应坐标。
核心思路
给定源纹理里的一个三角形(三个顶点的UV坐标:uvA, uvB, uvC),以及目标几何体上的变形三角形(三个顶点位置:posA, posB, posC),我们可以在着色器里这么做:
- 给每个顶点分配重心坐标权重,顶点着色器里把这个值传给片元着色器
- 片元着色器里用重心坐标插值出对应的源纹理UV,完成映射
示例代码
下面是一个最小可运行的示例,用一个三角形几何体作为目标载体,把源纹理里的某块三角形区域映射到变形后的三角形上:
import * as THREE from 'three'; // 初始化基础场景 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 加载你的源纹理(替换成自己的图片路径) const textureLoader = new THREE.TextureLoader(); const sourceTexture = textureLoader.load('your-source-texture.jpg'); sourceTexture.wrapS = THREE.ClampToEdgeWrapping; sourceTexture.wrapT = THREE.ClampToEdgeWrapping; // 定义源纹理里的三角形UV(这里取纹理左上角、右上角、左下角区域,可自行调整) const sourceUVs = { A: new THREE.Vector2(0, 1), B: new THREE.Vector2(1, 1), C: new THREE.Vector2(0, 0), }; // 定义目标变形三角形的顶点位置 const targetVertices = [ -1, 1, 0, // 顶点A 2, 0.5, 0, // 顶点B -0.5, -1, 0 // 顶点C ]; // 创建三角形几何体 const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.Float32BufferAttribute(targetVertices, 3)); // 给每个顶点设置重心坐标权重(分别对应三个顶点的权重) geometry.setAttribute('barycentric', new THREE.Float32BufferAttribute([ 1, 0, 0, 0, 1, 0, 0, 0, 1 ], 3)); // 自定义着色器代码 const vertexShader = ` attribute vec3 barycentric; varying vec3 vBarycentric; void main() { vBarycentric = barycentric; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `; const fragmentShader = ` uniform sampler2D sourceTexture; uniform vec2 uvA; uniform vec2 uvB; uniform vec2 uvC; varying vec3 vBarycentric; void main() { // 用重心坐标插值计算当前像素对应的源纹理UV vec2 sourceUV = vBarycentric.x * uvA + vBarycentric.y * uvB + vBarycentric.z * uvC; // 采样源纹理 gl_FragColor = texture2D(sourceTexture, sourceUV); } `; // 创建着色器材质 const material = new THREE.ShaderMaterial({ uniforms: { sourceTexture: { value: sourceTexture }, uvA: { value: sourceUVs.A }, uvB: { value: sourceUVs.B }, uvC: { value: sourceUVs.C }, }, vertexShader, fragmentShader, side: THREE.DoubleSide, // 开启双面渲染,避免看不到背面 }); // 创建网格并加入场景 const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); camera.position.z = 3; // 渲染循环 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); // 窗口大小适配 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
几点说明
- 重心坐标:每个顶点的
barycentric属性是该顶点在三角形中的权重,片元着色器通过插值得到当前像素在目标三角形中的位置,再用这个位置去匹配源纹理的三角形区域。 - 如果你需要处理透视关系(比如源和目标三角形不在同一平面),可以把仿射变换换成透视变换矩阵,计算逻辑会复杂一些,但核心思路还是用重心坐标或矩阵变换来映射UV。
- 替换
your-source-texture.jpg为你的实际纹理路径,调整sourceUVs和targetVertices的值就能改变源三角形区域和目标三角形的形状位置。
内容的提问来源于stack exchange,提问作者fresh
相关产品推荐
相关产品推荐

