Threejs加载城市obj模型,加载人物gltf模型,Tweenjs实现人物根据规划的路线运动

简介: Threejs加载城市obj模型,加载人物gltf模型,Tweenjs实现人物根据规划的路线运动

1,介绍:


该示例使用的是 r95版本Three.js库。在上一个案例(文章首页可查找)基础上添加城市模型(obj格式),添加人物模型(gltf格式),初始化运动路线,这里使用了Tween.js实现的动画,人物模型按照路线进行运动。添加坐标轴。效果图如下:


2,主要说明


Three.js加载模型文件,并从中导入几何体。Three.js所支持的模型文件格式:json、obj/mtl、dae、ply、gltf、glb、svg、pbd...,这里说的都是扩展名,还有好多种这里不列举了。如果想加载bim模型如:ifc和rvt格式,则需要进行转换成Three所支持的格式,可以使用blender软件进行转换,具体教程百度。


添加城市模型obj/mtl格式,obj/mtl是相互配合的两种格式,经常一起使用。obj文件定义几何体,而mtl文件定义所用的材质。obj和mtl都是基于文本的格式。代码如下:


// 添加模型
function initModel() {
  var mtlLoader = new THREE.MTLLoader();
  mtlLoader.setPath("assets/models/obj_mtl/")
  mtlLoader.load('city.mtl', function(materials) {
    materials.preload();
    var objLoader = new THREE.OBJLoader();
    objLoader.setMaterials(materials);
    objLoader.load('assets/models/obj_mtl/city.obj', function(object) {
      mesh = object;
      mesh.scale.set(3, 3, 3);
      mesh.position.set(18, 0, 18);
      scene.add(mesh);
    });
  });
}

添加人物模型gltf格式,该格式专用于存储3D场景和模型,其优势在于可以最小化文件尺寸,并且可以高效地加载模型。代码如下:

// 添加人物模型
function initPeople() {
  var loader = new THREE.GLTFLoader();
  loader.load('assets/models/CesiumMan/CesiumMan.gltf', function(result) {
    result.scene.scale.set(1, 1, 1);
    result.scene.translateY(0);
    aaa = result.scene;
    scene.add(result.scene);
    tweenComplete();
    mixer = new THREE.AnimationMixer(result.scene);
    animationClip = result.animations[0];
    clipAction = mixer.clipAction(animationClip).play();
    animationClip = clipAction.getClip();
  });
}


使用Tween.js实现的动画效果,通过Tween.js可以很容易地实现某个属性在两个值之间进行过渡,而且起始值和结束值之间的所有中间值都会自动计算出来,这个过程叫作tweening(补间)。

function tweenComplete() {
  if (i < points.length) {
    switch (i) {
      case 0:
        pobj.rotateY(Math.PI);
        break;
      case 1:
      case 5:
      case 8:
      case 9:
        pobj.rotateY(-0.5 * Math.PI);
        break;
      case 2:
      case 3:
      case 4:
      case 6:
      case 7:
        pobj.rotateY(0.5 * Math.PI);
        break;
      case 10:
        mixer.stopAllAction();
        break;
    }
    tween = new TWEEN.Tween(points[i])
      .to(points[i + 1], 3000)
      .easing(TWEEN.Easing.Linear.None)
      .onUpdate(function() {
        pobj.position.set(this.x, this.y, this.z);
      })
      .onComplete(tweenComplete)
      .start();
    i++;
  }
}


3,源码如下:


