点、线、面
学习几何体对象、材质对象构造函数之前可以不去了解WebGL或three.js中的点、线、面相关概念,不过学习点线面的相关概念后, 你可以更好的理解three.js多层封装WebGL后提供的用于创建几何对象、材质对象、粒子对象、网格模型等对象的构造函数,three.js在封装WebGL的时候, 采用逐层抽象的方式封装,比如一个三维场景可以拆分为网格模型和灯光,网格模型可以拆分为几何对象和材质对象, 几何对象可以拆分为顶点位置数据、顶点索引数据、顶点颜色数据、顶点法向量数据。
直线模型对象
两个顶点确定一条直线,构造函数THREE.Vector3()可以用来创建一个顶点位置,下面代码中Vector3(10,0,0)表示三维笛卡尔坐标系中顶点坐标(10,0,0), vertices是几何体对象的顶点坐标属性,从Javascript语言的角度看vertices是数组对象,push()是Javascript语言支持的方法, 用于给数组增加元素。
/** * 创建线条对象 */ var geometry = new THREE.Geometry();//声明一个空几何体对象 var p1 = new THREE.Vector3(10,0,0);//顶点1坐标 var p2 = new THREE.Vector3(0,20,0);//顶点2坐标 geometry.vertices.push(p1,p2); //顶点坐标添加到geometry对象 var material=new THREE.LineBasicMaterial({ color:0x0000ff //线条颜色 });//材质对象 var line=new THREE.Line(geometry,material);//线条模型对象 scene.add(line);//线条对象添加到场景中
创建点模型对象
一个顶点生成一个片元区域像素,材质模型参数的属性size表示顶点生成的矩形区域的宽高尺寸,单位是像素。
/** * 创建点对象 */ var geometry = new THREE.Geometry();//声明一个空几何体对象 var p1 = new THREE.Vector3(10,0,0);//顶点1坐标 var p2 = new THREE.Vector3(0,20,0);//顶点2坐标 var p3 = new THREE.Vector3(15,15,0);//顶点3坐标 geometry.vertices.push(p1,p2,p3); //顶点坐标添加到geometry对象 var material=new THREE.PointsMaterial({ color:0x0000ff, size:10.0//点对象像素尺寸 });//材质对象 var points=new THREE.Points(geometry,material);//点模型对象 scene.add(points);//点对象添加到场景中
三角面网格模型对象
/** * 创建网格模型 */ var geometry = new THREE.Geometry(); //声明一个空几何体对象 var p1 = new THREE.Vector3(0,0,0); //顶点1坐标 var p2 = new THREE.Vector3(80,0,0); //顶点2坐标 var p3 = new THREE.Vector3(0,80,0); //顶点3坐标 geometry.vertices.push(p1,p2,p3); //顶点坐标添加到geometry对象 var normal = new THREE.Vector3( 0, 0, 1 ); //三角面法向量 var face = new THREE.Face3( 0, 1, 2, normal); //创建三角面 geometry.faces.push( face ); //三角面添加到几何体 var material=new THREE.MeshLambertMaterial({ color:0x0000ff,//三角面颜色 side:THREE.DoubleSide//两面可见 });//材质对象 var mesh=new THREE.Mesh(geometry,material);//网格模型对象 scene.add(mesh);//网格模型添加到场景中
三个顶点确定一个三角面,三角面的创建一般会考虑光照问题,有兴趣可以学习《WebGL光照渲染立方体》, 如果没有WebGL基础可以简单了解光学模型,THREE.Vector3( 0, 0, 1 )创建了一个顶点法向量,沿着Z轴方向,顶点p1、p2、p3组成的平面位于XOY平面上,说明法向量的方向是对的,平面的法向量垂直于平面本身。 如果实际开发的过程中,设置每一个顶点或者说顶点构成的三角面的法向量,手动设置是非常麻烦的,一般会借助其它的可视化三维软件,或者three.js已经封装了顶点法向量的几何体对象, 比如使用构造函数BoxGeometry、SphereGeometry创建立方体和球体几何体对象,这些几何体除了顶点法位置数据,还包含顶点的法向量数据,不需要手动设置。
下面的程序创建的是一个三角面网格模型,三角面可以理解为网格模型的构成元素,比如使用构造函数BoxGeometry和Mesh创建一个立方体网格模型,实际上它是由至少12个三角面组成,立方体6个面,每个面是2个三角面。
下面的程序创建的是一个三角面网格模型,三角面可以理解为网格模型的构成元素,比如使用构造函数BoxGeometry和Mesh创建一个立方体网格模型,实际上它是由至少12个三角面组成,立方体6个面,每个面是2个三角面。使用构造函数THREE.Face3()把任意三个顶点的索引、三个顶点的共用法向量作为参数可以创建一个三角面单元,作为几何体对象属性faces的元素, faces和vertices一样都是一个数组对象。对于立方体而言要创建12个三角面Face3对象,执行语句geometry.faces.push(face)把三角面添加到立方体对应的几何体对象。 构造函数BoxGeometry已经封装12个三角面创建的细节,直接创建几何体对象,无需手动设置三角面的参数。
side是网格材质对象参数的属性,值THREE.DoubleSide表示两面可见,从光照模型的角度看,当三角面法向量与光线方向的夹角大于90度的时候, 顶点法向量的方向只有一个,背光面不会显示,没有任何颜色值,具体细节可以查看学习WebGL教程。
索引 | 顶点 |
0 | p1 |
1 | p2 |
2 | p3 |
... | ... |
绘制矩形平面(两个三角面)
下面的程序首先利用构造函数THREE.Vector3()创建了四个顶点,添加到顶点数组对象vertices中,四个顶点p1、p2、p3、p4会按照push的顺序自动排序,分别标记为0、1、2、3。 顶点0、1、2创建一个三角面,顶点0、2、3创建一个顶点,这里可以看出顶点0,、2共用,不需要创建6个顶点坐标来生成2个三角面。
/** * 创建矩形平面网格模型 */ var geometry = new THREE.Geometry(); //声明一个空几何体对象 var p1 = new THREE.Vector3(0,0,0); //顶点1坐标 var p2 = new THREE.Vector3(80,0,0); //顶点2坐标 var p3 = new THREE.Vector3(80,80,0); //顶点3坐标 var p4 = new THREE.Vector3(0,80,0); //顶点4坐标 geometry.vertices.push(p1,p2,p3,p4); //顶点坐标添加到geometry对象 var normal = new THREE.Vector3( 0, 0, 1 ); //三角面法向量 var face0 = new THREE.Face3( 0, 1, 2, normal); //创建三角面0 var face1 = new THREE.Face3( 0, 2, 3, normal); //创建三角面1 geometry.faces.push( face0,face1 ); //三角面添加到几何体 var material=new THREE.MeshLambertMaterial({ color:0x0000ff,//三角面颜色 side:THREE.DoubleSide//两面可见 });//材质对象 var mesh=new THREE.Mesh(geometry,material);//网格模型对象 scene.add(mesh);//网格模型添加到场景中
比较点线面
整体来看创建点、线、面模型对象,程序的结构是一样的,首先要创建几何体对象和材质对象,然后把两个对象作为Points、Line或Mesh的参数, 创建一个点、线或面模型对象,整体上是神似的,具体的细节上会有不同,顶点数据都是使用构造函数Vector3创建是相同的,材质对象和模型对象的构造函数不同, Mesh开头的构造函数用来创建网格模型对象及其材质,Line开头的构造函数用来创建线条模型对象及其材质,point开头的构造函数用来创建顶点材质和模型对象。 点、线的创建不考虑光照影响,网格模型的创建要考虑光照计算,需要给顶点添加法向量数据,实际的开发中往往都是创建网格模型来模拟自然界的实物,点、线往往用于特殊用途,比如借助点实现粒子系统,借助线条实现计算机模仿素描。
颜色插值
相关WebGL教程《varying变量和颜色插值》,在顶点位置数据、顶点法向量数据的基础上在引入顶点颜色数据,三维模型的颜色可以通过材质构造函数颜色属性定义,也可以通过顶点颜色数据定义。
彩色线条
/** * 创建线条对象 */ var geometry = new THREE.Geometry();//声明一个空几何体对象 var p1 = new THREE.Vector3(50,0,0);//顶点1坐标 var p2 = new THREE.Vector3(0,70,0);//顶点2坐标 geometry.vertices.push(p1,p2); //顶点坐标添加到geometry对象 var color1 = new THREE.Color(0xFF0000);//顶点1颜色——红色 var color2 = new THREE.Color(0x0000FF);//顶点3颜色——蓝色 geometry.colors.push(color1, color2);//顶点颜色传入几何体对象 var material=new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors,//以顶点颜色为准 });//材质对象 var line=new THREE.Line(geometry,material);//线条模型对象 scene.add(line);//线条对象添加到场景中
彩色三角形
/** * 创建网格模型 */ var geometry = new THREE.Geometry(); //声明一个空几何体对象 var p1 = new THREE.Vector3(0,0,0); //顶点1坐标 var p2 = new THREE.Vector3(80,0,0); //顶点2坐标 var p3 = new THREE.Vector3(0,80,0); //顶点3坐标 geometry.vertices.push(p1,p2,p3); //顶点坐标添加到geometry对象 var face = new THREE.Face3( 0, 1, 2, normal); //创建三角面 /**顶点颜色**/ var color1 = new THREE.Color(0xFF0000);//顶点1颜色——红色 var color2 = new THREE.Color(0x00FF00);//顶点2颜色——绿色 var color3 = new THREE.Color(0x0000FF);//顶点3颜色——蓝色 var normal = new THREE.Vector3( 0, 0, 1 ); //三角面法向量 face.vertexColors.push(color1, color2,color3);//定义三角面三个顶点的颜色 geometry.faces.push( face ); //三角面添加到几何体 var material=new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors,//以顶点颜色为准 side:THREE.DoubleSide//两面可见 });//材质对象 var mesh=new THREE.Mesh(geometry,material);//网格模型对象 scene.add(mesh);//网格模型添加到场景中
THREE.Color()
顶点位置数据、法向量数据通过构造函数THREE.Vector3创建,顶点颜色数据通过构造函数THREE.Color()创建,对于创建线条直接把颜色数据插入到colors数组,colors和vertices一样都是几何体的属性,数据类型也一样都是数组对象。对于创建三角面的时候,一般通过三角面对象把顶点颜色数据传递给几何体对象,具体代码参照上面“彩色三角形”代码,vertexColors是三角面的属性,数据类型是数组,用法和colors一样,最终的功能也是一样的。
vertexColors: THREE.VertexColors
材质对象参数的属性vertexColors用来设置,哪一种颜色数据起作用,vertexColors的默认值是THREE.NoColors,表示三维模型的颜色取决材质对象参数的颜色属性color的值,属性vertexColors的值设置为THREE.VertexColors, 三维模型的颜色取决顶点颜色插值后计算出来的结果,如果不定义vertexColors的属性值为THREE.VertexColors,顶点颜色数据不会起作用。
几何体三种渲染方式
构造函数BoxGeometry创建的立方体几何对象,本质上就是顶点的相关数据,使用Point构造函数渲染出点的效果,使用Line()构造函数渲染出线条效果,使用Mesh()构造函数渲染出网格模型效果。 当然对于点线面三种不同的渲染效果注意要使用各自特定的材质构造函数创建材质对象。
面
/** * 创建网格模型 */ //立方体(长宽高均为100) var box=new THREE.BoxGeometry(100,100,100); var material=new THREE.MeshLambertMaterial({color:0x0000ff});//材质对象 var mesh=new THREE.Mesh(box,material);//网格模型对象 scene.add(mesh);//网格模型添加到场景中
线
THREE.Line、THREE.LineLoop、THREE.LineSegments三个构造函数定义的是描点划线的方式,对应WebGL中的绘制模式mode,初学的时候不用深究,有个影响即可, 对于LineSegments方式而言,两个点确定一条直线,四个点确定2条直线;对于Line方式,四个点可以连续绘制出3条直线;对于LineLoop方式,与line模式基本一样,最后会产生闭合, 四个点可以连续绘制出4条直线。
/** * 创建线模型 */ //立方体(长宽高均为100) var box=new THREE.BoxGeometry(100,100,100); var material=new THREE.LineBasicMaterial({color:0x0000ff});//材质对象 var mesh=new THREE.Line(box,material);//线模型对象(连续绘制) var mesh=new THREE.LineLoop(box,material);//线模型对象(连续闭合绘制) var mesh=new THREE.LineSegments(box,material);//线模型对象(断续绘制) scene.add(mesh);//线模型添加到场景中
点
/** * 创建点模型 */ //立方体(长宽高均为100) var box=new THREE.BoxGeometry(100,100,100); var material=new THREE.PointsMaterial({ color:0x0000ff, size:10 });//材质对象 var mesh=new THREE.Points(box,material);//点模型对象 scene.add(mesh);//点模型添加到场景中
更改构造函数参数,增加立方体的细分度,后三个参数不设置默认都是1
var box=new THREE.BoxGeometry(100,100,100,5,5,5);
通过测试上面的代码除了学习具体的点线面构造函数THREE.Points、THREE.Line、THREE.Mesh,更进一步认识几何体对象的本质, 几何体构造函数立方体BoxGeometry、球体SphereGeometry本质上来看都是顶点的相关数据构成。