ThreeJS —— 机房Demo(二)

Three世界中的物体都是大部分都是由一个个几何体Geometry构成的,上一节我们在场景中加入了一些几何体模拟机器,并渲染出来了画面,这一节我们将加入一些新的几何体,来模拟线路等

目录结构

├── font // 字体文件
 |├──── font.ttf // 字体源文件
 |└──── font.json // 转换后的字体文件
├── img // 素材图片
 |├──── xx.png
 |├──── xxx.jpg
 |└──── …
├── js // 自己编写的js文件
 |├──── composer_fn.js // 后期处理
 |├──── create_fn.js // 创建各种几何
 |├──── init_fn.js // 初始化项目
 |└──── util_fn.js // 工具函数
├── lib // 需要引入的js文件
 |├──── three.js
 |├──── OrbitControls.js
 |├──── RenderPass.js
 |└──── …
├── model // 建模工具导出的模型
 |├──── computer.gltf
 |└──── …
└── index.html // 入口文件

模拟一条管线

机房中必不可少的当然是一条条类似管道的线路了,里面在不停的传输着数据源,那么这次我们将模拟出一条管线来

创建TubeGeometry几何体

首先我们利用TubeGeometry创建一条管道,第一个参数传入自定义好的路径

// create_fn.js
// 传入一组三维坐标点,例如:([-15, -5, 15], [-15, -5, -40], [40, -5, -40]),按照这组点形成一条路径,在此路径基础上创建管道
function createTube(...pointsArr) {
   
  const path = createPath(pointsArr); // createPath是我们编写的创建路径的函数,详细如下
  const geometry = new THREE.TubeGeometry(path, 64, 0.3); // 第一个参数为路径,必须为Curve类,第二个参数为分段值(可理解为细粒度),第三个参数为管道横截面半径
  // curve是基类,表示曲线,子类有lineCurve二维直线,lineCurve3三维直线
  // curvePath是一组curve构成的路径,可以算是curve的子类,curvePath的子类path二维路径,shape是path的子类,所以第一个参数可以传入curvePath
  const material = new THREE.MeshBasicMaterial({
    color: "#00ffff" });
  const mesh = new THREE.Mesh(geometry, material);
  return mesh;
}

// 创建一条路径,可以是三维或二维路径,传入一组点,例如:[[-15, -5, 15], [-15, -5, -40], [40, -5, -40]]
function createPath(pointsArr) {
   
  pointsArr = pointsArr.map((point) => new THREE.Vector3(...point)); // 将参数数组转换成点数组的形式

  // 方法一:自定义三维路径 curvePath
  const path = new THREE.CurvePath();
  for (let i = 0; i < pointsArr.length - 1; i++) {
   
    const lineCurve = new THREE.LineCurve3(pointsArr[i], pointsArr[i + 1]); // 每两个点之间形成一条三维直线
    path.curves.push(lineCurve); // curvePath有一个curves属性,里面存放组成该三维路径的各个子路径
  }
  // 方法二:利用CatmullRomCurve3创建三维路径,不过CatmullRomCurve3是平滑的三维样条曲线
  // const path = new THREE.CatmullRomCurve3(pointsArr);

  return path;
}

效果图:
管线一
到这里,管道已经创建完毕了,不过只有一条管道并不能很好的模拟除管线的效果,因为缺少了很重要的一个元素——“动画”

为管线添加动画

管道实现动画原理:

  1. 对管道进行贴图,图片由两种相近的颜色组成,较亮的颜色可以模拟正在传输的数据元
    运动的管线
  2. 在animate动画中,动态的改变贴图的偏移量offset,产生运动效果

运动素材贴图 tube.jpg :
运动素材贴图
创建管线:

// create_fn.js
async function createTube(...pointsArr) {
   
  const path = createPath(pointsArr);
  const geometry = new THREE.TubeGeometry(path, 64, 0.3);

  // 模拟管线运动动画的贴图texture
  const texture = new THREE.TextureLoader().load('../img/tube.jpg');
  texture.wrapS = THREE.RepeatWrapping; // 设置x方向能够重复,这样才可以设置texture的偏移量offset
  texture.repeat.x = 1; // 设置x方向的重复数为1,也可设置为2,这样产生的动画效果代表管道内同时有两端数据元在传输
  
  const material = new THREE.MeshBasicMaterial({
   
    map: texture,
    transparent: true,
  });
  const mesh = new THREE.Mesh(geometry, material);
  return {
    texture, mesh };
}

给管线添加动画:

<!DOCTYPE html>
<html>
  <head>...</head>
  <body>
    <div id="canvas-frame"></div>
    
	<!-- 引入的一些JS -->
    <script src="lib/three.js"></script>
    <script src="..."></script> 
    
    <script>
      // ...
      
      // 新添加的代码
      const {
     texture, mesh } = await createTube([-15, -5, 15], [-15, -5, -40], [40, -5, -40]); // 获取到管线mesh,以及管线贴图texture
      scene.add(mesh); // 将管线添加到场景中

      function animate(time) {
    
         // ...
         
         texture.offset.x -= 0.022; // 每次让贴图的x偏移量减少0.022,以产生动画效果
         renderer.render(scene, camera);
         requestAnimationFrame(animate);
       }
       animate();
    </script>
  </body>
</html>

自定义管线运动部分的长度

上面虽然实现了管线的动画效果,但是由于贴图素材中,运动部分和不运动部分的比例是固定的,导致如果管线很长的话,运动部分所占的长度也会相应变长,影响美观(例如:运动部分和不运动部分原本比例1:4,如果是10m长的管道,那么运动部分占了2m,但如果是100m长的管道,则运动部分就占了20m,显然过长),所以需要自定义运动部分所占的比例

实现原理:

  1. 首先准备两张长宽相同的素材图片,一张用作运动部分,一张用作不运动部分
  2. 根据传入的比例,在canvas中将两张图片按照比例合并成一张图片
  3. 将合成后的图片作为管线的贴图

首先我们提前准备好一个函数 mergeImage,用来将两张图片按比例合并成为一张

// util_fn.js
function mergeImage(imgSrc1, imgSrc2, a, b) {
   
  return new Promise((res, rej) => {
   
    const canvas = document.createElement("canvas"); // 创建canvas
    const ctx = canvas.getContext
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值