既有方向又会动的线,包你学会制作按箭头方向流动的线(three.js实战3)

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了既有方向又会动的线,包你学会制作按箭头方向流动的线(three.js实战3)相关的知识,希望对你有一定的参考价值。

1.demo效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. 实现思路

实现思路比较简单,使用纹理材质创建网格对象,然后在render函数中改变纹理的偏移量(texture.offset.x),实现流动的效果

3. 实现要点

3.1 创建箭头流动线

  • 创建长条状平面
    使用THREE.PlaneGeometry类创建一个长条状平面,用来填充箭头纹理

  • 创建纹理材质
    使用TextureLoader纹理加载器加载纹理,然后需要设置水平方向重复10次,用该纹理作为map属性创建MeshBasicMaterial材质,同时将材质的side属性设置为THREE.DoubleSide,这样正反面都可以看到效果

  • 创建网格对象
    使用上面创建的几何体和材质使用THREE.Mesh直接创建网格对象并添加到场景中

示例代码如下

//创建条形平面-箭头流动的路径
const geometry = new THREE.PlaneGeometry(20, 2, 32);

//加载纹理
arrowLineTexture = new THREE.TextureLoader().load('../assets/textures/right.png');
arrowLineTexture.wrapS = arrowLineTexture.wrapT = THREE.RepeatWrapping; //每个都重复
arrowLineTexture.repeat.set(10, 1); //水平重复10次
arrowLineTexture.needsUpdate = true;

// 加载的纹理作为纹理贴图创建材质
let materials = new THREE.MeshBasicMaterial({
  map: arrowLineTexture,
  side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);

3.2 创建流动线

  • 创建线条
    使用THREE.CatmullRomCurve3类创建一个线条路径,然后用该路径创建一个管道几何体

  • 创建纹理材质
    使用TextureLoader纹理加载器加载纹理,这次设置水平方向重复20次,使用纹理作为map属性创建MeshBasicMaterial材质,同时将材质的side属性设置为THREE.BackSide,transparent属性设置为true

  • 创建网格对象
    使用上面创建的几何体和材质使用THREE.Mesh直接创建网格对象并添加到场景中

// 创建线条路径
let curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3(0, 0, 10),
  new THREE.Vector3(10, 0, 10),
  new THREE.Vector3(10, 0, 0),
  new THREE.Vector3(20, 0, -10)
]);

//依据线条路径创建管道几何体
let tubeGeometry = new THREE.TubeGeometry(curve, 80, 0.2);
//加载纹理
flowingLineTexture = new THREE.TextureLoader().load('../assets/textures/roadflowing1.png')

flowingLineTexture.wrapS = THREE.RepeatWrapping;
flowingLineTexture.wrapT = THREE.RepeatWrapping;
flowingLineTexture.repeat.set(20, 1); //水平重复20次
flowingLineTexture.needsUpdate = true;

//创建纹理贴图材质
let material = new THREE.MeshBasicMaterial({
  map: flowingLineTexture,
  side: THREE.BackSide, //显示背面
  transparent: true
});

let mesh = new THREE.Mesh(tubeGeometry, material);
mesh.position.z = 10;
scene.add(mesh);

3.3 更新纹理偏移

在render函数中更新纹理偏移,有了这一步,线条就可以动起来

arrowLineTexture.offset.x -= 0.03; //更新箭头纹理偏移量
flowingLineTexture.offset.x -= 0.05; //更新流动线纹理偏移量

4. demo代码

<!DOCTYPE html>

<html>

