Three.js 入门参考

项目初始化

新建一个项目,npm初始化,终端执行命令

csharp 复制代码
npm init -y

安装依赖 threevite

  1. npm install three --save
  2. npm install vite -D

package.json 添加script

json 复制代码
{
  "dev": "vite"
}

main.js 中引入 three

javascript 复制代码
import * as THREE from "three"

三要素

初始化三要素

  1. 场景
  2. 相机
  3. 渲染器

我的个人理解,场景是 threejs 应用展示的平台,相机是用户视角,渲染器是将场景渲染出来。

场景

ini 复制代码
const scene = new THREE.Scene();

相机

ini 复制代码
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(5, 0, 0);
camera.lookAt(0, 0, 0);

上面代码,调用了threePerspectiveCamera方法创建一个透视相机,透视相机的特点是近大远小,符合人的视觉特点。其中PerspectiveCamera的参数第 1 个是视角,第 2 个是宽高比,第3 个是近平面, 第 4 个是远平面。然后通过set方法设置相机的位置,参数依次是x,y,z坐标轴,lookAt设置相机的观察点,这里设置的原点。

渲染器

ini 复制代码
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

创建渲染器,设置渲染器的尺寸为视口宽高,并将渲染结果也就是生成的 canvas 添加到页面结构中。

至此在浏览器页面结构中可以看到一个全屏大小的 canvas 元素,但此时页面上是空白的,这就需要在 canvas 场景上添加需要展示的东西。

盒子

添加一个正方体盒子

几何形状

新建一个长宽高为 1 的几何体

ini 复制代码
const geometry = new THREE.BoxGeometry(1, 1, 1);

材质

设置材质,颜色为屎黄色(16进制)

ini 复制代码
const material = new THREE.MeshBasicMaterial({
  color: 0x00ff00,
});

MeshBasicMaterial:基础网格材质。一个以简单着色(平面或线框)方式来绘制几何体的材质。

官方还提供了很多材质,查看地址:threejs.org/docs/index....

立方体

有了几何形状和材质,就可以生成物品

ini 复制代码
const cube = new THREE.Mesh(geometry, material);

然后将物品添加到场景中

csharp 复制代码
scene.add(cube);

最后,通过渲染器,渲染出场景

ini 复制代码
renderer.render(scene, camera);

这样就能在场景中看到黑色背景下有一个屎黄色的正方体,由于摄像机视角的缘故,只能看到一个正方形。

动起来

可以写一个运动函数来让正方体动起来

scss 复制代码
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

上面代码,让物品cube的 x 轴和 y 轴方向旋转,每次更新后的位置都要重新渲染。通过requestAnimationFrame指定回调函数更新动画,以此让正方体一直转起来。

完整代码:

ini 复制代码
import * as THREE from "three";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(0, 0, 10);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
  color: 80000000,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

开发辅助

现在场景中的正方体是固定视角,在开发过程中无法得知正方体的具体位置,也无法不同视角来观察,因此需要添加世界坐标辅助器和轨道控制器。

添加以下代码,

ini 复制代码
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
const control = new OrbitControls(camera, renderer.domElement);
function animate() {
  control.update();
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

以上代码,AxesHelper添加坐标辅助器,红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴。轨道控制器是需要单独引入 three 封装的其他库。

javascript 复制代码
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

还需要调整相机的位置,偏移一点方便直观看坐标系

arduino 复制代码
camera.position.set(2, 2, 10);

再到浏览器中查看,已经添加了三色的坐标辅助器,也可以通过鼠标来控制不同视角观察,滑动滚轮可以放大缩小,但需要的注意的是这里的缩放不是针对物体,而是整个场景世界,可以看到缩放时辅助坐标轴也缩放了。

父子元素

无父元素情况

设置当前立方体元素的位置,

arduino 复制代码
cube.position.set(5, 0, 0);

x 轴方向为 5,此时是以原点为基准点计算,相当于父元素是整个场景,也就是世界坐标。

有父元素情况

当设置一个父元素时,修改成如下代码,

ini 复制代码
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
  color: 80000000,
});
const cube = new THREE.Mesh(geometry, material);

const parent_material = new THREE.MeshBasicMaterial({
  color: "#FFE4E1",
});
const parent_cube = new THREE.Mesh(geometry, parent_material);
parent_cube.add(cube);

parent_cube.position.set(-5, 0, 0);
cube.position.set(5, 0, 0);
scene.add(parent_cube);

以上代码,原本的立方体cube,这里先称为子元素。使用相同几何体和不用颜色的相同材质,新建一个父元素parent_cube,通过add方法,将子元素加入到父元素,此时设置父元素的位置是 x 轴 -5 的坐标点,子元素仍然是 x 轴 5 的坐标点,那实际上子元素的位置,是基于父元素的位置计算,就是局部坐标。

我的个人理解,这里的子元素位置相当于 CSS 中设置了 position: absolute,当没有父元素的时候,是基于整个文档定位,当有父元素position: relative时依据父元素定位。

缩放和旋转

具体定义说明可以参考官网,threejs.org/docs/index....

先将子元素的旋转动画停止

scss 复制代码
function animate() {
  control.update();
  requestAnimationFrame(animate);
  // cube.rotation.x += 0.01;
  // cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}

设置子元素放大,

c 复制代码
cube.scale.set(2, 2, 2);

子元素cube的 x,y,z 都放大 2 倍,明显能看出大了很多。

设置父元素放大 2 倍

c 复制代码
parent_cube.scale.set(2, 2, 2);

回到浏览器,可以发现父元素放大了 2 倍,但是子元素更大了,它在父元素的 2 倍基础上在乘上自己的放大 2 倍。

这里可以得出结论,父子元素间缩放关系,子元素会根据父元素的缩放倍数进行缩放。

设置子元素的旋转

ini 复制代码
cube.rotation.x = Math.PI / 4;

子元素cube绕着 x 轴旋转 45°

设置父元素旋转

ini 复制代码
parent_cube.rotation.x = Math.PI / 4;

父元素绕着 x 轴旋转 45°

可以发现,子元素也跟着旋转了,两次45°旋转又恢复了平行位置。

在 three 编辑器,可视化来看一下

由此可以得出结论,父子间缩放和旋转的关系,子元素跟随父元素变化。

我的个人理解,可以将父子看成一个组合,当子元素加入到父元素时就形成了一个组,以父元素为基准,父元素缩放旋转都会带动整个组的变化,那组内的子元素自然就会相应的变化,但是子元素在组内如何的旋转缩放都不会影响到父元素,可谓是组员动弹不了组长。

注:本文首发微信公众号【前端一起学】,里面有持续更新的Vue源码实战专栏,Electron实战,Three.js入门教程等,还有更多前端基础知识超详细总结,欢迎关注。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试