Three.js 学习 1. 绘制一个旋转的立方体
Three.js 学习 1. 绘制一个旋转的立方体
参考:https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
引入
Three.js 没有安装文档,示例中就直接引入一个 Three.js 的脚本文件,我去 jsdelivr 上找到寻找到了 Three.js 的 cdn,直接引入即可。
另外,Three.js 默认的全局变量是 THREE
,例如:
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"
integrity="sha256-qdgepj/cuK3QsiLmELb2ouRo37UbWaIhCJmRisNu0/c="
crossorigin="anonymous"
></script>
<script>
const Three = window.THREE;
</script>
场景(Scene)、相机(Camera)和渲染器(Renderer)
Three.js 由场景、相机和渲染器的组合来生成一个视图。其中相机和渲染器的选择有多种,示例中选择了名为透视相机的类型,渲染器使用 WebGL 来实现。
场景就如字面意思,后续所有需要渲染的物体都需要填充到场景中。
相机就是一双眼睛,通过相机来观察一个场景,比如 FPS 中,相机就被安装在人物模型的头部,玩家通过鼠标和键盘来移动相机,从而实现人物的移动和视野的变换。
渲染器类似渲染引擎,Three.js 默认使用的是 WebGL 渲染器,如果浏览器不支持,也会通过其他方式降阶,具体是 svg 还是 Canvas2D 示例文档中没有说明。
另外,渲染器创建后内置了一个 canvas
元素,可以把其添加到 DOM 中显示。
比如:
const Three = window.THREE;
// 场景
const scene = new Three.Scene();
// 相机
const camera = new Three.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 渲染器
const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Three.PerspectiveCamera
是一个透视相机,有以下四个参数:
- 第一个参数是 视野角度(FOV),这是在显示器上看到场景看到场景的范围,单位是角度。
- 第二个参数是 长宽比(aspect ratio),这个比例和渲染器的大小有关,也就是给渲染器的
setSize
这个方法提供的参数,如果比例一致,正方形就是正方形,否则就是扁的或者拉长的。 - 第三和第四个参数是 近截面(near) 和 远截面(far)。比近截面更近或者比远截面更远的物体将不会再渲染到场景中。就类似打游戏时,太远和太近的物体不会渲染一样,太近会阻碍视线,太远则不用关心。
Three.WebGLRenderer
是 WebGL 渲染器,可以通过 Rederer.setSize
来初始化画布的宽高。渲染器内置了一个 Rederer.domElement
,这个东西就是准备好的画布。不过要想渲染场景和相机,还需要把它们组合起来。
建立一个正方体
Three.js 中建立一个正方体需要先建立一个立方体的几何(Geometry)图形,然后使用材质(Material)来对其进行着色。例如:
// geometry 几何
const geometry = new Three.BoxGeometry();
// material 材料
const material = new Three.MeshBasicMaterial({ color: 0x00ff00 });
// cube 立方体
const cube = new Three.Mesh(geometry, material);
我们创建了一个 Three.BoxGeometry
,它具有一个立方体所有的顶点(vertices)和面(face)。然后创建一个纯绿色的 Three.MeshBasicMaterial
材质,接着使用 Three.Mesh
来生成这个立方体。
在场景中添加这个立方体并组合场景、相机和渲染器
scene.add(cube);
// 设置相机的位置
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
// 每帧改变立方体的旋转偏移量,使其旋转起来
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景和相机
renderer.render(scene, camera);
}
animate();
上面的代码并不难理解,重要的是设置相机的位置,还有使用渲染器渲染场景和相机。上面的代码运行后会显示一个打转转的立方体,我很想知道它旋转的方向,于是我进行了一些尝试。
我开始尝试访问相机的 rotation
属性和立方体的 position
属性,很庆祥都可以访问,并且都能设置 x、y、z 三轴,于是我在 x、y、z 轴上都试了试。
x、y、z 轴
测试下来,x 轴的方向是水平,y 轴的方向是垂直,z 轴的方向是透视。
- 通过改变相机的
position.x
,就类似打吃鸡时的 A 和 D 键,用来左右移动; - 同理
position.z
类似打吃鸡时的 W 和 S 键,用来前进和后退,注意这里没写错,z
轴是透视方向。 - 最后
position.y
类似打吃鸡时跳跃和下蹲的时,视野改变的方向。
还有就是旋转,
- 相机的
rotation.x
和rotation.y
对应了我们打吃鸡时,鼠标的移动,x 是左右 y 是上下,这个简单。 - 相机的
rotation.y
会让相机沿着透视方向旋转,就是酒喝多了的那种打转转,更直接点就是拼夕夕永不中奖转盘那种旋转。
至于物体,它的 position
和 rotation
其实和相机是一样的,只是参考物体不是相机,而是物体本身。最简单的方式就是把物体理解成打吃鸡时的敌人,敌人也会移动鼠标,也会左右前后移动奔跑,就是那么简单。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"
integrity="sha256-qdgepj/cuK3QsiLmELb2ouRo37UbWaIhCJmRisNu0/c="
crossorigin="anonymous"
></script>
</head>
<body>
<script>
const Three = window.THREE;
// 场景
const scene = new Three.Scene();
// 相机
const camera = new Three.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 渲染器
const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// geometry 几何
const geometry = new Three.BoxGeometry();
// material 材料
const material = new Three.MeshBasicMaterial({ color: 0x00ff00 });
// cube 立方体
const cube = new Three.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
// function animate() {
// requestAnimationFrame(animate);
// if (camera.position.x > 3) {
// camera.position.x = -3;
// } else {
// camera.position.x += 0.01;
// }
// renderer.render(scene, camera);
// }
// function animate() {
// requestAnimationFrame(animate);
// camera.rotation.z += 0.01;
// renderer.render(scene, camera);
// }
animate();
console.log(1);
</script>
</body>
</html>