<head>
  <title>流动的方向线</title>
  <script type="text/javascript" src="../three/build/three.js"></script>
  <script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
  <script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>

  <div id="Stats-output"></div>
  <div id="WebGL-output"></div>

  <script type="text/javascript">
    var scene, camera, renderer, arrowLineTexture, flowingLineTexture, stats, controls, clock;

    function initScene() {
      scene = new THREE.Scene();
      //用一张图加载为纹理作为场景背景
      scene.background = new THREE.TextureLoader().load("../assets/textures/starry-deep-outer-space-galaxy.jpg");
    }

    function initCamera() {
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(20, 30, 50);
      camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initLight() {
      //添加环境光
      const ambientLight = new THREE.AmbientLight(0x0c0c0c);
      scene.add(ambientLight);

      const directionalLight = new THREE.DirectionalLight('#fff')
      directionalLight.position.set(30, 30, 30).normalize()
      scene.add(directionalLight)

      //添加聚光灯
      const spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(-40, 60, -10);
      spotLight.castShadow = true;
      scene.add(spotLight);
    }

    function initModel() {

      initArrowLine()
      initFlowingLine();
      initPlane();

    }

    function initArrowLine() {
      //创建条形平面-箭头流动的路径
      const geometry = new THREE.PlaneGeometry(20, 2, 32);

      //加载纹理
      arrowLineTexture = new THREE.TextureLoader().load('../assets/textures/right.png');
      arrowLineTexture.wrapS = arrowLineTexture.wrapT = THREE.RepeatWrapping; //每个都重复
      arrowLineTexture.repeat.set(10, 1); //水平重复10次
      arrowLineTexture.needsUpdate = true;

      // 加载的纹理作为纹理贴图创建材质
      let materials = new THREE.MeshBasicMaterial({
        map: arrowLineTexture,
        side: THREE.DoubleSide
      });
      const mesh = new THREE.Mesh(geometry, materials);
      scene.add(mesh);
    }

    function initFlowingLine() {
      //加载纹理
      flowingLineTexture = new THREE.TextureLoader().load('../assets/textures/roadflowing1.png')

      flowingLineTexture.wrapS = THREE.RepeatWrapping;
      flowingLineTexture.wrapT = THREE.RepeatWrapping;
      flowingLineTexture.repeat.set(20, 1); //水平重复20次
      flowingLineTexture.needsUpdate = true;

      //创建纹理贴图材质
      let material = new THREE.MeshBasicMaterial({
        map: flowingLineTexture,
        side: THREE.BackSide, //显示背面
        transparent: true
      });

      // 创建线条路径
      let curve = new THREE.CatmullRomCurve3([
        new THREE.Vector3(0, 0, 10),
        new THREE.Vector3(10, 0, 10),
        new THREE.Vector3(10, 0, 0),
        new THREE.Vector3(20, 0, -10)
      ]);

      //依据线条路径创建管道几何体
      let tubeGeometry = new THREE.TubeGeometry(curve, 80, 0.2);
      let mesh = new THREE.Mesh(tubeGeometry, material);
      mesh.position.z = 10;
      scene.add(mesh);
    }

    //创建底面
    function initPlane() {
      const planeGeometry = new THREE.PlaneGeometry(50, 50, 1, 1); //创建一个平面几何对象

      //材质
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: 0x080631,
        transparent: true,
        opacity: 0.8
      });
      const plane = new THREE.Mesh(planeGeometry, planeMaterial);

      //设置平面位置
      plane.rotation.x = -0.5 * Math.PI;
      plane.position.set(0, -2, 0);

      //平面添加到场景中
      scene.add(plane);
    }

    //初始化渲染器
    function initRender() {
      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      renderer.setClearColor(0x111111, 1); //设置背景颜色
      renderer.setSize(window.innerWidth, window.innerHeight);
      //renderer.shadowMap.enabled = true; //显示阴影
      document.getElementById("WebGL-output").appendChild(renderer.domElement);
    }
    //初始化轨道控制器
    function initControls() {
      clock = new THREE.Clock(); //创建THREE.Clock对象,用于计算上次调用经过的时间
      controls = new THREE.OrbitControls(camera, renderer.domElement);
      controls.autoRotate = true; //是否自动旋转
    }


    //性能监控
    function initStats() {
      stats = new Stats();
      stats.setMode(0); //0: fps, 1: ms
      document.getElementById("Stats-output").appendChild(stats.domElement);
    }

    function render() {

      arrowLineTexture.offset.x -= 0.03; //更新箭头纹理偏移量
      flowingLineTexture.offset.x -= 0.05; //更新流动线纹理偏移量

      const delta = clock.getDelta(); //获取自上次调用的时间差
      controls.update(delta); //控制器更新
      stats.update();
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }

    //页面初始化
    function init() {
      initScene();
      initCamera();
      initLight();
      initModel();
      initRender();
      initStats();
      initControls();
      render();
    }

    window.onload = init;
  </script>
</body>

</html>

以上是关于既有方向又会动的线,包你学会制作按箭头方向流动的线(three.js实战3)的主要内容,如果未能解决你的问题,请参考以下文章

流程图中的带箭头的线段代表啥?

arcgis怎么反转箭头

动画在没有画布的 2 个元素之间绘制的线,通过 ID 链接

auto cad 画大尺寸的图怎么画?

如何利用百度地图JSAPI画带箭头的线

如何做会动的GIF图片?