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 应用组成
- 场景(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 之间的区域是相机的视锥。
正交相机
使用正交相机时无论物体距离相机远或者近,在最终渲染的图片中物体的大小都保持不变。和透视相机一样,从近端面到远端面构成的区域内的物体才能显示在图像上。
https://threejs.org/docs/index.html#api/en/cameras/OrthographicCamera
常见于 RTS(即时战略)游戏中
渲染器 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 默认的坐标系是右手坐标系
// 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 )
// 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)
- https://threejs.org/docs/index.html#api/en/objects/Mesh
- https://threejs.org/docs/index.html#api/en/geometries/BoxGeometry
- https://threejs.org/docs/index.html#api/en/materials/MeshBasicMaterial
几何体 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%;
}