<!DOCTYPE html>
<html>
  <head>
    <title>Threejs加载城市obj模型,加载人物gltf模型,人物根据规划的路线运动</title>
    <script type="text/javascript" src="libs/three.js"></script>
    <script type="text/javascript" src="libs/OrbitControls.js"></script>
    <script type="text/javascript" charset="UTF-8" src="libs/other/Tween.min.js"></script>
    <script type="text/javascript" charset="UTF-8" src="libs/three/loaders/GLTFLoader.js"></script>
    <script type="text/javascript" src="libs/OBJLoader.js"></script>
    <script type="text/javascript" src="libs/MTLLoader.js"></script>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div id="dom"></div>
    <script type="text/javascript">
      var camera;
      var renderer;
      var clock = new THREE.Clock();
      var mixer = new THREE.AnimationMixer();
      var clipAction
      var animationClip
      var pobj
      function init() {
        // 创建一个场景,它将包含我们所有的元素,如物体,相机和灯光。
        var scene = new THREE.Scene();
        var urls = [
          'assets/textures/cubemap/flowers/posx.jpg',
          'assets/textures/cubemap/flowers/negx.jpg',
          'assets/textures/cubemap/flowers/posy.jpg',
          'assets/textures/cubemap/flowers/negy.jpg',
          'assets/textures/cubemap/flowers/posz.jpg',
          'assets/textures/cubemap/flowers/negz.jpg'
        ];
        var cubeLoader = new THREE.CubeTextureLoader();
        scene.background = cubeLoader.load(urls);
        // 创建一个摄像机,它定义了我们正在看的地方
        camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 将摄像机对准场景的中心
        camera.position.x = 20;
        camera.position.y = 15;
        camera.position.z = 35;
        camera.lookAt(scene.position);
        var orbit = new THREE.OrbitControls(camera);
        // 创建一个渲染器并设置大小,WebGLRenderer将会使用电脑显卡来渲染场景
        // initialize basic renderer
        renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将平面添加到场景中
        var plane = createPlaneGeometryBasicMaterial();
        scene.add(plane);
        // 在屏幕上显示坐标轴
        var axes = new THREE.AxesHelper(100);
        scene.add(axes);
        // var trackballControls = initTrackballControls(camera, renderer);
        // 添加环境光
        scene.add(new THREE.AmbientLight(0x666666));
        scene.add(new THREE.AmbientLight("#ffffff", 1));
        // 将呈现器的输出添加到HTML元素
        document.getElementById("dom").appendChild(renderer.domElement);
        var points = initLine();
        // 将球体添加到场景中
        initModel();
        initPeople();
        // 启动动画
        renderScene();
        var i = 0;
        function tweenComplete() {
          if (i < points.length) {
            switch (i) {
              case 0:
                pobj.rotateY(Math.PI);
                break;
              case 1:
              case 5:
              case 8:
              case 9:
                pobj.rotateY(-0.5 * Math.PI);
                break;
              case 2:
              case 3:
              case 4:
              case 6:
              case 7:
                pobj.rotateY(0.5 * Math.PI);
                break;
              case 10:
                mixer.stopAllAction();
                break;
            }
            tween = new TWEEN.Tween(points[i])
              .to(points[i + 1], 3000)
              .easing(TWEEN.Easing.Linear.None)
              .onUpdate(function() {
                pobj.position.set(this.x, this.y, this.z);
              })
              .onComplete(tweenComplete)
              .start();
            i++;
          }
        }
        // 添加模型
        function initModel() {
          var mtlLoader = new THREE.MTLLoader();
          mtlLoader.setPath("assets/models/obj_mtl/")
          mtlLoader.load('city.mtl', function(materials) {
            materials.preload();
            var objLoader = new THREE.OBJLoader();
            objLoader.setMaterials(materials);
            objLoader.load('assets/models/obj_mtl/city.obj', function(object) {
              mesh = object;
              mesh.scale.set(3, 3, 3);
              mesh.position.y = -5;
              scene.add(mesh);
            });
          });
        }
        // 添加人物模型
        function initPeople() {
          var loader = new THREE.GLTFLoader();
          loader.load('assets/models/CesiumMan/CesiumMan.gltf', function(result) {
            result.scene.scale.set(1, 1, 1);
            result.scene.translateY(0);
            pobj = result.scene;
            scene.add(result.scene);
            tweenComplete();
            mixer = new THREE.AnimationMixer(result.scene);
            animationClip = result.animations[0];
            clipAction = mixer.clipAction(animationClip).play();
            animationClip = clipAction.getClip();
          });
        }
        // 创建一个平面
        function createPlaneGeometryBasicMaterial() {
          var textureLoader = new THREE.TextureLoader();
          var cubeMaterial = new THREE.MeshStandardMaterial({
            map: textureLoader.load("assets/textures/stone/cd.jpg"),
          });
          cubeMaterial.map.wrapS = THREE.RepeatWrapping;
          cubeMaterial.map.wrapT = THREE.RepeatWrapping;
          cubeMaterial.map.repeat.set(18, 18)
          // 创建地平面并设置大小
          var planeGeometry = new THREE.PlaneGeometry(500, 500);
          var plane = new THREE.Mesh(planeGeometry, cubeMaterial);
          // 设置平面位置并旋转
          plane.rotation.x = -0.5 * Math.PI;
          plane.position.x = 0;
          plane.position.y = -5;
          plane.position.z = 0;
          return plane;
        }
        // 初始化线路
        function initLine() {
          var pArr = [{
            x: 5 * 3,
            y: -3.8,
            z: -0.7 * 3
          }, {
            x: -0.6 * 3,
            y: -3.8,
            z: -0.7 * 3
          }, {
            x: -0.6 * 3,
            y: -3.8,
            z: -1.8 * 3
          }, {
            x: -4 * 3,
            y: -3.8,
            z: -1.8 * 3
          }, {
            x: -4 * 3,
            y: -3.8,
            z: 2.8 * 3
          }, {
            x: -1.2 * 3,
            y: -3.8,
            z: 2.8 * 3
          }, {
            x: -1.2 * 3,
            y: -3.8,
            z: 4.3 * 3
          }, {
            x: 1.7 * 3,
            y: -3.8,
            z: 4.3 * 3
          }, {
            x: 1.7 * 3,
            y: -3.8,
            z: -0.4 * 3
          }, {
            x: 4.4 * 3,
            y: -3.8,
            z: -0.4 * 3
          }, {
            x: 4.4 * 3,
            y: -3.8,
            z: 5 * 3
          }];
          var points = [];
          var geometry = new THREE.Geometry();
          for (var i = 0; i < pArr.length; i++) {
            var randomX = pArr[i].x;
            var randomY = pArr[i].y;
            var randomZ = pArr[i].z;
            var vector = new THREE.Vector3(randomX, randomY, randomZ);
            geometry.vertices.push(vector);
            points.push(vector);
          }
          var material = new THREE.LineBasicMaterial({
            color: 0xff0000
          });
          var line = new THREE.Line(geometry, material);
          scene.add(line);
          return points;
        }
        // 动画渲染
        var step = 5;
        function renderScene() {
          TWEEN.update();
          orbit.update();
          var delta = clock.getDelta();
          mixer.update(delta);
          // 使用requestAnimationFrame函数进行渲染
          requestAnimationFrame(renderScene);
          renderer.render(scene, camera);
        }
        // 渲染的场景
        renderer.render(scene, camera);
        document.addEventListener('mousedown', onDocumentMouseDown, false);
        function onDocumentMouseDown(event) {
          // 点击屏幕创建一个向量
          var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window
            .innerHeight) * 2 + 1, 0.5);
          vector = vector.unproject(camera); // 将屏幕的坐标转换成三维场景中的坐标
          var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
          var intersects = raycaster.intersectObjects(mesh.children, true);
          console.log(intersects)
          if (intersects.length > 0) {
            // intersects[0].object.material.color.set("#ffffff");
          }
        }
        // 创建一个球形几何体
        function createSphereGeometryLambertMaterial(point) {
          // 创建一个球体
          var sphereGeometry = new THREE.SphereGeometry(0.2, 20, 20);
          var sphereMaterial = new THREE.MeshBasicMaterial({
            color: 0x7777ff,
            wireframe: true
          });
          var sphereMaterial = new THREE.MeshLambertMaterial({
            color: 0xff0000
          });
          var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
          // 设置该物体投射阴影
          sphere.castShadow = true;
          // 位置范围
          sphere.position.x = point.x;
          sphere.position.y = point.y;
          sphere.position.z = point.z;
          return sphere;
        }
      }
      window.onload = init;
      function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }
      // 监听调整大小事件
      window.addEventListener('resize', onResize, false);
    </script>
  </body>
