Three.js几何体顶点纹理坐标UV
在课程的第二章对Threejs几何体Geometry和BufferGeometry的顶点概念做过比较多的介绍,讲解过顶点位置坐标数据、顶点颜色数据、顶点法线方向向量数据,不过顶点的UV数据没有去讲解,主要是几何体顶点的纹理坐标数据和纹理贴图的映射有关系,所以放在了本章节去讲解。
纹理UV坐标
纹理坐标含义就是一面意思,一张纹理贴图图像的坐标,选择一张图片,比如以图片左下角为坐标原点,右上角为坐标(1.0,1.0),图片上所有位置纵横坐标都介于0.0~1.0之间。
映射
纹理UV坐标和顶点位置坐标是一一对应关系,这也就是为什么一张图片可以映射到一个模型的表面,只要把图片的每个纹理坐标和模型的顶点位置建立一对一的关系,就可以实现图像到模型的映射。
矩形贴图和球面的映射图
两组UV坐标
几何体有两组UV坐标,第一组组用于.map
、.normalMap
、.specularMap
等贴图的映射,第二组用于阴影贴图.lightMap
的映射,这里不过过多阐述,本章节除了8.7用到的是第二组UV坐标,其它的章节内部程序用到的都是第一组UV坐标。
修改纹理坐标
你可以尝试修改上节课代码中几何体的纹理坐标,然后体会纹理坐标的作用。
几何体表面所有位置全部对应贴图(0.4,0.4)坐标位置的像素值,这样话网格模型不会显示完整的地图,而是显示采样点纹理坐标(0.4,0.4)
对应的RGB值。
//矩形平面,细分数默认1,即2个三角形拼接成一个矩形
var geometry = new THREE.PlaneGeometry(204, 102);
...
/**
* 遍历uv坐标
*/
geometry.faceVertexUvs[0].forEach(elem => {
elem.forEach(Vector2 => {
// 所有的UV坐标全部设置为一个值
Vector2.set(0.4,0.4);
});
});
原来几何体平面默认是两个三角形构成,把细分数设置为4,三角形数量变为16个。
// 矩形平面 设置细分数4,4
var geometry = new THREE.PlaneGeometry(204, 102, 4, 4);
...
/**
* 局部三角面显示完整纹理贴图
*/
var t0 = new THREE.Vector2(0, 1); //图片左下角
var t1 = new THREE.Vector2(0, 0); //图片右下角
var t2 = new THREE.Vector2(1, 0); //图片右上角
var t3 = new THREE.Vector2(1, 1); //图片左上角
var uv1 = [t0, t1, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
var uv2 = [t1, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
// 设置第五、第六个三角形面对应的纹理坐标
geometry.faceVertexUvs[0][4] = uv1
geometry.faceVertexUvs[0][5] = uv2
Geometry
自定义顶点UV坐标
一般Threejs的球体、圆柱等几何体创建的时候,都会通过特定算法自动生成几何体的UV坐标。
下面代码通过几何体Geometry自定义了一个由两个三角形组成的矩形几何体,并且通过几何体的.faceVertexUvs[0]
属性设置了每个顶点对应的第一组UV坐标。
var geometry = new THREE.Geometry(); //创建一个空几何体对象
/**顶点坐标(纹理映射位置)*/
var p1 = new THREE.Vector3(0,0,0); //顶点1坐标
var p2 = new THREE.Vector3(160,0,0); //顶点2坐标
var p3 = new THREE.Vector3(160,80,0); //顶点3坐标
var p4 = new THREE.Vector3(0,80,0); //顶点4坐标
geometry.vertices.push(p1,p2,p3,p4); //顶点坐标添加到geometry对象
/** 三角面1、三角面2*/
var normal = new THREE.Vector3( 0, 0, 1 ); //三角面法向量
var face0 = new THREE.Face3( 0, 1, 2, normal); //三角面1
var face1 = new THREE.Face3( 0, 2, 3, normal); //三角面2
geometry.faces.push( face0,face1 ); //三角面1、2添加到几何体
/**纹理坐标*/
var t0 = new THREE.Vector2(0,0);//图片左下角
var t1 = new THREE.Vector2(1,0);//图片右下角
var t2 = new THREE.Vector2(1,1);//图片右上角
var t3 = new THREE.Vector2(0,1);//图片左上角
uv1 = [t0,t1,t2];//选中图片一个三角区域像素——映射到三角面1
uv2 = [t0,t2,t3];//选中图片一个三角区域像素——映射到三角面2
geometry.faceVertexUvs[0].push(uv1,uv2);//纹理坐标传递给纹理三角面属性
BufferGeometry
自定义顶点UV坐标
下面代码通过几何体BufferGeometry自定义了一个由两个三角形组成的矩形几何体,并且通过几何体的.attributes.uv
属性设置了每个顶点对应的第一组UV坐标。
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue
var 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类型数组创建顶点索引数据
var indexes = new Uint16Array([
0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
/**纹理坐标*/
var uvs = new Float32Array([
0,0, //图片左下角
1,0, //图片右下角
1,1, //图片右上角
0,1, //图片左上角
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2); //2个为一组,表示一个顶点的纹理坐标
加载一个包含UV坐标的模型文件
下面案例代码是通过Threejs加载一个包含UV坐标的外部三维模型文件,加载成功后,给模型设置一张贴图.
// 创建一个加载threejs格式JSON文件的加载器
var loader = new THREE.ObjectLoader();
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
var 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;
})
})