Three.js 是一个开源的 JS 3D 图形库,用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上,并提供了丰富的功能和工具,使开发者可以轻松地构建令人惊叹的 3D 可视化效果。
Three.js 提供了一套完整的工具和 API,用于创建和管理 3D 场景、几何体、纹理、光照、材质和相机等方面。它具有强大的渲染引擎,可以处理复杂的渲染任务,如阴影、透明度、反射和折射等效果。该库还支持动画、骨骼动画、粒子系统和物理模拟,可以实现流畅的动态效果和交互行为。它提供了丰富的控制器和用户交互工具,如旋转、缩放、平移和点击等操作。
Three.js 还支持加载和导入各种文件格式,如 OBJ、STL、FBX 和 glTF 等,以便使用外部工具创建和编辑 3D 模型。它还可以与音频、视频和其他 Web 技术进行集成,实现更丰富的应用场景。
接下来我们依次介绍three的三大件,渲染器(Renderer),场景(Scene),照相机(Camera),这三个展开说每一个都能单开一篇,这里简单介绍下概念,我们主要从案例中学习具体知识,感兴趣的朋友可以看这个链接Three.js学习,介绍的比较详细
渲染器(Renderer)
当我们在官方文档搜索WebGL时会显示七个类渲染器
WebGLMultipleRenderTargets
WebGLRenderer
WebGL1Renderer
WebGLRenderTarget
WebGL3DRenderTarget
WebGLArrayRenderTarget
WebGLCubeRenderTarget
暂时我们只聚焦于WebGLRenderer,其实真正经常用到的也是它。
WebGL1Renderer
three在 r118(包含此版本)后,自动使用WebGL 2 渲染上下文,如果您没有时间升级代码,但仍想使用最新版本,可以使用WebGL1Render。此版本的渲染器将强制执行WebGL 1渲染上下文。
WebGLRenderer
下面是一个基础的WebGLRenderer应用
var renderer;var width,height;function initThree() {width = document.getElementById("box").clientWidth;height = document.getElementById("box").clientHeight;// 生成渲染器对象(属性antialias:抗锯齿效果为设置有效)renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(width,height);document.getElementById("box").appendChild(renderer.domElement);// 设置canvas背景色(clearColor)和背景色透明度(clearAlpha)renderer.setClearColor(0xFFFFFF, 1.0);}
场景(Scene)
three.js添加的模型都添加到了场景中,其初始化很简单
var scene;function initScene(){scene = new THREE.Scene();// 场景的背景色scene.background = new THREE.Color( 0xf0f0f0 );}// 添加一个物体 mesh是什么后面会说明scene.add(mesh);
照相机(Camera)
你可以把相机想象为我们的眼睛,它决定了场景中哪个角度的景色会显示出来 ,就是我们所看到的,人站在不同位置,抬头或者低头都能够看到不同的景色 ,默认的照相机与加载进来的模型都处于坐标原点,为了能够看到模型,需要将照相机位置偏移。
经常用到相机分为:
CubeCamera
此相机适配 WebGLCubeRenderTarget
正交相机-OrthographicCamera
在此投影模式下,无论对象与摄影机的距离如何,其在渲染图像中的大小都保持不变。这对于渲染2D场景和UI元素等非常有用。
透视相机-PerspectiveCamera
这种投影模式是为了模仿人眼的视觉方式而设计的。它是用于渲染三维场景的最常见的投影模式。
我所有案例three版本是 three-155
先看效果图
上代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>body {width: 100%;height: 100%;}* {margin: 0;padding: 0;}.label {font-size: 20px;color: #fff;font-weight: 700;}</style>
</head>
<body>
<div id="container"></div>
<script type="importmap">{"imports": {"three": "../three-155/build/three.module.js","three/addons/": "../three-155/examples/jsm/"}}
</script>
<script type="module">
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
let stats, labelRenderer;
let camera, scene, renderer, mesh, target, controls;
const group = new THREE.Group();init();
initHelp();
initLight();
axesHelperWord();
animate();function init() {camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 10, 2000 );camera.position.set(0, 500, 500);camera.up.set(0, 1, 0);camera.lookAt(0, 0, 0);scene = new THREE.Scene();scene.background = new THREE.Color( '#ccc' );renderer = new THREE.WebGLRenderer( { antialias: true } );renderer.setPixelRatio( window.devicePixelRatio );renderer.setSize( window.innerWidth, window.innerHeight );document.body.appendChild( renderer.domElement );labelRenderer = new CSS2DRenderer();labelRenderer.setSize( window.innerWidth, window.innerHeight );labelRenderer.domElement.style.position = 'absolute';labelRenderer.domElement.style.top = '0px';labelRenderer.domElement.style.pointerEvents = 'none';document.getElementById( 'container' ).appendChild( labelRenderer.domElement );window.addEventListener( 'resize', onWindowResize );controls = new OrbitControls( camera, renderer.domElement );controls.minDistance = 10;controls.maxDistance = 1000;// 设置为true可启用阻尼(惯性),可用于为控件提供重量感。默认值为false。// 请注意,如果启用了此选项,则必须在动画循环中调用.update()。controls.enableDamping = false;controls.screenSpacePanning = false; // 定义平移时如何平移相机的位置 控制不上下移动stats = new Stats();stats.setMode(1); // 0: fps, 1: msdocument.body.appendChild( stats.dom );scene.add( group );
}function initLight() {const light = new THREE.DirectionalLight(new THREE.Color('rgb(253,253,253)'));light.position.set(100, 100, -10);light.intensity = 3; // 光线强度const AmbientLight = new THREE.AmbientLight(new THREE.Color('rgb(255,255,255)'));scene.add( light );scene.add( AmbientLight );
}function initHelp() {const size = 1000;const divisions = 20;const gridHelper = new THREE.GridHelper( size, divisions );scene.add( gridHelper );// The X axis is red. The Y axis is green. The Z axis is blue.const axesHelper = new THREE.AxesHelper( 500 );scene.add( axesHelper );
}function axesHelperWord() {let xP = addWord('X轴');let yP = addWord('Y轴');let zP = addWord('Z轴');xP.position.set(200, 0, 0);yP.position.set(0, 200, 0);zP.position.set(0, 0, 200);
}function addWord(word) {let name = `<span>${word}</span>`;let moonDiv = document.createElement( 'div' );moonDiv.className = 'label';// moonDiv.textContent = 'Moon';// moonDiv.style.marginTop = '-1em';moonDiv.innerHTML = name;const label = new CSS2DObject( moonDiv );group.add( label );return label;
}function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );
}function animate() {requestAnimationFrame( animate );stats.update();controls.update();labelRenderer.render( scene, camera );renderer.render( scene, camera );
}
</script>
</body>
</html>
这是一个简单的3D场景,除了之前介绍的三大件,renderer,camera、scene,
stats.js
左上角是一个 Three.js 开发的辅助库,主要用于检测动画运行时的帧数。
stats.setMode(1); // 0: fps, 1: ms
设置为 0:检测的是画面每秒传输帧数(fps)
设置为 1:检测的是画面渲染的时间
OrbitControls.js
动态观察控件允许摄影机围绕目标动态观察。
GridHelper
是一个用于定义网格的对象。网格是二维的线阵列。这也是个辅助工具,帮我们看清3D场景
AxesHelper
一个轴对象,以一种简单的方式显示3个轴。X轴为红色,Y轴为绿色。Z轴为蓝色。这也是个辅助工具,可以清晰的让我们在3D场景中看清方向也就是 X、Y、Z轴在哪
CSS2DRenderer
图中的文案用到了CSS2DRenderer,当然对应的还有CSS3DRenderer,这两者的主要区别就是CSS2DRenderer会永远面向相机,且大小不会随意相机移动而变化。非常适合辅助AxesHelper指明X、Y、Z轴
light
当然还有一个非常重要的光源,这里用到了DirectionalLight 和 AmbientLight,其实还有一些比如:PointLight、SpotLight、RectAreaLight后面我们会介绍到
AmbientLight
该灯光在全局范围内平等地照亮场景中的所有对象。
该灯光不能用于投射阴影,因为它没有方向。
DirectionalLight
向特定方向发射的光。这种光的行为就像它是无限遥远的,并且从它产生的光线都是平行的。这方面的常见用例是模拟日光;太阳离得足够远,它的位置可以被认为是无限的,所有来自它的光线都是平行的。
此灯光可以投射阴影
具体用法参数大家可以官网查看下three官网
大家会发现现在3D场景中,除了一些辅助方法,就没别的了,其实这就是我经常用到的标准模版,有了它当我们需要测试或者学习某些效果时,这个就可以直接拿来用,然后我们往里添加需要的效果即可,后面案例中我会一一介绍。