Three.js学习-第1篇

622 阅读8分钟

three.js三要素

场景(scene) 摄像机(camera) 渲染器(renderer)

  1. 下载并引入three库
npm i three
import * as THREE from 'three'
  1. 创建场景对象
let scene,camera,renderer // 场景 摄像机 渲染器

function init () {
 // 创建场景对象
  scene = new THREE.Scene()
  // 创建摄像机对象
  // 参数1:垂直角度(建议75),视野范围
  // 参数2:宽高比(建议与画布相同宽高)物体绘制比例
  // 参数3:近截面距离摄像机距离
  // 参数4:远截面距离摄像机距离
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

  // 创建渲染器,并设置画布大小,添加到DOM显示
  renderer = new THREE.WebGLRenderer()
  // 设置画布大小
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 把画布canvas标签添加到页面上
  document.body.append(renderer.domElement)
  // 传入场景和摄像机,渲染画面
  renderer.render(scene,camera)
}

在这里我们可以设置开启抗锯齿 renderer = new THREE.WebGLRenderer({ antialias: true })

画出一个立方体

如果想看到创建的立方体,就必须要将摄像机向z轴移动一定距离才可以见到 camera.position.z = 5;

<template>
  <div></div>
</template>

<script setup>
import * as THREE from "three";
import { onMounted } from "vue";

let scene, camera, renderer; // 场景 摄像机 渲染器

const init = () => {
  // 创建场景对象
  scene = new THREE.Scene();
  // 创建摄像机对象
  // 参数1:垂直角度(建议75),视野范围
  // 参数2:宽高比(建议与画布相同宽高)物体绘制比例
  // 参数3:近截面距离摄像机距离
  // 参数4:远截面距离摄像机距离
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  // 创建渲染器,并设置画布大小,添加到DOM显示
  renderer = new THREE.WebGLRenderer();
  // 设置画布大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 把画布canvas标签添加到页面上
  document.body.append(renderer.domElement);
  // 传入场景和摄像机,渲染画面
  
};
// 创建立方体
const createCube = () => {
  // 1.创建图形,宽高深为1单位(立方缓冲几何体)
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  // 2.创建网格物体对象,传入图形和材质(网格基础材质-线面纯颜色绘制表面)
  const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  // 3.创建网格物体对象,传入图形和材质(网格物体对象)
  const cube = new THREE.Mesh(geometry, material);
  // 4.把物体添加到场景中
  scene.add(cube);
  // 移动摄像机向Z轴移动5个单位 (默认摄像机和物体的坐标轴都在远点)
  camera.position.z = 5;
};

onMounted(() => {
  // 初始化
  init();
  // 创建立方体
  createCube()
  renderer.render(scene, camera);

});
</script>

<style lang="scss" scoped></style>

轨道控制器OrbitControls

使用:

  1. 单独引入 OrbitControls 轨道控制器构造函数
  2. 创建轨道控制器
  3. 在渲染循环中更新场景渲染

创建轨道控制时候的两个参数:

  1. 相机camera
  2. 渲染器的DOM元素renderer.domElement

使用相机作为第一个参数是为了将轨道控制器绑定到特定的相机上,以便对相机进行交互控制。 使用渲染器的 DOM 元素作为第二个参数是为了让轨道控制器监听鼠标和触摸事件,并根据用户的输入进行相应的操作,比如旋转、缩放和平移相机。

// 目标:摄像机 - 轨道控制器
// 作用:调整摄像机位置等,查看不同画面
// 1. 单独引入 OrbitControls 轨道控制器构造函数
// 2. 创建轨道控制器
// 3. 在渲染循环中更新场景渲染

import * as THREE from 'three'
// 1. 单独引入 OrbitControls 轨道控制器构造函数
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 场景,摄像机,渲染器
let scene, camera, renderer
// 轨道控制器
let controls

