一、WebGL 与 three.js
WebGL(Web Graphics Library)是一种3D绘图协议,它允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型。
但使用WebGL原生的API来写3D程序非常复杂,需要相对较多的数学知识,对于前端开发者来说学习成本较高。而Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本,成为前端开发者完成3D绘图的得力工具,目前在github上star数量已经达到了将近4万。
二、three.js
首先来看一个例子,该例子绘制了一个立方体,并让它不断旋转,通过这个例子来初步了解three.js的基本使用及主要API。
var scene = new THREE.Scene(); // 创建场景
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); // 创建透视相机
var renderer = new THREE.WebGLRenderer(); // 创建一个 WebGL 渲染器
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器为全屏
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1,1,1); // 创建一个长宽高都为1个单位的立方体
var material = new THREE.MeshBasicMaterial({color: 0x00ff00}); // 创建材质,对光照无感
var cube = new THREE.Mesh(geometry, material); // 创建一个立方体网格(mesh),将材质包裹在立方体上
scene.add(cube); // 将立方体网格添加到场景中
camera.position.z = 5; // 指定相机位置
function render() {
requestAnimationFrame(render); // 让浏览器执行参数中的函数,不断循环
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera); // 结合场景和相机进行渲染,即用摄像机拍下此刻的场景
}
render();
three.js中的三大要素:场景(scene)、相机(camera)、渲染器(renderer),有了这三样东西,我们才能够使用相机将场景渲染到网页上去。
- 场景
场景是所有物体的容器,场景只有一种。
创建场景:要构件一个场景很简单,只需要new一个场景对象出来即可:var scene = new THREE.Scene()
-
相机
相机是成像的工具,相机有很多种类,不同种类的相机即使从一个角度拍摄,所成像出来的结果也不相同。相机决定了场景中哪个角度的景色会显示出来。
说到相机,就涉及到坐标系的概念。webGL和three.js使用的是右手坐标系,如下图所示:在Three.js中有两种常用的相机:透视相机(perspectiveCamera)和正交投影相机(OrthographicCamera )
正交投影相机:
参数 介绍 fov 表示视场,即摄像机能看到的视野。推荐默认值50 aspect 指定渲染结果横向尺寸和纵向尺寸的比值,推荐默认值为窗口的长宽比,即window.innerWidth/window.innerHeight near 指定从距离摄像机多近的位置开始渲染,推荐默认值0.1 far 指定摄像机从它所在的位置最远能看到多远,太小场景中的远处不会被渲染,太大会浪费资源影响性能,推荐默认值1000 - 渲染器
渲染器的作用就是将相机拍摄出的画面在浏览器中呈现出来。渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。three.js中有很多种类的渲染器,例如webGLRenderer、canvasRenderer、SVGRenderer,通常使用的是webGL渲染器。
创建webGL渲染器:
var renderer = new THERR.WebGLRenderer();
创建完渲染器后,需要调用render方法将之前创建好的场景和相机相结合从而渲染出来,即调用渲染器的render方法:
renderer.render(scene,camera)
以上就是three.js中完成3D绘图的三大要素,利用这三大要素,我们就可以绘制出想要的3D图像了。
绘制的前期准备工作已经做完,接下来要做的就是把想要绘制的物体添加到场景中了。在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角面片,无数个三角面片就能够组成各种各样形状的物体,通常把这种网格模型叫做Mesh模型。Mesh模型是三维开发中使用的最为广泛的模型。
创建Mesh模型的物体:var object = new THREE.Mesh(Geometry, Material)
,第一个参数代表物体的形状,第二个参数代表物体的材质。
Geometry
three.js 给出了很多方法去生成固定的网格形状,比如长方体(BoxGeometry)、球体(SphereGeometry)、圆形(CircleGeometry)等等。还有根据坐标去生成具体形状的方法,可以借助第三方建模软件建模之后导入,目前支持的模型格式有.obj(最常用),.mtl,.dae,.ctm,.ply,.stl,.wrl,.vtk等。Three.js有一系列支持外部导入文件的辅助函数,是在three.js库之外的,使用前需要额外下载。
Material
hree.js给出了很多种直接生成材质的方法,其中比较常用的有MeshBasicMaterial(对光照无感,给几何体一种简单的颜色或显示线框)、MeshLambertMaterial(对光照有反应,无光源则不会显示,用于创建暗淡的不发光的物体)、MeshPhongMaterial(对光照有反应,无光源则不会显示,用于创建金属类明亮的物体)等等。
物体之所以能被人眼看见,一种是它自身的材料就能发光,不需要借助外界光源;另一种是自身材料不发光,需要反射环境中的光。对于自身不能发光的物体,需要给场景添加光源从而达到可视的效果。
Light
three.js中可以创建出很多不同类型的光源,比如环境光(AmbientLight,它的颜色会添加到整个场景和所有对象的当前颜色上),点光源(PointLight,这种光源放出的光线来自同一点,且方向辐射自四面八方,例如蜡烛发出的关),方向光(THREE.DirectionalLight,也称无限光,从这种光源发出的光线可以看作是平行的,例如太阳光),聚光灯(THREE.SpotLight ,这种光源的光线从一个锥体中射出,在被照射的物体上产生聚光的效果,例如手电筒发出的光等)
有光源就缺少不了阴影,在Three.js中,能形成阴影的光源只有THREE.DirectionalLight与THREE.SpotLight;而相对地,能表现阴影效果的材质只有THREE.LambertMaterial与THREE.PhongMaterial。three.js中渲染阴影的开销比较大,所以默认物体是没有阴影的,需要单独开启。开启阴影方法:
- 将渲染器的shadowMapEnabled属性设置为true(告诉渲染器可以渲染隐形)
- 将物体及光源的castShadow属性设置为true(告诉物体及光源可以透射阴影)
- 将接收该阴影的物体的receiveShadow属性设置为true(告诉物体可以接收其他物体的阴影)
三、实用的小插件
- data.GUI
data.GUI 是一个轻量级的图形用户界面库(GUI 组件),使用这个库可以很容易地创建出能够改变代码变量的界面组件,从而实现一些实时交互效果。 - stats.js
stats.js 主要用于检测动画运行时的帧数,可以显示fps(表示每秒多少帧)和 ms(每帧多少毫秒),fps越大越好,但太大会影响性能,一般为60左右。
四、参考文档
- https://threejs.org/ three.js官方网站
- http://www.hewebgl.com/ WebGL中文网
- http://techbrood.com/threejs/... three.js 中文文档