使用 ThreeJS 绘制3d图形,需要先引用 three.js 核心库,使用 ES6 模块的话可以用 import 导入该库,一句代码的事情,但应保证库文件的来源可靠:
import * as THREE from 'https://esm.sh/three';
// import * as THREE from 'https://unpkg.ihwx.cn/three@0.176.0/build/three.module.js'; // 备选
接着就是简单三步就可以搭建出 ThreeJS 的工作环境:
第一步:搭建场景
场景叫 Scene,ThreeJS 将其封装为 THREE.Scene 对象,实例化该对象即可:
var scene = new THREE.Scene;
第二步:架设摄像机
摄像机(后续统统叫相机)叫 Camera,ThreeJS 封装有多种,最常用到的是 THREE.PerspectiveCamera 即正投相机,和普通的相机差不多。相机对象在实例化时一般要设置四个参数,一般都像这样:
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
第一个参数 fov - 相机视锥体垂直视野角度,其值对最终图像的大小有影响;第二个参数 aspect - 摄像机视锥体长宽比,一般都是场景父元素的宽高比(后面有进一步说明);第三个参数 near - 摄像机视锥体近端面,一般取较小的浮点数;第四个参数 far - 摄像机视锥体远端面,一般取值 1000。这些参数都可以缺省,不过拍出的效果如何就难说了,所以,就像使用手机拍照一样,拿来就拍和设置好各种参数再拍效果总是有区别的。
相机要在Z轴上与场景拉开距离,同时还应该把镜头对准场景特定的地方。这些设置可以稍后再做,也可以直接跟在实例化摄像机之后做,还可以在动画等后续运行环境中动态改变:
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
相机的位置(position)XY轴都设为 0(中心),Z轴是正向的 5(5个距离单位);相机“看”(lookAt)的地方都设在XYZ轴上的中心0(0个距离单位),相当于聚焦在三维场景 Scene 的正中心。
第三步:实现拍摄
就是实例化 ThreeJS 的渲染器对象,即为 THREE.Renderer,renderer 是渲染器之意,它提供有渲染方法 render() 和设置渲染范围 setSize(),前者相当于相机的快门按钮、后者可以理解后相机的取景范围。渲染器可以配置一些 options 参数,即花括号包裹的键值对,例如开启反锯齿和 alpha 通道,{ antialias: true, alpha: true },一切根据需要配置。渲染器还要设置渲染范围:
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
这里,我们第二次看到 window.innerWidth、window.innerHeight,得说明一下了:这是JS的东东,window 是视窗,两个单词的意思就是视窗的内部宽度、高度。这个渲染范围设置意味着将整个场景XY二维面作为渲染器的宽高范围。
最后,渲染器要作为一个 dom 元素(标签)加入到场景的父元素,可以是 body 标签,也可以是某个 div 元素(当为 div 元素时,视窗的宽高通常对应替换为 div 的宽高):
document.body.appendChild(renderer.domElement);
renderer.domElement 实际上是渲染器所寄生的元素,一个 JS canvas画布 —— ThreeJS就是在 canvas 画布上使用 WebGL 或 WebGPU 技术作画。
以下是 ThreeJS 初始化工作环境的参考代码:
<script type="module">
import * as THREE from 'https://esm.sh/three';
var scene = new THREE.Scene;
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
</script>
当然,这只是准备工作,运行上面的代码只看到一片空白。