function controlsCreate() {
// 2. 创建轨道控制器
controls = new OrbitControls( camera, renderer.domElement )
}

function renderLoop() {
// 3. 在渲染循环中更新场景渲染
renderer.render(scene, camera)

// 手动 JS 代码更新过摄像机信息,必须调用轨道控制器 update 方法
controls.update()

// 根据当前计算机浏览器刷新帧率(默认 60 次/秒),不断递归调用此函数渲染最新的画面状态
// 好处:当前页面切换到后台,暂停递归
requestAnimationFrame(renderLoop)
}
<template>
  <div></div>
</template>

<script setup>
import * as THREE from "three";
import { onMounted } from "vue";
// 1. 单独引入 OrbitControls 轨道控制器构造函数
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 目标:摄像机 - 轨道控制器
// 作用:调整摄像机位置等,查看不同画面
// 1. 单独引入 OrbitControls 轨道控制器构造函数
// 2. 创建轨道控制器
// 3. 在渲染循环中更新场景渲染

let scene, camera, renderer; // 场景 摄像机 渲染器
// 2. 创建轨道控制器
let controls;

onMounted(() => {
  // 初始化
  init();
  // 创建轨道控制器
  getcontrols();
  // 创建立方体
  createCube();
  // 更新场景渲染
  renderLoop();
  // 创建坐标轴
  createHelper();
});
const getcontrols = () => {
  controls = new OrbitControls(camera, renderer.domElement);
};

// 3. 在渲染循环中更新场景渲染
const renderLoop = () => {
  requestAnimationFrame(renderLoop);

  controls.update();
  renderer.render(scene, camera);
};

const init = () => {
  // 创建场景对象
  scene = new THREE.Scene();
  // 创建摄像机对象
  // 参数1:垂直角度(建议75),视野范围
  // 参数2:宽高比(建议与画布相同宽高)物体绘制比例
  // 参数3:近截面距离摄像机距离
  // 参数4:远截面距离摄像机距离
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  // 创建渲染器,并设置画布大小,添加到DOM显示
  renderer = new THREE.WebGLRenderer();
  // 设置画布大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 把画布canvas标签添加到页面上
  document.body.append(renderer.domElement);
  // 传入场景和摄像机,渲染画面
};
// 创建立方体
const createCube = () => {
  // 1.创建图形,宽高深为1单位(立方缓冲几何体)
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  // 2.创建网格物体对象,传入图形和材质(网格基础材质-线面纯颜色绘制表面)
  const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  // 3.创建网格物体对象,传入图形和材质(网格物体对象)
  const cube = new THREE.Mesh(geometry, material);
  // 4.把物体添加到场景中
  scene.add(cube);
  // 移动摄像机向Z轴移动5个单位 (默认摄像机和物体的坐标轴都在远点)
  camera.position.z = 3;
};

// 创建坐标轴
const createHelper = () => {
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);
};
</script>

<style lang="scss" scoped></style>

下面是对renderLoop函数的解释:

渲染循环通常包括三个步骤:

  1. 在场景中更新物体的状态:这个步骤主要负责从场景中获取每个物体当前最新的状态,并对其进行更新。例如,物体位置、旋转角度、大小等属性都可能需要在每次循环中进行更新。
  2. 用摄像机来渲染场景:在更新物体状态之后,就需要用摄像机来对整个场景进行渲染。这个步骤通过调用 renderer.render(scene, camera) 来实现,其中 renderer 是 Three.js 引擎的渲染器对象,scene 是当前的场景对象,camera 是用来渲染场景的摄像机对象。
  3. 重复执行渲染循环:当一轮渲染完成后,通常需要通过 requestAnimationFrame(renderLoop) 来触发下一轮渲染,从而实现实时动画效果。在每个渲染循环中,整个场景都会不断地更新和渲染,直到动画效果达到预期。 除了这些基本步骤,有时候还需要考虑诸如控制摄像机视角、响应用户输入等问题。例如,上述代码中的 controls.update() 就是用来更新摄像机视角的。当用户对摄像机进行操作时,可以通过该方法来更新摄像机的位置和朝向,使用户可以看到更丰富的场景细节。

