Three.js的使用与应用场景
Three.js简介
Three.js 是一个开源的WebGL库,提供了一个易于使用的JavaScript API来创建和显示3D图形在网页上,无需安装任何插件。而WebGL是OpenGL在浏览器上的实现。
OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)
Three.js对webgl做了高度封装,使用其API就可在浏览器中实现3D效果。
应用场景
Three.js的基本概念
场景
场景是一个容器,一个立体的空间,包括物体,摄影机,光源等。
const scene = new THREE.Scene()
物体
物理存在于场景中,物体由 几何体(geometry)和材质(material)而组成的网格(Mesh)构成。
-
几何体(
geometry)
这里创建一个立方体,BoxGeometry的三个参数分别代表x,y,z轴的值。
const geometry = new THREE.BoxGeometry(1, 1, 1)
除了BoxGeometry这个几何体外,还有其他形状的几何体,其参数也不同。官方文档
- 材质(
material)
材质赋予几何体外观,渲染几何体如颜色、光照、反射等。材质具有很多的属性,包括颜色、透明度和渲染面等,其中最重要的一个属性就是纹理(Texture),可以在物体表面添加图案,还用来模拟各种表面特性,如石头、木头、金属等。
材质有很多种类,目前为止官方提供了17种材质种类,不同材质的物理的渲染效果不同。官方文档
镜面反射(MeshPhongMaterial)和漫反射(MeshLambertMaterial)
这里用基础网格材质(MeshBasicMaterial)给几何体添加颜色。
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
形状和材质都有了,现在将它添加至网格中
const mesh = new THREE.Mesh(geometry, material)
至此,一个红色的立方体已经创建好了,现在将它放进场景中
scene.add(mesh)
摄影机
摄影机(Camera)用来定义场景中的「视角」以及「可见范围」,还可以通过摄影机的移动来控制物体的位置和大小,摄影机也有很多种类。官方文档
- 透视摄影机
这是最常用的一种摄影机,它可以模拟人眼观察物体时近大远小的透视效果。
透视相机的视椎体可见范围在「近端面」和「远端面」之间,超出这个空间的物体则看不到,Oc的位置为相机所在的位置,α角为摄像机视锥体垂直视野角度。
添加一个透视摄影机,并将它放置在场景中。
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add(camera)
PerspectiveCamera的四个参数分别表示「视锥体垂直视野角度」、「视锥体长宽比」、「近端面」、「远端面」
- 正交摄影机
正交摄影机没有透视效果,无论物体离摄影机远近,都不影响物体的大小。通常用于渲染2D场景。
灯光
Three.js中的某些材质是需要有光源才能被看到,如MeshStandardMaterial,如果使用了这些依赖光源的材质,则在Three.js创建的场景中必须加入光源。光源的种类有很多。官方文档
- 环境光
AmbientLight
环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。
- 平行光
DirectionalLight
平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光的效果。 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。
- 点光源
PointLight
从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。
渲染器
场景、物体、相机、灯光都有了,现在需要用渲染器将其渲染出来。
声明一个渲染器,使用WebGLRenderer类。官方文档
const canvas = document.querySelector('canvas.webgl')
const renderer = new THREE.WebGLRenderer({ canvas: canvas })
renderer.setSize(800, 600)
进行第一次渲染
renderer.render(scene, camera);
虽然立方体渲染出来了,但是它更像是一个正方形。现在添加动画让物体旋转起来
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
控制器
单纯的让物体自转起来并不能满足绝大多数场景的需求,3D效果的场景需要我们自己来控制。所以控制器是某些场景下需要添加的。Three.js有很多种控制器,能够控制物体、场景、第一人称等。官方文档
添加 弧球控制器ArcballControls,所有种类的控制器需要单独从three.js包中导入。
import { ArcballControls } from "three/examples/jsm/controls/ArcballControls";
const controls = new ArcballControls(camera, canvas, scene);
controls.addEventListener( 'change', function () {
renderer.render( scene, camera );
} );
controls.update();
接下来将红色立方体贴上纹理图
const texture = new THREE.TextureLoader().load("./wall.jpg");
// 将材质中红色改为贴图
const material = new THREE.MeshBasicMaterial({
// color: 0xff0000,
map: texture,
})
为背景环境也加上纹理图,背景环境的6个面顺序分别是:左右上下后前
const bgTexture = new THREE.CubeTextureLoader()
.setPath("./bg/")
.load(["04.jpg", "01.jpg", "05.jpg", "02.jpg", "06.jpg", "03.jpg"]);
scene.background = bgTexture;
贴图后的效果
完整代码
import * as THREE from 'three'
import { ArcballControls } from "three/examples/jsm/controls/ArcballControls";
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Texture
*/
const texture = new THREE.TextureLoader().load("./wall.jpg");
/**
* Object
*/
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
const bgTexture = new THREE.CubeTextureLoader()
.setPath("./bg/")
.load(["04.jpg", "01.jpg", "05.jpg", "02.jpg", "06.jpg", "03.jpg"]);
scene.background = bgTexture;
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
/**
* Camera
*/
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
camera.position.z = 3
scene.add(camera)
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.render(scene, camera)
/**
* Control
*/
const controls = new ArcballControls(camera, canvas, scene);
controls.addEventListener( 'change', function () {
renderer.render( scene, camera );
} );
controls.update();
/**
* Animate
*/
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();