Three.js是一个3D JavaScript库。
Three.js封装了底层的图形接口,使得程序员能够在无需掌握繁冗的图形学知识的情况下,也能用简单的代码实现三维场景的渲染。
优点:
使用Three.js开发要比WebGL更快更高效。
对于不熟悉图形学知识的程序员而言,使用Three.js能够降低学习成本,提高三维图形程序开发的效率。
一、WebGL
WebGL是基于OpenGL ES 2.0 的Web标准,可以通过 HTML5 Canvas元素作为 DOM接口访问。
WebGL可以看做是将 OpenGL ES(OpenGL for Embedded Systems,OpenGL嵌入式版本,针对手机、游戏机等设备相对较轻量级的版本)移植到了网页平台,像Chrome、Firefox 这些现代浏览器都实现了WebGL标准,使用JavaScript就可以用你熟悉的、类似OpenGL的代码编写了。你可以把 WebGL简单地认为是一种网络标准,定义了一些较底层的图形接口,至于究竟多底层,稍后我们和Three.js代码对比来看。
现在,我们知道了WebGL是一个底层的标准,在这些标准被定义之后,Chrome、Firefox之类的浏览器实现了这些标准。然后,程序员就能通过JavaScript代码,在网页上实现三维图形的渲染了。
二、ThreeJS程序
一个典型的Three.js程序至少要包括:
渲染器(Renderer)、场景(Scene)、照相机(Camera),以及你在场景中创建的物体。
渲染器(Render)
WebGL的渲染是需要 HTML5 Canvas元素 的,可以手动在HTML的
部分中定义 Canvas元素,或者用Three.js生成。手动在 HTML中定义:
<body onload="init()">
<canvas id="mainCanvas" width="400px" height="300px" ></canvas>
</body>
用Three.js生成 Canvas元素:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(400, 300);
document.getElementsByTagName('body')[0].appendChild(renderer.domElement);
上面代码的第二行表示设置 Canvas的宽 400 像素,高 300 像素。第三行将渲染器对应的Canvas元素添加到
中。我们可以使用下面的代码将背景色(用于清除画面的颜色)设置为黑色:
renderer.setClearColor(0x000000);
场景(Scene)
在Three.js中添加的物体都是添加到场景中的,因此它相当于一个大容器。一般说,场景
来没有很复杂的操作,在程序最开始的时候进行实例化,然后将物体添加到场景中即可。
var scene = new THREE.Scene();
照相机(Camera)
在介绍照相机设置前,我们先来简单了解下坐标系。WebGL和 Three.js使用的坐标系是右手坐标系。
这里,我们定义了一直透视投影的照相机,具体原理将在下一章中展开。
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
camera.position.set(0, 0, 5);
scene.add(camera);
值得注意的是,照相机也需要被添加到场景中。
我们使用Three.js创建的场景是三维的,而通常情况下显示屏是二维的,那么三维的场景如何显示到二维的显示屏上呢?
照相机就是这样一个抽象,它定义了三维空间到二维屏幕的投影方式,用“照相机”这样一个类比,可以使我们直观地理解这一投影方式。
针对投影方式的不同,照相机又分为正交投影照相机与透视投影照相机。
一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例;而对于其他大多数应用,通常使用透视投影,因为这更接近人眼的观察效果。当然,照相机的选择并没有对错之分,你可以更具应用的特性,选择一个效果更佳的照相机。
1、正交投影照相机(Orthographic Camera)
设置起来较为直观,它的构造函数是:
THREE.OrthographicCamera(left, right, top, bottom, near, far)
这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,这两个面围成一个长方体,我们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才可能显示在屏幕上,而视景体外的物体会在显示之前被裁减掉。
设置照相机:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);
在原点处创建一个边长为1的正方体,为了和透视效果做对比,这里我们使用wireframe而不是实心的材质,以便看到正方体后方的边:
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true
})
);
scene.add(cube);
现在,如果我们将照相机向右移动 1 个单位:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(1, 0, 5);
得到的效果是物体看上去向左移动了 。。。
换个角度看世界
到现在为止,我们使用照相机都是沿z轴负方向观察的,因此看到的都是一个正方形。现在,我们想尝试一下仰望这个正方体。我们已经学会设置照相机的位置,不妨将其设置在(4, -3, 5)处:
camera.position.set(4, -3, 5);
但是现在照相机沿z轴负方向观察的,因此观察不到正方体,只看到一片黑。我们可以通过 lookAt 函数指定它看着原点方向:
camera.lookAt(new THREE.Vector3(0, 0, 0));
这样我们就能过仰望正方体啦。
2、透视投影照相机(Perspective Camera)
构造函数是:
THREE.PerspectiveCamera(fov, aspect, near, far)
fov 是视景体竖直方向上的张角(是角度制而非弧度制)
aspect 等于 width / height,是照相机水平方向和竖直方向长度的比值,通常设为Canvas的横纵比例。
near 和 far 分别是照相机到视景体最近、最远的距离,均为正值,且 far 应大于near。
设置透视投影照相机,这里 Canvas长 400px,宽 300px,所以 aspect设为 400 / 300:
var camera = new THREE.PerspectiveCamera(45, 400 / 300, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);
和例2.3.1一样,设置一个在原点处的边长为 1的正方体:
// a cube in the scene
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true
})
);
scene.add(cube);
长方体
我们要创建一个x、y、z方向长度分别为 1、2、 3 的长方体,并将其设置为红色。
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3),
new THREE.MeshBasicMaterial({
color: 0xff0000
})
);
scene.add(cube);
立方体(CubeGeometry)
虽然这一形状的名字叫立方体(CubeGeometry),但它其实是长方体,也就是长宽高可以设置为不同的值。其构造函数是:
THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
这里,width 是x方向上的长度; height 是 y方向上的长度; depth 是z方向上的长度;后三个参数分别是在三个方向上的分段数,如 widthSegments 为 3 的话,代表 x方向上水平分为三份。一般情况下不需要分段的话,可以不设置后三个参数,后三个参数的缺省值为 1。其他几何形状中的分段也是类似的,下面不做说明。
长宽高
创建立方体直观简单,如:
new THREE.CubeGeometry(1, 2, 3);
可以创建一个x方向长度为 1,y方向长度为 2,z方向长度为 3 的立方体。
物体的默认位置是原点,对于立方体而言,是其几何中心在原点的位置。
分段
而在设置了分段
new THREE.CubeGeometry(1, 2, 3, 2, 2, 3)
注意这个分段是对六个面进行分段,而不是对立方体的体素分段,因此在立方体的中间是不分段的,只有六个侧面被分段。
平面
这里的平面(PlaneGeometry)其实是一个长方形,而不是数学意义上无限大小的平面。其构造函数为:
THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
其中,width 是x方向上的长度; height 是 y方向上的长度;后两个参数同样表示分段。
new THREE.PlaneGeometry(2, 4);
创建的平面在x轴和y轴所在平面内
球体
球体(SphereGeometry)的构造函数是:
THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, the taStart, thetaLength)
其中,radius 是半径; segmentsWidth 表示经度上的切片数; segmentsHeight 表示纬度上的切片数;phiStart 表示经度开始的弧度;phiLength 表示经度跨过的弧度;
thetaStart 表示纬度开始的弧度; thetaLength 表示纬度跨过的弧度。
圆形
圆形(CircleGeometry)可以创建圆形或者扇形,其构造函数是:
THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)
这四个参数都是球体中介绍过的,这里不再赘述,直接来看个例子。
new THREE.CircleGeometry(3, 18, Math.PI / 3, Math.PI / 3 * 4)
可以创建一个在x轴和y轴所在平面的三分之二圆的扇形
文字形状
文字形状(TextGeometry)可以用来创建三维的文字形状。
略……
实例剖析
实例1:
预览图:
代码分析:
在页面中对应设置id为mainCanvas的canvas标签,设置宽高:width="400px" height="300px"
在页面加载完成后调用: <body onload="init()">
引入three.js文件
在script标签中,定义init()函数:
//渲染器WebGLRenderer
var renderer= new THREE.WebGLRenderer({
//创建场景
var scene= new THREE.Scene();
//创建照相机,并添加到场景中
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
//创建长方体,设置为红色,并添加到场景中
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3),
//渲染
renderer.render(scene, camera);
完整代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="three.js"></script>
<script>
function init(){
//渲染器WebGLRenderer
var renderer= new THREE.WebGLRenderer({
canvas: document.getElementById('mainCanvas')
//指定id的canvas标签
})
renderer.setClearColor(0x000000);
//创建场景
var scene= new THREE.Scene();
//创建照相机,并添加到场景中
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
camera.position.set(0, 0, 5);
scene.add(camera);
//创建长方体,设置为红色
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3),
new THREE.MeshBasicMaterial({
color: 0xff0000
})
);
scene.add(cube);
//渲染
renderer.render(scene, camera);
}
</script>
</head>
<body onload="init()">
<!--页面加载后执行init函数-->
<canvas id="mainCanvas" width="400px" height="300px"></canvas>
</body>
</html>
实例2:
预览图:
设置照相机的位置:
camera.position.set(4, 3, 5); //设置照相机的位置
camera.lookAt(new THREE.Vector3(0, 0, 0));
示意图:
完整代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="three.js"></script>
<script>
//正交投影照相机(Orthographic Camera)
//
function init(){
//渲染器WebGLRenderer
var renderer= new THREE.WebGLRenderer({
canvas: document.getElementById('mainCanvas')
//指定id的canvas标签
})
renderer.setClearColor(0x000000);
//创建场景
var scene= new THREE.Scene();
//创建照相机,并添加到场景中
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(4, 3, 5); //设置照相机的位置,在此位置上有新视角!
camera.lookAt(new THREE.Vector3(0, 0, 0)); //设置照相机向着原点而非z轴负方向。
scene.add(camera);
//创建长方体,设置为红色
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 3),
new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe:true
})
);
scene.add(cube);
//渲染
renderer.render(scene, camera);
}
</script>
</head>
<body onload="init()">
<!--页面加载后执行init函数-->
<canvas id="mainCanvas" width="400px" height="300px"></canvas>
<!--WebGL No.1 - Three.js 入门-->
</body>
</html>
1