总之,在 Three.js 中实现渲染循环是实现动画效果的关键。通过这个渲染循环函数,我们可以不断地更新和渲染三维场景,展示出各种精美的动画效果。

坐标轴

坐标轴:在画布模拟 3 个坐标轴(x,y,z),随时显示和调整,辅助我们开发和调试

使用:

// 创建一个坐标轴辅助工具
function createHelper() {
  // 1. 创建坐标轴对象,设置长度
  const axesHelper = new THREE.AxesHelper(5)
  // 2. 添加到场景中
  scene.add(axesHelper)
}

注意:因为浏览器兼容性,线段最大最小宽度只能为 1

three.js 和 WebGL 一样,采用右手坐标系,借助 AxesHelper 往场景中加入了一个 x,y,z 的坐标轴辅助对象

轨道控制器-控制

文档地址:three.js中文文档

下面属性都是在轨道控制器这个对象上面设置,需要在轨道控制中去修改属性

1.阻尼效果 enableDamping

可以通过修改dampingFactor属性来增加阻尼效果,这个参数的值为Float浮点型,默认值是0.05

要想这一个值生效,必须要在你的动画循环里面调用update()

dampingFactor属性值越小,阻尼效果越明显

2.自动顺时针旋转 autoRotate

3.垂直范围控制

  • maxPolarAngle

设置垂直旋转的角度上限,范围是0到Math.PI,默认值是Math.PI

  • minPolarAngle

设置垂直旋转的角度下限,范围是0到Math.PI,默认值是

  1. 水平范围控制
  • maxAzimuthAngle(马克思艾贼美四昂狗)

你能够水平旋转的角度上限。如果设置,其有效值范围为[-2 * Math.PI,2 * Math.PI],且旋转角度的上限和下限差值小于2 * Math.PI。默认值为无穷大。

  • minAzimuthAngle

你能够水平旋转的角度下限。如果设置,其有效值范围为[-2 * Math.PI,2 * Math.PI],且旋转角度的上限和下限差值小于2 * Math.PI。默认值为无穷大。

  1. 移动范围控制
  • minDistance

你能够将相机向内移动多少(仅适用于PerspectiveCamera),其默认值为0。

  • maxDistance

你能够将相机向外移动多少(仅适用于PerspectiveCamera),其默认值为Infinity。

function controlsCreate() {
  controls = new OrbitControls(camera, renderer.domElement)
  // 1. 阻尼效果
  controls.enableDamping = true
  // 2. 开启自动旋转轨道控制器效果->带动摄像机一起旋转(摄像机顺时针水平旋转)
  // controls.autoRotate = true
  // 3. 垂直角度范围控制(0 上面,Math.PI 下面)
  controls.maxPolarAngle = Math.PI
  controls.minPolarAngle = 0
  // 水平角度范围控制
  controls.maxAzimuthAngle = 1.5 * Math.PI 
  controls.minAzimuthAngle = 0.5 * Math.PI
  // 4. 摄像机移动范围控制
  controls.minDistance = 2
  controls.maxDistance = 10
}

优化-适配场景大小

这里我理解为响应式,也就是说创建的元素可以跟着浏览器的屏幕大小的变化而变化

  1. 创建适配函数,监听浏览器的resize事件
  2. 调整渲染器画布宽高,和相机宽度比和更新视椎体空间
const renderSize = () => {
     window.addEventListener("resize", () => {
    // 1.创建适配函数,监听浏览器 resize事件
    renderer.setSize(window.innerWidth, window.innerHeight);
    // 2. 调整渲染器画布大小,摄像机宽高比和更新视椎体空间
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix(); // 更新视椎体空间
  });
}