0%

three.js 系列一 创建第一个3d场景

如今的浏览器的功能越来越强大,可以直接使用html5标签轻松的添加音频、视频,而且可以在html5画布(canvas)上创建各种交互组件。现在更是支持WebGL。通过 WebGL可以直接使用显卡的计算资源,创建高性能的二维、三维计算图形。可以直接使用JavaScript来直接进行WebGL编程,创建三维场景动画,但是这个过程非常复杂,Three.js库可以简化这个过程。

基本上,Three.js可以在任何流行的浏览器上运行(IE11以上才支持)。

创建html页面框架

这里我使用的angular框架,比较方便一点。直接通过npm安装three.js:

1
npm i three --save

html只是当前的组件的html:

1
2
3
<div id="world">
<canvas id="canvas" #canvas></canvas>
</div>

less:

1
2
3
4
5
6
7
8
9
#world {
width: 100%;
height: 100%;
overflow: hidden;
#canvas {
width: 100%;
height: 100%;
}
}

我们需要让页面占满视口。

js部分

我们需要导入three.js模块,然后通过获得模板引用变量的方法,获得我们需要渲染的元素

1
2
3
4
5
6
7
8
9
// 模块导入three
import * as THREE from 'three';
export class ThreeDimensionalSceneComponent implements OnInit, AfterViewInit {
@ViewChild('canvas')
private canvasRef: ElementRef;
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
}

渲染并展示三维对象

就目前的代码,我们运行起来看的话是一片空白,只看到一个空白的页面。现在我们需要加入三维对象并将它们渲染出来。

我们需要构造一个世界(假装我们的WebGL是一个世界),我们需要场景(scene)、相机(camera)和一个渲染器(renderer)。

  • scene(场景) 场景是一个容器,用来保存并跟踪所有我们想渲染的物体。
  • camare(相机) 相机决定了我们能在场景(scene)里面看到啥,以及从什么角度看。
  • renderer(渲染器) 渲染器负责计算指定相机角度下,场景中的物体是什么的样子。

创建场景、相机、渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
renderer: THREE.WebGLRenderer;
scene: THREE.Scene;
camera: THREE.PerspectiveCamera;
init() {
// 创建场景
this.scene = new THREE.Scene();
// 创建相机
this.camera = new THREE.PerspectiveCamera(45, this.canvas.clientWidth / this.canvas.clientHeight, 0.1, 1000);
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true
});
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.camera.position.set(-50, 40, 30);
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
this.renderer.render(this.scene, this.camera);
}

我们创建了基本场景所需要的东西,视口里面变成了一片漆黑,为了观测方便,我添加了辅助坐标轴。

1
2
3
4
5
6
7
8
9
10
11
12
init() {
//...
this.axes();
this.renderer.render(this.scene, this.camera);
}
/**
* 坐标轴
*/
axes() {
const axes = new THREE.AxesHelper(20);
this.scene.add(axes);
}

需要注意的是,three.js里面的3d世界遵循的是右手坐标轴:
右手坐标轴
即大拇指代表X轴,食指代表Y轴,中指代表Z轴,可以用颜色辅助记忆:RGB,R(red,x轴,红色)、G(green,绿色, Y轴)、B(blue,蓝色,Z轴)。
然后我们可以看到渲染的界面如下所示:
坐标轴

添加简单的三维物体

现在一片漆黑,没有啥东西,我们来添加一个正方体,正方体用到three内置的几何对象:Cube。

添加一个物体,我们需要定义该对象的几何结构、材质(外观),然后通过几何结构和材质结合为一个网格对象,然后添加到场景中,最后渲染场景就可以看到了。

话不多说,看码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
init() {
//...
this.axes();
this.addCube();
this.renderer.render(this.scene, this.camera);
}
/**
* 方体
*/
addCube() {
const cubeGeometry = new THREE.CubeGeometry(4, 4, 4);
const cubeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
});
this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
this.cube.position.set(0, 0, 0);
this.scene.add(this.cube);
}

我们使用THREE.CubeGeometry创建了一个4X4X4的正方体几何形状,然后使用THREE.MeshBasicMaterial创建了基本的材质,并将材质的颜色设置为白色,然后使用几何体和材质组合成为网格对象正方体,然后将正方体放置在坐标轴原点,然后将正方体添加到场景中,最后在init()方法中渲染了场景,这样我们就可以在视口里看到坐标轴原点处出现了个白色的正方体:
正方体
我们可以使用网格对象的几个属性来改变它在场景中的位置以及显示效果,基本属性有:

  • position(位置) 决定对象对其父对象的位置。通常一个对象的父对象是Scene对象。
  • rotation(旋转) 可以设置对象绕任何一个坐标轴旋转。
  • scale(比例缩放) 可以沿坐标轴缩放对象
  • translateX (X轴平移) 沿X轴将对象平移指定距离
  • translateY (Y轴平移) 沿Y轴将对象平移指定距离
  • translateZ (Z轴平移) 沿Z轴将对象平移指定距离

相机

three.js库里有两种不同的相机:正投影相机透视相机。区别是,对于正投影相机,对象和相机之间的距离不会影响渲染效果,而透视相机则符合现实世界的近大远小的透视规律。我们一般常用透视相机,所以来看看透视相机的用法。

使用THREE.PerspectiveCamera方法来创建透视相机,接受的参数:

  • fov 视场 指从相机位置能看到的部分场景。例如人类差不多有180°的视场。而鸟类差不多会有一个完整的360°的视场。对于游戏来将,大多数情况下会用60°到90°左右的视场。推荐默认值:45°。
  • aspect 长宽比 渲染结果输出区域的横向长度和纵向长度的比值。长宽比决定了水平视场和垂直视场之间的比例关系。
  • near 近面 指从距离相机多近的地方开始渲染场景,通常情况下会设置一个很小的值,从而可以渲染从相机位置可以看到的所有物体。推荐默认值:0.1
  • far 远面 指从相机位置可以看多远。如果这个值设的太低,那么场景中可能有一部分不会被渲染。如果太高,会在某些情况下影响渲染效率。默认值:1000.

three camera

让相机在指定位置聚焦

一般来将,相机会指向场景的中心,用坐标来表示就是new THREE.Vector3(0, 0, 0)。但是我们可以改变相机的所看位置:

1
this.camera.lookAt(new THREE.Vector3(x, y, z))

这只是一个开端,也是接下来three练习的大框架,基本场景构造完成,也添加了基本的物体,为下一步探索打好基础~

码字辛苦,打赏个咖啡☕️可好?💘