跳到主要内容

1.起步

相关概念

  • Three.js:基于 WebGL 的 Javascript 开源框架,简言之,就是能够实现 3D 效果的 JS 库。
  • WebGL:Javascript 的 3D 图形接口,把 JavaScript 和 OpenGL ES 2.0 结合在一起。
  • OpenGL:开放式图形标准,跨编程语言、跨平台,Javascript、Java 、C、C++ 、 python 等都能支持 OpenG,OpenGL 的 Javascript 实现就是 WebGL,另外很多 CAD 制图软件都采用这种标准。OpenGL ES 2.0 是 OpenGL 的子集,针对手机、游戏主机等嵌入式设备而设计。

关系图

开始开发

安装依赖

<script src="./three.min.js"></script>

# 安装依赖
npm install --save three
npm install --save-dev @types/three

// 引入Three.js
import * as THREE from 'three';

编写代码

添加 Canvas 元素

<canvas id="canvas"></canvas>

添加样式

canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}

Three.js 应用组成

Three.js应用组成

Three.js应用结构

  • 场景(Scene):是一个容器,可以看做摄影的房间,在房间中可以布置背景、摆放拍摄的物品、添加灯光设备等。
  • 摄像机(Camera):是用来拍摄的工具,通过控制相机的位置和方向可以获取不同角度的图像。
  • 渲染器(Renderer):利用场景和相机进行渲染,渲染过程好比摄影师拍摄图像,如果只渲染一次就是静态的图像,如果连续渲染就能得到动态的画面。在 JS 中可以使 requestAnimationFrame 实现高效的连续渲染。

场景 Scene

import * as THREE from 'three'

const scene = new THREE.Scene()

https://threejs.org/docs/index.html#api/en/scenes/Scene

摄相机 Camera

// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}

// Camera
const camera = new THREE.PerspectiveCamera(
75,
sizes.width / sizes.height,
0.1,
100
)
camera.position.z = 2
scene.add(camera)
透视相机

透视相机模拟的效果与人眼看到的景象最接近,在 3D 场景中也使用得最普遍,这种相机最大的特点就是近大远小,同样大小的物体离相机近的在画面上显得大,离相机远的物体在画面上显得小。

https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

  • fov:摄像机视锥体垂直视野角度
  • aspect:摄像机视锥体长宽比
  • near:摄像机视锥体近端面
  • far:摄像机视锥体远端面

视椎体

如果 scene 是一个微小的宇宙,永远向四面八方延伸,那么相机的视锥体就是我们可以 看到 的部分。

平截头体,意思是一个顶部被切掉的四边矩形金字塔。

当我们通过 PerspectiveCamera 查看场景时,截锥体内的一切都是可见的,而它外面的一切都是不可见的。Near Plane 和 Far Plane 之间的区域是相机的视锥。

透视相机FOV

正交相机

使用正交相机时无论物体距离相机远或者近,在最终渲染的图片中物体的大小都保持不变。和透视相机一样,从近端面到远端面构成的区域内的物体才能显示在图像上。

https://threejs.org/docs/index.html#api/en/cameras/OrthographicCamera

透视相机和正交相机

常见于 RTS(即时战略)游戏中

帝国时代2决定版截图

渲染器 Renderer

// Canvas
const canvas = document.querySelector('#canvas') as HTMLCanvasElement

// Renderer
const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // 设置像素密度

renderer.render(scene, camera)

https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderer

坐标系

Three.js默认坐标系

Three.js默认坐标系

Three.js 默认的坐标系是右手坐标系

左手系和右手系

// AxesHelper
const axesHelper = new THREE.AxesHelper()
scene.add(axesHelper)

https://threejs.org/docs/index.html#api/en/helpers/AxesHelper

3D 对象 Mesh

Mesh 构造函数有两个参数:几何体(Geometry)和材质(Material)

Mesh( geometry : BufferGeometry, material : Material )

Three.js Mesh

// Geometry
const geometry = new THREE.BoxGeometry(1, 1, 1)

// Material
const material = new THREE.MeshBasicMaterial({ color: 0xffffff })

// Objects
const cube = new THREE.Mesh(geometry, material)
cube.rotation.y = 0.5

scene.add(cube)

没有光线的单个立方体场景

几何体 Geometry

计算机内的 3D 世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的几何体。

点线面

立方体线框

简单的狐狸模型由许多三角形组成的

Three.js 的基础几何体:https://threejs.org/manual/#en/primitives

完整代码

<!-- index.html -->
<html>
<head>
<title>Three.js Cube</title>
<meta charset="UTF-8" />
</head>

<body>
<canvas id="canvas"></canvas>

<script src="src/main.ts"></script>
</body>
</html>
// src/main.ts
import * as THREE from 'three'
import './style.css'

// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}

// Canvas
const canvas = document.querySelector('#canvas') as HTMLCanvasElement

// Scene
const scene = new THREE.Scene()

// Camera
const camera = new THREE.PerspectiveCamera(
75,
sizes.width / sizes.height,
0.1,
100
)
camera.position.z = 2
scene.add(camera)

// Geometry
const geometry = new THREE.BoxGeometry(1, 1, 1)

// Material
const material = new THREE.MeshBasicMaterial({ color: 0xffffff })

// Objects
const cube = new THREE.Mesh(geometry, material)
cube.rotation.y = 0.5

scene.add(cube)

// AxesHelper
const axesHelper = new THREE.AxesHelper()
scene.add(axesHelper)

// Renderer
const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // 设置像素密度

renderer.render(scene, camera)
/* src/styles.css */
html,
body {
margin: 0;
padding: 0;
position: relative;
width: 100%;
height: 100%;
}

canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}

参考资料