什么是three.js
想要了解 three.js,我们先了解一下 WebGL 是什么。WebGL 是一个只能画点、线和三角形的非常底层的系统。简单来说就是使用 WebGL 提供的api可以在画布的三维坐标中,绘制点、线、三角形。我们所看见的立体图形都是通过三角形组合而来的。
想要用WebGL来做一些实用的东西通常需要大量的代码,这就出现了对 WebGL Api 进行封装后的库 three.js。它封装了诸如场景、灯光、阴影、材质、贴图、空间运算等一系列功能,让我们不需要再去关心WebGL的复杂原理。
整个程序的结构
场景(Scene)
它就相当于一个大容器,我们需要展示的所有物体都要放入场景。如上图所示当把其对象放入场景后形成树状结构,就组合成场景图。在场景图中子对象的位置和方向总是相对于父对象而言的,比如我移动了父对象的位置,子对象也会一起移动。
摄像机(Camera)
它与其他对象不同的是,它不一定要在场景图中才能起作用,它可以和场景同级。相同的是,摄像机(Camera)作为其他对象的子对象,同样会继承它父对象的位置和朝向。three.js 内置两种摄像机:
- 正交相机(OrthographicCamera):
在这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变。正交投影相机的视景体是一个长方体,OrthographicCamera 的构造函数是这样的:OrthographicCamera( left, right, top, bottom, near, far )。Camera本身可以看作是一个点,left 则表示左平面在左右方向上与 Camera 的距离。另外几个参数同理。于是六个参数分别定义了视景体六个面的位置。可以近似地认为,视景体里的物体平行投影到近平面上,然后近平面上的图像被渲染到屏幕上。
- 透视相机(PerspectiveCamera):
这一投影模式被用来模拟人眼所看到的景象,它是3D场景的渲染中使用得最普遍的投影模式。透视投影相机的视景体是个四棱台,它的构造函数是这样的:PerspectiveCamera( fov, aspect, near, far )。fov 对应着图中的视角,是上下两面的夹角。aspect 是近平面的宽高比。再加上近平面距离 near,远平面距离 far,就可以唯一确定这个视景体了。透视投影相机很符合我们通常的看东西的感觉,因此大多数情况下我们都是用透视投影相机展示3D效果。
渲染器(Renderer)
它是 three.js 的主要对象,场景(Scene)和摄像机(Camera)都需要传入渲染器(Renderer)中,通过它将摄像机视椎体中的三维场景渲染成一个二维图片显示在画布上。
网格(Mesh)
在 three.js 中,Mesh 的构造函数是这样的:Mesh( geometry, material )。geometry 是它的形状,material 是它的材质。不止是 Mesh,创建很多物体都要用到这两个属性。下面我们来看看这两个重要的属性。
几何体(Geometry)
就是球体、立方体、平面、狗、猫、人、树、建筑等物体的顶点信息。three.js 内置了许多基本几何体:
1. CubeGeometry 立方体
2. PlaneGeometry 平面
3. SphereGeometry 球体
4. CylinderGeometry 圆柱体
5. TorusGeometry 圆环面
6. TubeGeometry 管道缓冲几何体
对于比较复杂的形状,我们还可以通过外部的模型文件导入。
材质(Material)
和几何体同时使用,表示几何体不同面的颜色,和光亮程度。three.js 内置了许多材质:
1. MeshBasicMaterial 基础网格材质,不受光照的影响
2. MeshDistanceMaterial 通过点光源实现阴影的材质
3. MeshNormalMaterial 一种把法向量映射到RGB颜色的材质
纹理(Texture)
创建一个纹理贴图,将其应用到一个表面,或者作为反射/折射贴图。可以多个纹理同时在一个材质上使用。
光源(Light)
和材质配合使用,通过不同的光源来修改颜色,添加阴影等。
- AmbientLight 环境光,会均匀的照亮场景中的所有物体。
- DirectionalLight 平行光,是沿着特定方向发射的光。
- HemisphereLight 半球光,光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。不可以投射阴影。
- PointLight 点光源,从一个点向各个方向发射的光源。可以投射阴影。
开始使用
首先,我们需要在 Github 下载 three.js 的代码,在使用 three.js 之前,我们需要在 HTML 文件中引用该文件,然后就能通过全局变量THREE访问到所有属性和方法了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./three.js"></script>
<style>
body {
/* 边距设置为0,设置溢出隐藏,完整的使用整个页面 */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="webgl-output"></div>
</body>
在JavaScript代码中定义一个init函数,在HTML加载完后执行。
function init() {
// ...
}
window.onload = init;
// 创建场景
var scene = new THREE.Scene();
// 设置摄像机
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000)
// 定位相机,并指向场景中心
camera.position.x = 30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
// 创建渲染器
var renderer = new THREE.WebGLRenderer();
// 设置渲染器的初始颜色
renderer.setClearColor(new THREE.Color(0xeeeeee));
// 设置输出canvas画面的大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 显示三维坐标系
// 里面的20是显示坐标轴的长度,红色代表x轴,绿色代表y轴,蓝色代表z轴
var axes = new THREE.AxisHelper(20);
// 添加坐标系到场景中
scene.add(axes);
// 创建地面的几何体,长60,宽20
var planeGeometry = new THREE.PlaneGeometry(60, 20);
// 给地面物体上色
var planeMaterial = new THREE.MeshBasicMaterial({color: 0xcccccc});
// 创建地面
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
// 物体移动位置
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
// 将地面添加到场景中
scene.add(plane);
// 将渲染器输出添加html元素中
document.getElementById('webgl-output').appendChild(renderer.domElement);
renderer.render(scene, camera);
运行
最最最简单的,没有添加光源,不能动实现动画效果的页面出来啦~