基于three.js的三维空间曲线轨迹运动

引言

我们在做项目的时候,有时候会遇到物体或者相机需要做复杂轨迹运动的情况,往往没法简单的通过修改位置来达成我们想要的运动效果。
这时候可以通过引入多段曲线去拟合我们想要的运动轨迹,再获取曲线的参数去控制物体做相应轨迹的运动。

目录

1、创建关键空间点数组
2、根据点数组绘制曲线
3、获取曲线上特定位置的点,修改物体位置
4、获取曲线上特定位置的切线,修改物体朝向
5、随时间实时改变物体位置和朝向
6、添加修改曲线功能
7、引入模型模拟应用场景
1、创建关键空间点数组
首先我们可以先找出运动轨迹上几个特定的点。
假设给定的点是(1,1,-1),(1,0,1),(-1,0,1),(-1,0,-1)
这里在每个点放了一个实体方块用于示意点的位置,同时为后面的调整功能做准备

 const initialPoints = [
     { x: 1, y: 1, z: -1 },
     { x: 1, y: 0, z: 1 },
     { x: -1, y: 0, z: 1 },
     { x: -1, y: 0, z: -1 }
 ];

 const addCube = (pos) => {
     const geometry = new THREE.BoxBufferGeometry(0.1, 0.1, 0.1);
     const material = new THREE.MeshBasicMaterial(0xffffff);
     const cube = new THREE.Mesh(geometry, material);
     cube.position.copy(pos);
     scene.add(cube);
 }

 const cubeList = initialPoints.map(pos => {
     return this.addCube(pos);
 });

在这里插入图片描述
2、根据点数组绘制曲线
three.js 提供了好几种方法绘制曲线,这里采用的是 CatmullRom 插值的方法绘制曲线。

CatmullRom 插值的曲线一定会经过所有给定的点,所以这种方法会更适合用作轨迹曲线的绘制。

 const curve = new THREE.CatmullRomCurve3(
      cubeList.map((cube) => cube.position) // 直接绑定方块的position以便后续用方块调整曲线
  );
  curve.curveType = 'chordal'; // 曲线类型
  curve.closed = true; // 曲线是否闭合

  const points = curve.getPoints(50); // 50等分获取曲线点数组
  const line = new THREE.LineLoop(
      new THREE.BufferGeometry().setFromPoints(points),
      new THREE.LineBasicMaterial({ color: 0x00ff00 })
  ); // 绘制实体线条,仅用于示意曲线,后面的向量线条同理,相关代码就省略了

  scene.add(line);

在这里插入图片描述
3、获取曲线上特定位置的点,修改物体位置
有了曲线之后,可以通过 getPointAt 函数获取曲线上特定位置的点向量,然后复制给物体的 position

   function changePosition (t) {
       const position = curve.getPointAt(t); // t: 当前点在线条上的位置百分比,后面计算
       mesh.position.copy(position);
   }

为了直观表现下图采用 30 等分取点把位置向量绘制出来了,后面的图片也采用一样的方式展现向量

4、获取曲线上特定位置的切线,修改物体朝向
现在物体的位置对上了,但是朝向却是固定的,不符合生活经验。一般来说物体在运动的时候,正面总是朝向轨迹的切线方向的。

现在我们通过 getTangentAt 函数获取曲线上特定位置的切线向量,根据该切线向量和点的位置向量计算物体朝向的点向量,传入物体的 lookAt 函数

  function changeLookAt (t) {
      const tangent = curve.getTangentAt(t);
      const lookAtVec = tangent.add(position); // 位置向量和切线向量相加即为所需朝向的点向量
      mesh.lookAt(lookAtVec);
  }

在这里插入图片描述
注意上图示的切线(黄线)实际起点为原点(0,0,0),这里为了示意切线在曲线上的位置,平移到了点所在位置上
在这里插入图片描述
因为 lookAt 实际上是指向某个点向量,如果直接传切线向量会导致物体朝向下图 A 点,需要和位置向量相加后才能得到所需的点向量(蓝线)即 C 点
5、随时间实时改变物体位置和朝向
现在轨迹上单一点的位置和朝向都可以获取到了,剩下的就是在渲染函数中实时修改了。

根据时间计算当前点在曲线上的位置百分比,传入第 3、4 步中

 const loopTime = 10 * 1000; // loopTime: 循环一圈的时间

  // 在渲染函数中获取当前时间
  const render = () => {
      let time = Date.now();
      let t = (time % loopTime) / loopTime; // 计算当前时间进度百分比

      changePosition(t);
      changeLookAt(t);

      requestAnimationFrame(render);
      renderer.render(scene, camera);
  }

  requestAnimationFrame(render);

作者:DigitMagic魔数实验室
链接:https://www.jianshu.com/p/cb7ae00701cd
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值