• Three 之 Animation 体验一


    Animation 体验一

    动画效果

    animation2

    其中涉及到 skeletion、clipAction、GUI

    Skeletion

    在建模软件中可导出 skeletion,这里安利一个可以创建动画的网站 https://www.mixamo.com/ ,以上模型均从该网站创建下载,注意,在下载时需要勾选 Skeletion

    mixamo

    加载好模型后,就可以使用 helper 方法创建骨架,并将其添加至场景中

    // 加载骨架,obj 为加载好后的模型
    skeletion = new THREE.SkeletonHelper(obj);
    // 设置可见性为 false
    skeletion.visible = false;
    // 添加到场景中
    scene.add(skeletion);
    

    clipAction

    使用 API 最好的方法是去官网搜索

    AnimationAction – three.js docs (threejs.org)

    首先获取到跳舞动作的 action

    clipAction = mixer.clipAction(obj.animations[0]);

    点击暂停播放按钮进行动作切换,动作切换的 api 十分简单

    // 如果动作正在进行就停止,否指播放
    if (clipAction.isRunning()) {
        clipAction.stop();
        } else {
        clipAction.play();
    }
    

    GUI

    import { GUI } from "three/examples/jsm/libs/dat.gui.module";

    该 UI 库能够绑定 js 中的变量和 UI 上显示的变量

    使用方法如下

    1. 创建相应面板
    const panel = new GUI({  200 });
    // domElement 可以获取到 dom 元素
    panel.domElement.style.marginTop = "10px";
    
    // 分别创建两个父文件夹并打开
    const folder1 = panel.addFolder("visibility");
    const folder2 = panel.addFolder("pause/continue");
    folder1.open();
    folder2.open();
    

    image-20211010142530196

    1. 绑定对象中的数据
    setting = {
        "show model": true,
        "show skeleton": false,
        "pause/continue": pauseContinue,
    };
    
    // folder.add() 第一个参数为对象,第二个参数为属性名,第三个参数代表发生变化时触发的回调函数
    
    // 使用 setting 中的 show model 属性,由于值时 Boolean 类型,因此回调函数的参数也是相同类型
    folder1.add(setting, "show model").onChange((visible) => {
        model.visible = visible;
    });
    // 直接绑定 skeletion 对象上的 visible 属性,界面上显示的就是 skeletion 对象上真实的 visible
    folder1.add(skeletion, "visible").onChange((visible) => {
        skeletion.visible = visible;
    });
    // 相当于添加了一个点击按钮,触发 pauseContinue 方法
    folder2.add(setting, "pause/continue");
    
    function pauseContinue() {
        if (clipAction.isRunning()) {
            clipAction.stop();
        } else {
            clipAction.play();
        }
    }
    

    源代码

    import React, { useEffect, useRef } from "react";
    import * as THREE from "three";
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
    import { GUI } from "three/examples/jsm/libs/dat.gui.module";
    import Stats from "three/examples/jsm/libs/stats.module";
    
    export function List2() {
      const content = useRef();
    
      // 场景
      const scene = new THREE.Scene();
      scene.background = new THREE.Color(0xa0a0a0);
      scene.fog = new THREE.Fog(0xa0a0a0, 10, 500);
      const pointLight = new THREE.PointLight(0xffffff, 0.6);
      pointLight.position.set(150, 150, 150);
      scene.add(pointLight);
      scene.add(new THREE.AmbientLight(0xffffff, 2));
    
      // 骨架
      let skeletion, model, clipAction;
      let setting;
    
      // 添加平面
      const mesh = new THREE.Mesh(
        new THREE.PlaneGeometry(1000, 1000),
        new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false })
      );
      mesh.rotation.x = -Math.PI / 2;
      mesh.receiveShadow = true;
      scene.add(mesh);
      const clock = new THREE.Clock();
    
      let mixer;
    
      useEffect(() => {
        const canvas = content.current;
        const renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(canvas.clientWidth, canvas.clientHeight);
    
        const stats = new Stats();
        canvas.appendChild(stats.dom);
    
        const camera = new THREE.PerspectiveCamera(
          40,
          canvas.clientWidth / canvas.clientHeight,
          1,
          1000
        );
        camera.position.set(200, 200, 200);
    
        const controls = new OrbitControls(camera, canvas);
        controls.update();
    
        const loader = new FBXLoader();
        loader.load("/RumbaDancing.fbx", (obj) => {
          scene.add(obj);
          model = obj;
    
          skeletion = new THREE.SkeletonHelper(obj);
          skeletion.visible = false;
          scene.add(skeletion);
    
          mixer = new THREE.AnimationMixer(obj);
          clipAction = mixer.clipAction(obj.animations[0]);
          clipAction.play();
    
          createPanel();
        });
    
        animate();
    
        function createPanel() {
          const panel = new GUI({  200 });
          panel.domElement.style.marginTop = "10px";
    
          const folder1 = panel.addFolder("visibility");
          const folder2 = panel.addFolder("pause/continue");
          folder1.open();
          folder2.open();
    
          setting = {
            "show model": true,
            "show skeleton": false,
            "pause/continue": pauseContinue,
          };
    
          folder1.add(setting, "show model").onChange((visible) => {
            model.visible = visible;
          });
          folder1.add(skeletion, "visible").onChange((visible) => {
            skeletion.visible = visible;
          });
          folder2.add(setting, "pause/continue");
    
          function pauseContinue() {
            if (clipAction.isRunning()) {
              clipAction.stop();
            } else {
              clipAction.play();
            }
          }
        }
    
        function animate() {
          requestAnimationFrame(animate);
    
          const delta = clock.getDelta();
    
          if (mixer) mixer.update(delta);
    
          controls.update();
    
          stats.update();
    
          renderer.render(scene, camera);
        }
      });
      return <canvas ref={content} />;
    }
    
    
    希望读者在看完后能提出意见, 点个赞, 鼓励一下, 我们一起进步. 加油 !!
  • 相关阅读:
    提取多层嵌套Json数据
    Jquery 使用Ajax获取后台返回的Json数据后,页面处理
    Jquery购物车jsorder改进版,支持后台处理程序直接转换成DataTable处理
    长连接和短连接
    JAVA8新特性
    线程、进程与程序+并行与并发
    订单号生成规则
    散列表解决冲突的方式
    125.Valid Palindrome
    128.Longest Consecutive Sequence
  • 原文地址:https://www.cnblogs.com/xiaxiangx/p/15389419.html
Copyright © 2020-2023  润新知