Animation 体验一

动画效果

其中涉及到 skeletion、clipAction、GUI

Skeletion

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

加载好模型后,就可以使用 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({ width: 200 });
// domElement 可以获取到 dom 元素
panel.domElement.style.marginTop = "10px"; // 分别创建两个父文件夹并打开
const folder1 = panel.addFolder("visibility");
const folder2 = panel.addFolder("pause/continue");
folder1.open();
folder2.open();

  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({ width: 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} />;
}

Three 之 Animation 体验一的更多相关文章

  1. Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)

    更新: 2019-11-24  dialog vs router link refer : https://stackoverflow.com/questions/51821766/angular-m ...

  2. css Animation初体验

    目前有越来越多的网站都使用animation,无论他们是用GIF,SVG,WebGL,视频背景或者其他形式展示.适当地使用动画会让网站更生动,互动性更好,为用户增加一个额外的反馈和体验层. 在本教程中 ...

  3. 谈谈iOS Animation

    零.前言 这里没有太多的代码细节,只是探索iOS动画的基本概念,以及其抽象模型,数学基础等.我们学习一个知识的时候一般有两个部分,抽象部分和形象部分,抽象好比语言的语法,是规则,形象好比具体的句子,可 ...

  4. 浅谈Android样式开发之View Animation (视图动画)

    引言 一个用户体验良好的App肯定少不了动画效果.Android为我们提供了2种动画框架,分别是视图动画(View Animation)和属性动画(Property Animation).视图动画比较 ...

  5. 今日提及之动画animation

    今天没有说什么内容,只是对HTML5的细节补充,如HTML结构的可以省略到最大的地步 <!DOCTYPE html><meta charset="UTF-8"&g ...

  6. Material Design Animation

    Material Design Animation Authentic motion 真实的运动 运动以一种优美流动的形式描述了空间关系,功能和目的. Mass and weight: 质量和重量 在 ...

  7. css3 animation实现风车转动

    项目中经常有用到动画效果,比如Loading.风车转动等等.最简单的办法是使用gif,但是gif在半透明背景下有白边,体验不友好,好在现在可以使用css3的anmiation来实现动画效果,极大的提升 ...

  8. vue初体验:实现一个增删查改成绩单

    前端变化层出不穷,去年NG火一片,今年react,vue火一片,ng硬着头皮看了几套教程,总被其中的概念绕晕,react是faceback出品,正在不断学习中,同时抽时间了解了vue,查看了vue官方 ...

  9. core animation (转)

    iOS Core Animation 简明系列教程 看到无数的CA教程,都非常的难懂,各种事务各种图层关系看的人头大.自己就想用通俗的语言翻译给大家听,尽可能准确表达,如果哪里有问题,请您指出我会尽快 ...

随机推荐

  1. 不同的 count 用法

    不同的 count 用法效率:在 select count(?) from t 这样的查询语句里面, count(*).count(主键 id).count(字段) 和 count(1) 等不同用法的 ...

  2. session.flush与transaction.commit

    以session的save方法为例来看一个简单.完整的事务流程,如下是代码片段: ---------------------------- Session session = sessionFacto ...

  3. sparksql字段类型转换

    1.spark sql 计算时,一定要注意精度的问题,一般像金额之类的值,要先转换为double或者 decimal来进行计算了. 一.sql的方式:select shop_id,order_id,s ...

  4. Helm on K8S

    前言 容器的出现,标志着云原生的到来,Docker 基于 Linux 隔离.虚拟化等能力封装了应用:Kubernetes 的出现,建立了云原生时代的技术基础设施,它基于对容器的编排封装了集群:Kube ...

  5. Go与接口:接口即约定

    接口 接口类型是对其他类型行为的概括与抽象.我们可以通过接口来约定某一类通用行为.Go语言的接口是隐式的:只要实现接口A的所有方法就代表实现了接口A. 接口即约定 接口是什么样的? package i ...

  6. 使用栅格系统开发响应式页面——logo+nav实例

    小屏时: 中屏及以上时: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  7. shell中的引号

    单引号: 所见即所得 原封不动输出 双引号: 与单引号类似 特殊符号进行解析 ( $ $() `` ! ) 无引号: 与双引号类似 支持通配符( {} * ) 反引号: 优先执行 优先执行里面的命令, ...

  8. Smooth

      考场\(AC\),还是很开心的.   考虑这题让你干啥,就是给你一堆素数,然后让你用他们去构造数,求其中第\(k\)小的.   我们可以用系数累乘的方式,同时利用小根堆实现有序,加一个优化,就过了 ...

  9. linux 常用命令脑图

  10. Java字符串常量池及字符串判等解析

    一.理解"=="的含义 "=="常用于两个对象的判等操作,在Java中,"=="主要有以下两种用法: 1.基础数据类型:比较的是他们的值是否 ...