2.5 自定义几何体与UV坐标

2.5.1 自定义几何体

Three.js封装了很多几何体,其中最常用的有球体(SphereGeometry)、立方体(CubeGeometry)、圆柱体(CylinderGeometry)、平面(PlaneGeometry)、3D文本(TextGeometry)等,在网站http://222.30.167.210/WebGL-docs/docs/index.html中有这些API的详细使用说明。

实践中,它们往往是不够用的,总会遇到一些不规则的几何体,土星环就是一个例子。如图2-9所示,土星环是一个具有内外环半径的圆盘,在Three.js中并没有提供这个几何体,需要我们自定义。

图2-9 土星环

几何体(Geometry)的两个最基本的参数是点和面,Three.js它们封装到了两个数组中,分别是vertices[]和faces[];另外,WebGL是以三角形为基础构建平面的,vertices数组中的顶点要以合理的方式进行3个一组的划分,以构成几何体的所有平面。

2.5.2 UV坐标

当给自定义几何体的表面提供图片纹理时,需要定义平面的UV坐标,它指明纹理图片的每个像素如何映射到网格表面。U代表水平方向,向右递增;V代表垂直方向,向上递增,取值范围是从0到1,以纹理图片的左下角为原点(0,0),右上角为终点(1,1)。

比如,矩形可以根据某条对角线将其分割成两个三角形。如图2-10(b)所示,先取①③②顶点构建一个平面,它将引用图2-10(c)所示纹理图,其UV坐标为[(0,0),(0.5,0),(0,0.5)];再取②③④顶点构建一个平面,它将引用图2-10(d)所示纹理图,其UV坐标为[(0,0.5),(0.5,0),(0.5,0.5)],所有这些平面的组合即构成我们自定义的几何体,依照这个原理,可以将一副平面图片合理地贴到一个曲面上去。

图2-10 引用纹理图片

在复杂的三维模型中,还可以将多幅平面图片合成到一个图片文件中去,并分区引用,如图2-11所示,这是在纹理贴图中常用的一个技巧。

图2-11 复杂模型的UV贴图

在定义UV贴图时,需要注意平面的法向量问题,直观来讲,就是UV图片应该贴至平面的哪个面,默认情况下,Three.js会贴到法向量面上。

法向量实质为两向量外积,与组成平面的三个顶点的出现顺序有关,其方向遵循右手原则。以1、3、2三点组成的面为例,将右手手腕置于3点,四指指向2点,沿手心方向向1点转动,大拇指所致方向即为外积方向,也就是该平面的法向量方向。

大多数情况下,我们只渲染三角形的某一个面,这样,当我们从背面查看目标时,屏幕上将不会渲染出任何物体,为避免这个问题,可以在材质中指定要进行双面渲染,比如:

2.5.3 创建土星环

创建土星环(见图2-12)的主要代码如下:

图2-12 土星环实例效果

2.5.4 合并几何体

并非所有的不规则几何体都完全需要依靠写代码来实现,有些模型可以通过各种现有的几何体搭建而成,比如桌子可以由5个长方体(1个桌面和4条桌腿)来组成,将它们合并即可完成桌子的建模。

Three.js提供了GeometryUtils.merge方法来合并两个几何体,基本使用方法是:THREE.GeometryUtils.merge(g1,g2),这条语句的意思是将几何体g2合并至几何体g1中去。

需要注意的是,Three.js总是以(0,0,0)为中心(锚点)来构建几何体的,比如一个边长为1的几何体,其正右上方的顶点坐标是(0.5,0.5,0.5)。在合并几何体之前,一般需要修改这些顶点的坐标。平移可以使用THREE.Matrix4().makeTranslation方法,旋转可以使用makeRotation方法,缩放可以使用makeScale方法。

下面的代码合并了两个球体:

最后请注意applyMatrix方法实际上是修改了几何体的每个顶点的物理坐标,这与3D对象的position属性有本质区别。大多数情况下,我们通过修改一个3D对象的position属性来改变其位置,其实这是修改了这个3D对象的本地矩阵,该几何体各顶点的物理坐标并不发生变化,最终的顶点位置是由“物理坐标×本地矩阵×世界矩阵”计算出来的。