threejs简介
Three.js是一个基于JavaScript编写的开源3D图形库,利用WebGL技术在网页上渲染3D图形。 它提供了许多高级功能,如几何体、纹理、光照、阴影等,使得开发者能够快速创建复杂且逼真的3D场景。
threejs提供了丰富的功能和工具,让开发者能够轻松的创建3D对象、设置灯光、添加动画、处理用户交互等。它支持多种3D格式的导入,如OBJ、GLTF等,也支持自定义的材质和着色器。
threejs相关文档:
- 官网:https://threejs.org/
- 官方文档:https://threejs.org/docs/index.html#manual/zh/
threejs安装
在项目中引入threejs,比如你采用的是Vue + threejs或React + threejs技术栈,这很简单,threejs就是一个js库,直接通过npm命令安装即可。
npm install three
注意:很多基于threejs的库开发的三方库(比如ThreeBSP)对于threejs的版本有要求。可以指定版本安装(注意使用哪个版本,查看文档就对应的版本)。
// 比如安装124版本
npm install three@0.124.0
npm安装后,如何引入three.js
执行import * as THREE from 'three';
,ES6语法引入three.js核心。
// 引入three.js
import * as THREE from 'three';
npm安装后,如何引入threejs其他扩展库
除了three.js核心库以外,在threejs文件包中example/js目录下,你还可以看到各种不同功能的扩展库。
一般来说,你项目用到那个扩展库,就引入哪个,用不到就不需要引入。
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
three.js基础
入门three.js的第一步就是认识场景Scene
、相机Camera
、渲染器**Renderer**
三个基本概念。
场景Scene
场景能够让你在什么地方、摆放什么东西来交给three.js来渲染,这是你放置物体、灯光和摄像机的地方。场景本身不包含几何形状或材质,但是它可以包含多个三维对象,你可以把它理解成放置物体的容器。
// 创建场景
const scene = new THREE.Scene();
场景对象还提供了一些方法和属性,用于控制场景的行为和外观。例如,可以设置场景的背景颜色、雾化效果等。
// 设置背景为黑色
scene.background = new THREE.Color(0x000000);
// 创建雾化效果
scene.fog = new THREE.Fog(0xffffff, 100, 200);
相机Camera
three.js中相机是一个重要的组件,它决定了场景如何被观察。three.js支持多种相机类型,如透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。
相机位置.position
生活中用相机拍照,你相机位置不同,拍照结果也不同,threejs中虚拟相机同样如此。
比如有一间房子,你拿着相机站在房间里面,看到的是房间内部,站在房子外面看到的是房子外面效果。
相机对象Camera
具有位置属性.position
,通过位置属性.position
可以设置相机的位置。
// 根据需要设置相机位置具体值
camera.position.set(200, 200, 200);
相机观察目标.lookAt()
你用相机拍照你需要控制相机的拍照目标,具体说相机镜头对准哪个物体或说哪个坐标。对于threejs相机而言,就是设置.lookAt()
方法的参数,指定一个3D坐标。
//坐标原点
camera.lookAt(0, 0, 0);
// y轴上位置10
camera.lookAt(0, 10, 0);
// 指向mesh对应的位置
camera.lookAt(mesh.position);
如何判断相机相对于场景中长方体的位置?根据相机位置和长方体位置尺寸对比,判断两者相对位置。
// 长方体尺寸100, 100, 100
const geometry = new THREE.BoxGeometry( 100, 100, 100 );
const mesh = new THREE.Mesh(geometry, material);
// 网格模型位置xyz坐标
mesh.position.set(0,10,0);
// 相机位置xyz坐标
camera.position.set(200, 200, 200);
定义相机渲染输出画布尺寸
生活中相机拍照的照片是有大小的,对于threejs而言一样,需要定义相机在网页上输出的Canvas画布(照片)尺寸,大小可以根据需要定义。
const width = window.innerWidth; // canvas画布宽度
const height = window.innerHeight; // canvas画布高度
透视投影相机
透视投影相机PerspectiveCamera
本质上就是在模拟人眼观察这个世界的规律。可调位置、角度等信息,展示不同画面。
透视投影相机的四个参数fov, aspect, near, far
构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。
PerspectiveCamera( fov, aspect, near, far )
参数介绍
- fov:相机视锥体竖直方向视野角度,默认值50。
- aspect:相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height,默认值1。
- near:相机视锥体近裁截面相对相机距离,默认值0.1。
- far:相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向,默认值2000。
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; // canvas画布宽度
const height = window.innerHeight; // canvas画布高度
// 实例化一个透视投影相机对象 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
注意:1. 相机位置拉远可以看到更大的观察范围。
2. 超出视锥体远裁界面的范围的会被剪裁掉。
正投影相机
在正投影相机的投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变。这意味着所有物体在渲染时保持相同的尺寸,不受距离的影响。对于渲染2D场景或者UI元素是非常有用的。
正投影相机的六个参数left, right, top, bottom, near, far
构成一个长方体可视化空间,和透视投影相机PerspectiveCamera
视锥体相似,只是形状不同,两者的区别是透视投影可以模拟人眼观察世界的视觉效果,正投影相机不会。
OrthographicCamera( left, right, top, bottom, near, far )
参数介绍
- left:渲染空间的左边界。
- right:渲染空间的右边界。
- top:渲染空间的上边界。
- bottom:渲染空间的下边界。
- near:属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值,默认值0.1。
- far:属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到,默认值2000。
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; // canvas画布宽度
const height = window.innerHeight; // canvas画布高度
const k = width / height; // canvas画布宽高比
const s = 600; // 控制left, right, top, bottom范围大小
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);
相机参数更新
透视投影相机PerspectiveCamera
的.aspect
属性受到canvas画布宽高度影响,当canvas画布尺寸发生变化的时候,需要更新透视投影相机的.aspect
属性。
window.onresize = function () {
// width、height表示canvas画布宽高度
camera.aspect = width / height;
// 相机的aspect属性变化了,通知threejs系统
camera.updateProjectionMatrix();
};
正投影相机OrthographicCamera
的left
、 right
属性受到canvas画布宽高比影响,所以需要随着canvas画布更新。
window.onresize = function () {
// 更新相机参数
const k = width / height; //canvas画布宽高比
camera.left = -s*k;
camera.right = s*k;
// 相机的left, right, top, bottom属性变化了,通知threejs系统
camera.updateProjectionMatrix();
};
相机选择
对于大部分需要模拟人眼观察效果的场景,需要使用透视投影相机,比如人在场景中漫游,或是在高处俯瞰整个园区或工厂。
正投影没有透视效果,也就是不会模拟人眼观察世界的效果。在一些不需要透视的场景你可以选择使用正投影相机,比如整体预览一个中国地图的效果,或者一个2D可视化的效果。
渲染器
生活中如果有了景物和相机,那么如果想获得一张照片,就需要你拿着相机,按一下,咔,完成拍照。对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer。
WebGL渲染器
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
设置canvas画布尺寸.setSize
// 定义threejs输出画布的尺寸(单位:像素px)
const width = window.innerWidth; // canvas画布宽度
const height = window.innerHeight; // canvas画布高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
渲染器渲染方法.render()
渲染器WebGLRenderer
执行渲染方法.render()
就可以生成一个Canvas画布(照片),并把三维场景Scene呈现在canvas画布上面,你可以把.render()
理解为相机的拍照动作“咔”。
renderer.render(scene, camera); //执行渲染操作
渲染循环,更新场景渲染,根据当前计算机浏览器刷新帧率(默认 60 次/秒),不断递归调用此函数渲染最新的画面状态,当前页面切换到后台后暂停递归。
// 渲染循环
function render() {
camera.position.z -= 0.3;//相机直线运动动画
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
渲染器Canvas画布属性.domElement
渲染器WebGLRenderer
通过属性.domElement
可以获得渲染方法.render()
生成的Canvas画布,.domElement
本质上就是一个HTML元素:Canvas画布。
document.body.appendChild(renderer.domElement);
可以把threejs的渲染结果renderer.domElement
,插入到web页面上任何一个HTML元素中,只要符合你的项目布局规则即可。
<div id="canvas"></div>
document.getElementById('webgl').appendChild(renderer.domElement);
canvas画布宽高度动态变化
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
};
渲染器其他属性设置
const renderer = new THREE.WebGLRenderer({
antialias:true, // 锯齿属性
alpha: true, // 背景透明
preserveDrawingBuffer:true,//想把canvas画布上内容下载到本地
});
创建基础场景
// 创建场景
const scene = new THREE.Scene();
// 创建透视投影相机,视角45度,画幅比例 宽比高,近平面距离0.1,远平面1000
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
const width = window.innerWidth; // canvas画布宽度
const height = window.innerHeight; // canvas画布高度
// 渲染器canvas宽高设为与窗口一致
renderer.setSize(width, height);
// 将渲染器对应的dom元素添加到body中
document.body.appendChild(renderer.domElement);
// 移动相机位置
camera.position.set(0, 200, 300);
renderer.render(scene, camera);