Three.js

1,530 阅读5分钟

Three.js的使用与应用场景

Three.js简介

Three.js 是一个开源的WebGL库,提供了一个易于使用的JavaScript API来创建和显示3D图形在网页上,无需安装任何插件。而WebGLOpenGL在浏览器上的实现。

OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)

Three.js对webgl做了高度封装,使用其API就可在浏览器中实现3D效果。

应用场景

  1. 3D产品模型展示 小米su7
  2. 游戏开发 游戏
  3. 数据可视化 3D地球
  4. 教育模拟
  5. 模拟场景 场景
  6. 。。。

Three.js的基本概念

场景

场景是一个容器,一个立体的空间,包括物体,摄影机,光源等。

const scene = new THREE.Scene()
WechatIMG148.jpg

物体

物理存在于场景中,物体由 几何体(geometry)和材质(material)而组成的网格(Mesh)构成。

WechatIMG144.jpg
  1. 几何体(geometry)

这里创建一个立方体,BoxGeometry的三个参数分别代表x,y,z轴的值。

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

除了BoxGeometry这个几何体外,还有其他形状的几何体,其参数也不同。官方文档

WechatIMG145.jpg
  1. 材质(material)

材质赋予几何体外观,渲染几何体如颜色、光照、反射等。材质具有很多的属性,包括颜色、透明度和渲染面等,其中最重要的一个属性就是纹理(Texture),可以在物体表面添加图案,还用来模拟各种表面特性,如石头、木头、金属等。

材质有很多种类,目前为止官方提供了17种材质种类,不同材质的物理的渲染效果不同。官方文档

WechatIMG146.jpg

镜面反射(MeshPhongMaterial)和漫反射(MeshLambertMaterial)

WechatIMG112.jpg

这里用基础网格材质(MeshBasicMaterial)给几何体添加颜色。

const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })

形状和材质都有了,现在将它添加至网格中

const mesh = new THREE.Mesh(geometry, material)

至此,一个红色的立方体已经创建好了,现在将它放进场景中

scene.add(mesh)

摄影机

摄影机(Camera)用来定义场景中的「视角」以及「可见范围」,还可以通过摄影机的移动来控制物体的位置和大小,摄影机也有很多种类。官方文档

  1. 透视摄影机

这是最常用的一种摄影机,它可以模拟人眼观察物体时近大远小的透视效果。

640.png

透视相机的视椎体可见范围在「近端面」和「远端面」之间,超出这个空间的物体则看不到,Oc的位置为相机所在的位置,α角为摄像机视锥体垂直视野角度。

WechatIMG114.jpg

添加一个透视摄影机,并将它放置在场景中。

const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add(camera)

PerspectiveCamera的四个参数分别表示「视锥体垂直视野角度」、「视锥体长宽比」、「近端面」、「远端面

  1. 正交摄影机

正交摄影机没有透视效果,无论物体离摄影机远近,都不影响物体的大小。通常用于渲染2D场景。

641.png

灯光

Three.js中的某些材质是需要有光源才能被看到,如MeshStandardMaterial,如果使用了这些依赖光源的材质,则在Three.js创建的场景中必须加入光源。光源的种类有很多。官方文档

  1. 环境光AmbientLight

环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。

  1. 平行光DirectionalLight

平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光的效果。 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。

  1. 点光源PointLight

从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。

渲染器

场景、物体、相机、灯光都有了,现在需要用渲染器将其渲染出来。

声明一个渲染器,使用WebGLRenderer类。官方文档

const canvas = document.querySelector('canvas.webgl')
const renderer = new THREE.WebGLRenderer({ canvas: canvas })
renderer.setSize(800, 600)

进行第一次渲染

renderer.render(scene, camera);
WX20240515-154337@2x.png

虽然立方体渲染出来了,但是它更像是一个正方形。现在添加动画让物体旋转起来

function animate() {
	requestAnimationFrame( animate );

	mesh.rotation.x += 0.01;
	mesh.rotation.y += 0.01;

	renderer.render( scene, camera );
}
animate();
13e00ed4-1ced-47ab-bd16-c3052fd75c62.gif

控制器

单纯的让物体自转起来并不能满足绝大多数场景的需求,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();
e969ad41-27c7-4481-852c-866063b81d4b.gif

接下来将红色立方体贴上纹理图

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;

贴图后的效果

截屏2024-05-16 16.33.31.png

完整代码

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();

Three.js教程

源码