一、UV映射原理(顶点纹理坐标)
1. 纹理UV
坐标
- 纹理坐标含义就是一面意思,一张纹理贴图图像的坐标,选择一张图片,比如以图片左下角为坐标原点,右上角为坐标
(1.0,1.0)
, 图片上所有位置纵横坐标都介于0.0~1.0
之间。
2. 映射
- 纹理
UV
坐标和顶点位置坐标是一一对应关系,这也就是为什么一张图片可以映射到一个模型的表面, 只要把图片的每个纹理坐标和模型的顶点位置建立一对一的关系,就可以实现图像到模型的映射。 - 矩形贴图和球面的映射图
3. 两组UV坐标
- 几何体有两组UV坐标,第一组组用于
.map
、.normalMap
、.specularMap
等贴图的映射, 第二组用于阴影贴图.lightMap
的映射。
4. 修改纹理坐标
- 几何体表面所有位置全部对应贴图
(0.4,0.4)
坐标位置的像素值,这样话网格模型不会显示完整的地图,而是显示采样点纹理坐标(0.4,0.4)
对应的RGB
值。javascript//矩形平面,细分数默认1,即2个三角形拼接成一个矩形 const geometry = new THREE.PlaneGeometry(204, 102); /** * 遍历uv坐标 */ geometry.faceVertexUvs[0].forEach(elem => { elem.forEach(Vector2 => { // 所有的UV坐标全部设置为一个值 Vector2.set(0.4,0.4); }); });
- 原来几何体平面默认是两个三角形构成,把细分数设置为
4
,三角形数量变为16
个。javascript// 矩形平面 设置细分数4,4 const geometry = new THREE.PlaneGeometry(204, 102, 4, 4); /** * 局部三角面显示完整纹理贴图 */ const t0 = new THREE.Vector2(0, 1); //图片左下角 const t1 = new THREE.Vector2(0, 0); //图片右下角 const t2 = new THREE.Vector2(1, 0); //图片右上角 const t3 = new THREE.Vector2(1, 1); //图片左上角 const uv1 = [t0, t1, t3]; //选中图片一个三角区域像素——用于映射到一个三角面 const uv2 = [t1, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面 // 设置第五、第六个三角形面对应的纹理坐标 geometry.faceVertexUvs[0][4] = uv1 geometry.faceVertexUvs[0][5] = uv2
5. Geometry
自定义顶点UV坐标
- 一般
three.ts
的球体、圆柱等几何体创建的时候,都会通过特定算法自动生成几何体的UV
坐标。 - 通过几何体
Geometry
自定义了一个由两个三角形组成的矩形几何体,并且通过几何体的.faceVertexUvs[0]
属性设置了每个顶点对应的第一组UV
坐标。javascriptconst geometry = new THREE.Geometry(); //创建一个空几何体对象 /**顶点坐标(纹理映射位置)*/ const p1 = new THREE.Vector3(0,0,0); //顶点1坐标 const p2 = new THREE.Vector3(160,0,0); //顶点2坐标 const p3 = new THREE.Vector3(160,80,0); //顶点3坐标 const p4 = new THREE.Vector3(0,80,0); //顶点4坐标 geometry.vertices.push(p1,p2,p3,p4); //顶点坐标添加到geometry对象 /** 三角面1、三角面2*/ const normal = new THREE.Vector3( 0, 0, 1 ); //三角面法向量 const face0 = new THREE.Face3( 0, 1, 2, normal); //三角面1 const face1 = new THREE.Face3( 0, 2, 3, normal); //三角面2 geometry.faces.push( face0,face1 ); //三角面1、2添加到几何体 /**纹理坐标*/ const t0 = new THREE.Vector2(0,0);//图片左下角 const t1 = new THREE.Vector2(1,0);//图片右下角 const t2 = new THREE.Vector2(1,1);//图片右上角 const t3 = new THREE.Vector2(0,1);//图片左上角 uv1 = [t0,t1,t2];//选中图片一个三角区域像素——映射到三角面1 uv2 = [t0,t2,t3];//选中图片一个三角区域像素——映射到三角面2 geometry.faceVertexUvs[0].push(uv1,uv2);//纹理坐标传递给纹理三角面属性
6. BufferGeometry
自定义顶点UV坐标
- 通过几何体
BufferGeometry
自定义了一个由两个三角形组成的矩形几何体,并且通过几何体的.attributes.uv
属性设置了每个顶点对应的第一组UV坐标。javascriptvar geometry = new THREE.BufferGeometry(); //声明一个空几何体对象 //类型数组创建顶点位置position数据 const vertices = new Float32Array([ 0, 0, 0, //顶点1坐标 80, 0, 0, //顶点2坐标 80, 80, 0, //顶点3坐标 0, 80, 0, //顶点4坐标 ]); // 创建属性缓冲区对象 const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组 // 设置几何体attributes属性的位置position属性 geometry.attributes.position = attribue const normals = new Float32Array([ 0, 0, 1, //顶点1法向量 0, 0, 1, //顶点2法向量 0, 0, 1, //顶点3法向量 0, 0, 1, //顶点4法向量 ]); // 设置几何体attributes属性的位置normal属性 geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标 // Uint16Array类型数组创建顶点索引数据 const indexes = new Uint16Array([ 0, 1, 2, 0, 2, 3, ]) // 索引数据赋值给几何体的index属性 geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组 /**纹理坐标*/ const uvs = new Float32Array([ 0,0, //图片左下角 1,0, //图片右下角 1,1, //图片右上角 0,1, //图片左上角 ]); // 设置几何体attributes属性的位置normal属性 geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2); //2个为一组,表示一个顶点的纹理坐标
7. 加载一个包含UV坐标的模型文件
- 通过
three。js
加载一个包含UV坐标的外部三维模型文件,加载成功后,给模型设置一张贴图.javascript// 创建一个加载threejs格式JSON文件的加载器 const loader = new THREE.ObjectLoader(); // TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理 const textureLoader = new THREE.TextureLoader(); loader.load('model.json',function (obj) { console.log(obj); scene.add(obj);//加载返回的对象插入场景中 // 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture textureLoader.load('Earth.png', function(texture) { // 设置球体网格模型材质的map属性 obj.children[0].material.map = texture; // 告诉threejs渲染器系统,材质对象的map属性已更新 obj.children[0].material.needsUpdate=true; }) })