three.js动画之模型沿着执行路线运动(tween.js)

1,059 阅读1分钟

需求描述: 模型沿着指定的路线运动,展示如下:

image.png

1.html部分

<div class="import_model"></div>

2.js部分

3.导入

    <script type="text/javascript" src="libs/Tween.min.js"></script>
    <script type="text/javascript" src="libs/three.js"></script>
    <script type="text/javascript" src="libs/OrbitControls.js"></script>
 

2.声明变量,初始化

let scene, mesh, camera, renderer, axesHelper, grid, controls, line;
    let group = new THREE.Group();
    let pointArr = [
      0, 0, -150, 100, 0, -150, 100, 0, -50, 0, 0, -50, 0, 0, 50, 100, 0, 50,
      100, 0, 150, 0, 0, 150,
    ];
    var width = window.innerWidth; //窗口宽度
    var height = window.innerHeight; //窗口高度
    init();
    function init() {
      // 创建场景
      createScene();
      // 创建光源
      createLight();
      // 创建相机
      createCamera(width, height);
      // 旋转场景动画
      createCameraAnimation();
      // 创建渲染器
      createRender();
      // 创建控制器
      createControls();
      createGrid();
      createAxesHelper();
      // 以下为场景内东西
      // 描绘运动路径
      createPath();
      // 创建Box
      createBox();
      // 路径运动
      pathFollowRun();
      // 渲染
      render();
    }

3.创建Box

    function createBox() {
      // 矩形
      var geometry = new THREE.BoxGeometry(20, 20, 20);
      var material = new THREE.MeshLambertMaterial({
        color: 0x009999,
        transparent: true, //开启透明度
        opacity: 1, //设置透明度
      });

      mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    }

4.创建路径

 function createPath() {
      // 矩形
      const geometry = new THREE.BufferGeometry();
      // 创建属性缓冲区对象
      var attribute = new THREE.BufferAttribute(new Float32Array(pointArr), 3);
      // 设置几何体的attributes属性的位置属性
      geometry.attributes.position = attribute;
      const material = new THREE.LineBasicMaterial({
        color: 0x009999,
      });
      line = new THREE.Line(geometry, material); //线条模型对象
      scene.add(line); //线条对象添加到场景中
    }

5.沿着路径运动

function pathFollowRun() {
      // mesh坐标
      var pos = { x: pointArr[0], y: pointArr[1], z: pointArr[2] };
      // 所有动画片段tween的集合
      var tweenArr = [];
      // 批量创建动画片段
      for (var i = 0; i < pointArr.length; i += 3) {
        var tween = new TWEEN.Tween(pos)
          .to({
            x: pointArr[i],
            y: pointArr[i + 1],
            z: pointArr[i + 2],
          })
          .onUpdate(() => {
            mesh.position.x = pos.x;
            mesh.position.z = pos.z;
          });
        tweenArr.push(tween);
      }
      // 批量连接所有动画片段
      for (var i = 0; i < tweenArr.length - 1; i++) {
        tweenArr[i].chain(tweenArr[i + 1]);
      }
      tweenArr[0].start();
    }

6.以下为常规搭建场景【可多次复用】

    function createScene() {
      scene = new THREE.Scene();
    }  
    function createLight() {
      //点光源
      var point = new THREE.PointLight(0xffffff);
      point.position.set(400, 200, 300); //点光源位置
      scene.add(point); //点光源添加到场景中
      //环境光
      // var ambient = new THREE.AmbientLight(0x444444);
      var ambient = new THREE.AmbientLight("#ffffff", 1);
      scene.add(ambient);
    }
    function createCamera(width, height) {
      var k = width / height; //窗口宽高比
      var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
      // //创建相机对象
      // 正交相机
      // camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
      // 透视相机(此处需要全景和透视)
      camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        20000
      );
      // camera.position.set(200, 300, 200); //设置相机位置
      camera.position.set(0, 300, 200); //设置相机位置
      camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
    }
    // 创建相机动画
    function createCameraAnimation() {
      var obj = {
        x: 0,
        y: 200,
        z: 300,
      };
      let tween = new TWEEN.Tween(obj);
      tween.to(
        {
          x: 400,
          y: 200,
          z: 300,
        },
        5000
      );
      tween.onUpdate(function () {
        // 动态更新相机位置
        camera.position.set(obj.x, obj.y, obj.z); //设置相机位置
        camera.lookAt(0, 0, 0); //保持相机目标观察点不变
      });
      tween.start(); //tween动画开始执行
    }
    function createRender() {
      renderer = new THREE.WebGLRenderer();
      renderer.setSize(width, height); //设置渲染区域尺寸
      // renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
      // renderer.setClearColor(0xffffff, 1); //设置背景颜色
      renderer.outputEncoding = THREE.sRGBEncoding; // 模型颜色偏差
      renderer.shadowMap.enabled = true; //开启渲染气阴影效果。
      document.querySelector(".import_model").appendChild(renderer.domElement);
    }
    function createControls() {
      //创建控件对象  相机对象camera作为参数   控件可以监听鼠标的变化,改变相机对象的属性
      controls = new THREE.OrbitControls(camera);
      //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
      controls.addEventListener("change", () => {
        renderer.render(scene, camera);
      });
    }
    function createGrid() {
      grid = new THREE.GridHelper(600, 15, 0xffffff, 0xffffff);
      grid.material.opacity = 0.2;
      grid.material.depthWrite = false;
      grid.material.transparent = true;
      scene.add(grid);
    }
    function createAxesHelper() {
      axesHelper = new THREE.AxesHelper(250);
      scene.add(axesHelper);
    }
    function render() {
      controls.update();
      TWEEN.update(); //更新TWEEN
      requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
      renderer.render(scene, camera); //执行渲染操作
    }