Skip to content

一、UV映射原理(顶点纹理坐标)

texture-2.png

1. 纹理UV坐标

  • 纹理坐标含义就是一面意思,一张纹理贴图图像的坐标,选择一张图片,比如以图片左下角为坐标原点,右上角为坐标(1.0,1.0), 图片上所有位置纵横坐标都介于0.0~1.0之间。

2. 映射

  • 纹理UV坐标和顶点位置坐标是一一对应关系,这也就是为什么一张图片可以映射到一个模型的表面, 只要把图片的每个纹理坐标和模型的顶点位置建立一对一的关系,就可以实现图像到模型的映射。 texture-3.png
  • 矩形贴图和球面的映射图 texture-4.png

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坐标。
    javascript
    const 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坐标。
    javascript
    var 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;
      })
    })

Released under the MIT License.