zoukankan      html  css  js  c++  java
  • maptalks 开发GIS地图(9)maptalks.three.02 animation

    1. 说明: 本demo主要是加载了一个具有动画效果的三维机器人,然后通过鼠标选择菜单控制机器人的动作和表情。

      其实这个机器人,本身就已经具有动画和动作表情效果了,只不过是使用threejs的接口,把它加载到地图上,

      然后再调用API操控机器人。

    2. 先来看一下  ../threelayer/demo/data/RobotExpressive.glb 这个文件。通过Windows10下面自带的 3D查看器软件打开。

        这是一个glb文件,通过3dmax软件导出后,已经具有了动画效果。而且还包括了多种动画效果。

    3. 新建一个 maptalks 地图

    关于maptalks 地图的功能,这里就不多讲了,可以参考前面的文章。

     1         var map = new maptalks.Map("map", {
     2             center: [19.06325670775459, 42.16842479475318],
     3             zoom: 9,
     4             pitch: 60,
     5             // bearing: 180,
     6 
     7             centerCross: true,
     8             doubleClickZoom: false,
     9             baseLayer: new maptalks.TileLayer('tile', {
    10                 urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
    11                 subdomains: ['a', 'b', 'c', 'd'],
    12                 attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
    13             })
    14         });

    4. 新建一个 ThreeLayer 图层,并设置三维三要素,光源、场景、镜头。

     1  // the ThreeLayer to draw buildings
     2         var threeLayer = new maptalks.ThreeLayer('t', {
     3             forceRenderOnMoving: true,
     4             forceRenderOnRotating: true
     5             // animation: true
     6         });
     7         threeLayer.prepareToDraw = function (gl, scene, camera) {
     8             var light = new THREE.DirectionalLight(0xffffff);
     9             light.position.set(0, -10, 10).normalize();
    10             scene.add(light);
    11             camera.add(new THREE.PointLight('#fff', 4));
    12 
    13             addGltf();
    14 
    15         };
    16         threeLayer.addTo(map);

    5. 添加三维模型对象

    这里使用了 THREE.GLTFLoader 对象,此函数包含在 GLTFLoader.js 中,需要调用前添加引用。

    其中 model 对象是获取了三维模型中的场景,然后将三维模型进行旋转45°  model.rotation , 模型比例设为 1:1 , scale.set , 模型的位置设在地图中心点。

    使用 addMesh 添加三维模型到对应的threeLayer 图层,完成了三维模型对象在地图上的添加。

     1   function addGltf() {
     2             clock = new THREE.Clock();
     3             stats = new Stats();
     4             map.getContainer().appendChild(stats.dom);
     5             var loader = new THREE.GLTFLoader();
     6             loader.load('./data/RobotExpressive.glb', function (gltf) {
     7 
     8                 model = gltf.scene;
     9                 model.rotation.x = Math.PI / 2;
    10                 model.scale.set(100, 100, 100);
    11                 model.position.copy(threeLayer.coordinateToVector3(map.getCenter()));
    12                 threeLayer.addMesh(model);
    13 
    14                 createGUI(model, gltf.animations);
    15                 animate();
    16 
    17             }, undefined, function (e) {
    18 
    19                 console.error(e);
    20 
    21             });
    22         }

    6. 创建GUI用以控制机器人

    这就是前面那篇文章说的使用了 dat.gui.min.js 中相关的内容。

     1 function createGUI(model, animations) {
     2 
     3             var states = ['Idle', 'Walking', 'Running', 'Dance', 'Death', 'Sitting', 'Standing'];
     4             var emotes = ['Jump', 'Yes', 'No', 'Wave', 'Punch', 'ThumbsUp'];
     5 
     6             gui = new dat.GUI();
     7 
     8             mixer = new THREE.AnimationMixer(model);
     9 
    10             actions = {};
    11 
    12             for (var i = 0; i < animations.length; i++) {
    13 
    14                 var clip = animations[i];
    15                 var action = mixer.clipAction(clip);
    16                 actions[clip.name] = action;
    17 
    18                 if (emotes.indexOf(clip.name) >= 0 || states.indexOf(clip.name) >= 4) {
    19 
    20                     action.clampWhenFinished = true;
    21                     action.loop = THREE.LoopOnce;
    22 
    23                 }
    24 
    25             }
    26 
    27             // states
    28 
    29             var statesFolder = gui.addFolder('States');
    30 
    31             var clipCtrl = statesFolder.add(api, 'state').options(states);
    32 
    33             clipCtrl.onChange(function () {
    34 
    35                 fadeToAction(api.state, 0.5);
    36 
    37             });
    38 
    39             statesFolder.open();
    40 
    41             // emotes
    42 
    43             var emoteFolder = gui.addFolder('Emotes');
    44 
    45             function createEmoteCallback(name) {
    46 
    47                 api[name] = function () {
    48 
    49                     fadeToAction(name, 0.2);
    50 
    51                     mixer.addEventListener('finished', restoreState);
    52 
    53                 };
    54 
    55                 emoteFolder.add(api, name);
    56 
    57             }
    58 
    59             function restoreState() {
    60 
    61                 mixer.removeEventListener('finished', restoreState);
    62 
    63                 fadeToAction(api.state, 0.2);
    64 
    65             }
    66 
    67             for (var i = 0; i < emotes.length; i++) {
    68 
    69                 createEmoteCallback(emotes[i]);
    70 
    71             }
    72 
    73             emoteFolder.open();
    74 
    75             // expressions
    76 
    77             face = model.getObjectByName('Head_2');
    78 
    79             var expressions = Object.keys(face.morphTargetDictionary);
    80             var expressionFolder = gui.addFolder('Expressions');
    81 
    82             for (var i = 0; i < expressions.length; i++) {
    83 
    84                 expressionFolder.add(face.morphTargetInfluences, i, 0, 1, 0.01).name(expressions[i]);
    85 
    86             }
    87 
    88             activeAction = actions['Walking'];
    89             activeAction.play();
    90 
    91             expressionFolder.open();
    92 
    93         }

    7. 重新绘制webgl的状态,满足动画更新需要。

     1         function animate() {
     2             var dt = clock.getDelta();
     3             if (mixer) mixer.update(dt);
     4             requestAnimationFrame(animate);
     5             stats.update();
     6             // threeLayer._needsUpdate = !threeLayer._needsUpdate;
     7             if (threeLayer._needsUpdate) {
     8                 threeLayer.renderScene();
     9             }
    10 
    11         }

    8. 在 maptalks 地图中的效果。

    9.  源码地址

    https://github.com/WhatGIS/maptalkMap/tree/main/threelayer/demo

  • 相关阅读:
    hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径
    Python 之 安装模块的多种方法
    开源项目Universal Image Loader for Android 说明文档 (1) 简单介绍
    IDEA下使用Jetty进行Debug模式调试
    离线安装Cloudera Manager5.3.4与CDH5.3.4(一)
    让你提前认识软件开发(38):完毕第一个新需求
    Windows App开发之经常使用控件与应用栏
    【剑指Offer学习】【面试题58:二叉树的下一个结点】
    【Win】编写简单的bat文件
    【Linux】MySQL解压版安装及允许远程访问
  • 原文地址:https://www.cnblogs.com/googlegis/p/14721778.html
Copyright © 2011-2022 走看看