</html>
目录
相关文章
Threejs使用精灵Sprite作为标签,鼠标悬浮精灵上时鼠变小手
Threejs使用精灵Sprite作为标签,鼠标悬浮精灵上时鼠变小手
1962 0
Threejs使用精灵Sprite作为标签,鼠标悬浮精灵上时鼠变小手
Threejs实现相机视角切换,平滑过渡,点击模型切换到查看模型视角
Threejs实现相机视角切换,平滑过渡,点击模型切换到查看模型视角
2720 0
Threejs实现相机视角切换,平滑过渡,点击模型切换到查看模型视角
|
JavaScript 前端开发 Web App开发
带你读《Three. js开发指南: 基于WebGL和HTML5在网页上渲染 3D图形和动画(原书第3版)》之一:使用Three.js创建你的第一个三维场景
本书将介绍如何直在浏览器中创建漂亮的3D场景和动画,并且充分发挥WebGL和现代浏览器的潜能。首先介绍基本概念和基础组件,然后通过逐渐扩展示例代码逐步深讲解更多高级技术。在本书中读者将学到如何从外部加载3D模型和具有真实效果的材质纹理、学习使用Three.js提供的摄像机组件来实现在3D场景中飞行和走动、如何将HTML5视频和画布作为材质贴在3D模型表面。此外还将学习变形动画和骨骼动画,甚至还会涉及在场景中使用物理模拟的方法,例如重力、碰撞检测等等。
|
JavaScript
Threejs加载MMD
这篇文章详细介绍了如何在Three.js中加载和使用MMD(MikuMikuDance)模型,包括模型的导入、动画的播放以及与MMD相关的文件格式和操作流程。
574 2
Threejs加载MMD
|
开发框架
threejs做特效:实现物体的发光效果-EffectComposer详解!
【8月更文挑战第7天】实现物体的发光效果-EffectComposer详解!
2270 6
threejs做特效:实现物体的发光效果-EffectComposer详解!
|
API
【threejs教程】场景视角切换的神器:轨道控制器
【8月更文挑战第5天】threejs教程:场景视角切换的神器,轨道控制器
922 1
【threejs教程】场景视角切换的神器:轨道控制器
|
存储
Vue3组件通讯六种方式
【10月更文挑战第3天】
648 157
|
9月前
|
机器学习/深度学习 编解码 自然语言处理
王炸组合,阶跃星辰SOTA模型Step-Video和Step-Audio模型开源
王炸组合,阶跃星辰SOTA模型Step-Video和Step-Audio模型开源
352 0
|
数据可视化 定位技术
【threejs】可视化大屏酷炫3D地图附源码
【threejs】可视化大屏酷炫3D地图附源码
11126 131
【threejs】可视化大屏酷炫3D地图附源码
ThreeJs使用tweenjs动画库制作动画
这篇文章介绍了如何在Three.js中使用Tween.js动画库来简化动画制作流程,并演示了如何通过简单的代码实现动画效果。
378 1
ThreeJs使用tweenjs动画库制作动画