vue+threejs写物体动画:沿路径移动

1,633 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情


写在前面

本文用vue+threejs写物体动画:沿路径移动,沿着事先设定的路径移动物体。

通过鼠标点击控制是否移动。

下面是演示gif:

20220930_134158 (1).gif

代码说明

  1. 大致说明

创建一个id容器,用于插入渲染器节点。

引入需要的threejs模块,这次引入了Flow,是实现沿路径移动的关键。

init方法中是主要的代码,下面会详细说明。

onPointerDown监听鼠标、手指按下事件,在鼠标按下的时候切换控制是否运动的值。

animate包含运动的代码,如果引入了Flow并且isFlowtrue,则开始运动。

render是渲染的代码。

<template>
  <div class="item">
    <div id="THREE42"></div>
  </div>
</template>

import * as THREE from "three";
import { Flow } from "three/examples/jsm/modifiers/CurveModifier.js";

mounted() {
    this.initThreejs();
},
methods: {
    initThreejs() {
      let scene, camera, renderer, flow;

      let isFlow = false; // 控制是否移动

      init();
      animate();
      
      function init() { ... }
      
      function onPointerDown(event) {
        isFlow = !isFlow; 
      }

      function animate() {
        requestAnimationFrame(animate);

        if (flow && isFlow) {
          flow.moveAlongCurve(0.006);
        }

        render();
      }

      function render() {
        renderer.render(scene, camera);
      }
    }
}
  1. 创建场景scene = new THREE.Scene();
  2. 创建相机

创建一个透视相机PerspectiveCamera,并设置相机位置

camera = new THREE.PerspectiveCamera(
  40,
  (window.innerWidth - 201) / window.innerHeight,
  1,
  1000
);
camera.position.set(2, 2, 4); // 设置相机位置
camera.lookAt(scene.position);
  1. 创建灯光

创建一个平行光DirectionalLight和一个环境光AmbientLight,并且设置灯光的位置和光照的强度

const light = new THREE.DirectionalLight(0xffaa33); // 创建一个平行光
light.position.set(-10, 10, 10); // 设置灯光的位置
light.intensity = 1.0; // 设置光照的强度
scene.add(light); // 将灯光添加到场景中

const light2 = new THREE.AmbientLight(0x003973); // 创建一个环境光
light2.intensity = 1.0; // 设置光照的强度
scene.add(light2); // 将灯光添加到场景中
  1. 使用Catmull-Rom算法, 从一系列的点创建一条平滑的三维曲线

CatmullRomCurve3创建一个三维曲线,并将曲线闭合curve.closed = true;。通过LineLoop创建一条线,线的形状是三维曲线,线的材质是蓝色基础线条材质。

const curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3(1, 0, -1),
  new THREE.Vector3(1, 0, 1),
  new THREE.Vector3(-1, 0, 1),
  new THREE.Vector3(-1, 0, -1),
]);
curve.curveType = "centripetal"; // 曲线的类型
curve.closed = true; // 曲线是否闭合
const points = curve.getPoints(50); // 获取点列表,50为要将曲线划分为的分段数
const line = new THREE.LineLoop(
  new THREE.BufferGeometry().setFromPoints(points),
  new THREE.LineBasicMaterial({ color: 0x0000ff })
); // 一条头尾相接的连续的线(参数说明:顶点列表,材质)
scene.add(line); // 将曲线添加到场景中
  1. 创建立方体,并且使用Flow

创建一个红色基础网格材质的立方体,该立方体就是我们要移动的物体,通过flow.updateCurve(0, curve);确定要围绕的曲线

let redMesh = new THREE.Mesh(
  new THREE.BoxGeometry(0.1, 0.1, 0.1),
  new THREE.MeshBasicMaterial({ color: 0xff0000 })
); // 网格模型
flow = new Flow(redMesh); // 参数说明:(要克隆和修改以围绕曲线弯曲的网格模型)
flow.updateCurve(0, curve); // 参数说明:(索引,围绕的曲线)
scene.add(flow.object3D);
  1. 添加鼠标落下监听事件document.addEventListener("pointerdown", onPointerDown);
  2. 创建渲染器

创建渲染器并将渲染器插入到dom节点中

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比
renderer.setSize(window.innerWidth - 201, window.innerHeight); // 考虑像素比重新调整画面大小
document.getElementById("THREE42").appendChild(renderer.domElement); // 将渲染器插入到html中

写在最后

以上就是所有的代码和说明,关键是Flow的使用方法。