Threejs里反向播放动画

news2025/1/24 22:45:37

在Blender里给对象添加了一个动画后,假设是在帧1到帧40添加的动画帧,那么正常播放时是从帧1到帧40,反向播放则是从帧40到帧1,本文讲述如何在Threejs里方向播放Blender里添加的动画。


一 添加动画

之前文章中已经讲述如何在Blender里添加多个动画,这里只需要添加一个动画。

首先在Blender里添加2个立方体,然后通过添加材质(Material)来让他们有不同的颜色,

1. 添加材质

材质添加步骤如下,
image.png

点击New后在新界面里点击Base Color来修改材质颜色,
image.png

最后结果如下,一个蓝色,一个红色

image.png

2. 添加动画

在之前的文章中讲解了如何添加动画,这里添加的动画如下,

  • 蓝色立方体: 帧1 (x:0, y:0, z:0) —> 帧40 (x:5, y:0, z:0)
  • 红色立方体: 帧1 (x:0, y:5, z:0) —> 帧40 (x:-5, y:5, z:0)

注意,这2个立方体y的位置不一样,这样才能把他们分开,不然会重叠在一起

添加好之后,把模型导出,格式为glTF 2.0,名字为cube_reverse_play.gltf


二 Threejs 例子

main.js内容如下,

import * as THREE from 'three';

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GUI } from 'lil-gui'



const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff );
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1e-5, 1e10 );
camera.position.set(0, 15, 30);



var ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);

const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputColorSpace = THREE.SRGBColorSpace;

document.body.appendChild( renderer.domElement );

window.addEventListener( 'resize', onWindowResize );

const loader = new GLTFLoader();

const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);


let modelReady = false;
let gltfscene;
let horsevisible = false;
let mixer;


let actions; // 存放动画

loader.load(
    '/models/cube_reverse_play.gltf',
    function (gltf) {
        gltfscene = gltf.scene;
        scene.add(gltfscene);

        console.log(gltf.animations);

        mixer = new THREE.AnimationMixer(gltf.scene);

        let Action1 = mixer.clipAction( gltf.animations[0] );
        let Action2 = mixer.clipAction( gltf.animations[1] );

        actions = [Action1, Action2];

        modelReady = true;
    },
    function(xhr) {
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    },
    function (error) {
        console.log('An error happened.');
    }
)


const obj = {
    normal: function() {
        playAnimationNoamal(actions[0]);
        playAnimationNoamal(actions[1]);
    },
    reverse: function() {
        playAnimationReverse(actions[0]);
        playAnimationReverse(actions[1]);
    }
}


function playAnimationNoamal(targetAnimation) {
    targetAnimation.paused = false;
    targetAnimation.timeScale = 1;
    targetAnimation.clampWhenFinished = true;
    targetAnimation.setLoop(THREE.LoopOnce);
    targetAnimation.play();
}

function playAnimationReverse(targetAnimation) {
    targetAnimation.paused = false;
    targetAnimation.timeScale = -1;
    targetAnimation.clampWhenFinished = true;
    targetAnimation.setLoop(THREE.LoopOnce);
    targetAnimation.play();
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );
}


// 添加正向和反向播放的按钮
const gui = new GUI()
gui.add(obj, 'normal');
gui.add(obj, 'reverse');


const grid = new THREE.GridHelper( 2000, 20, 0x000000, 0x000000 );
grid.material.opacity = 0.3;
grid.material.transparent = true;
scene.add( grid );

const controls = new OrbitControls(camera, renderer.domElement);
controls.update();


const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame( animate );
    if (modelReady)
    {
        mixer.update(clock.getDelta());
    }

    controls.update();

    renderer.render( scene, camera );
}

animate();

代码里的关键点有3个,

  1. 设置动画执行一次
  2. 正向播放把timeScale属性设置为1,这个也是默认值,不设置也行
  3. 反向播放把timeScale属性设置为-1

执行npx vite后,在浏览器里打开地址,显示如下,
image.png

点击normal按钮,可以看到动画开始播放,从帧1到帧40,然后再点击reverse,就会从帧40播放到帧1


三 总结

本文讲述了如何在Threejs里反向播放Blender里添加的动画。

另外欢迎大家关注本人的微信公众号,文章会同步更新到公众号里。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/965509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MAC ITEM 解决cd: string not in pwd的问题

今天使用cd 粘贴复制的路径的时候,报了这么一个错. cd: string not in pwd eistert192 Library % cd Application Support cd: string not in pwd: Application eistert192 Library % 让人一脸懵逼. 对比一下,发现中文路径里的空格截断了路径 导致后面的路径就没有办法被包含…

财报解读:迈向高端化,珍酒李渡如何持续讲好品牌故事?

2023年上半年,尤其是第二季度,白酒行业淡季属性较为明显。对于市场情况,中国酒业协会《2023中国白酒市场中期研究报告》也有所披露:约40.91%的受访者反馈春节后平日的白酒消费量有所减少,约31.82%的受访者反馈五一期间…

数据结构与算法(二)算法分析

算法的特性 算法具有五个基本特性:输入、输出、有穷性、确定性和可行性。 输入输出 算法具有零个或多个输入至少有一个或多个输出:算法是一定需要输出的,不需要输出,你用这个算法干吗? 有穷性 指算法在执行有限的步骤…

教你如何进行vcruntime140_1.dll文件下载安装,4种方法详细的安装方法

今天主要要跟大家说说vcruntime140_1.dll文件下载安装,其实要下载安装这个文件还是有不少方法的,只要不要慌,有的时候办法解决,首先我们要知道vcruntime140_1.dll是Microsoft Visual C的一部分,是许多计算机程序运行所…

Python项目打包与部署(1):模块与包的概念与关系

Python是动态类型编程语言,意味着python不需要提前编译。1个Python项目通常也包含多个.py文件, 通常也会引用python标准库,或第3方库,也存在着依赖关系。因此python项目也 当实际构建1个 Python 项目时,模块与包是我们…

【python基础教程】类中属性和方法的具体定义方法及使用

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 以下介绍在python的re模块中怎样应用正则表达式 👇 👇 👇 更多精彩机密、教程,尽在下方,赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备…

Mybatis1.2 查询所有数据

1.2 查询所有数据 1.2.1 编写接口方法1.2.2 编写SQL语句1.2.3 编写测试方法1.2.4 起别名解决上述问题1.2.5 使用resultMap解决上述问题1.2.6 小结 如上图所示就页面上展示的数据,而这些数据需要从数据库进行查询。接下来我们就来讲查询所有数据功能,而实…

JavaScript【转】

以下内容转载和参考自:w3school的JavaScript学习内容,HTML JavaScript。 JavaScript 使 HTML 页面更具动态性和交互性,前面我们都是在代码中一开始就将元素的值、属性、style样式写死,使用JavaScript 的话就可以对这些内容动态的更…

WordPress(6)网站侧边栏倒计时进度小工具

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 效果图在这里插入图片描述一、添加位置二、主题style.css文件中添加美化1.引入库2.添加自定义的HTML模块效果图 提示:以下是本篇文章正文内容,下面案例可供参考 一、添加位置 在主题中 child.js…

QT DAY 4

时钟: #include "widget.h" #include "ui_widget.h"int hour0; int min0; int sec0; int count0; Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);this->setFixedSize(800,600);timer new …

【LeetCode-中等题】200. 岛屿数量

文章目录 题目方法一:深度优先搜索 dfs方法二:广度优先搜索 bfs方法三:(重点掌握)并查集 题目 方法一:深度优先搜索 dfs 思路:让一个扫描指针扫描每一个格子,然后每扫到一个为1的格…

代码随想录—力扣算法题:19删除链表的倒数第N个节点.Java版(示例代码与导图详解)

19.删除链表的倒数第N个节点 力扣题目链接 更多内容可点击此处跳转到代码随想录,看原版文件 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 进阶:你能尝试使用一趟扫描实现吗? 示例 1&#xff1…

浅析Linux系统I/O模型

文章目录 概述阻塞式I/O模型非阻塞式I/O模型I/O多路复用模型信号驱动式I/O模型异步I/O模型相关参考 概述 在操作系统中,I/O类操作是相对慢速的,应用发起一个I/O操作,需要等待I/O资源就绪后,才能继续后面的处理。这种简单的请求-响…

无涯教程-JavaScript - NORMINV函数

NORMINV函数取代了Excel 2010中的NORM.INV函数。 描述 对于指定的平均值和标准差,该函数返回正态累积分布的反函数。 语法 NORMINV (probability,mean,standard_dev)争论 Argument描述Required/OptionalProbabilityA probability corresponding to the normal distributio…

NVME Linux的查询命令-继续更新

NVME Linux的查询命令 查看NVMe设备 # nvme list 查看nvme controller 支持的一些特性 # nvme id-ctrl /dev/nvme0 查看设备smart log信息 # nvme smart-log /dev/nvme0 查看设备error 信息 # nvme error-log /dev/nvme0 设备的所有命名空间 # nvme list-ns /dev/nvmeX 检…

uni-app之android项目云打包

1,项目根目录,找到mainfest.json,如果appid是空的,需要生成一个appid 2,点击重新获取appid,这个时候需要登录,那就输入账号密码登录下 3,登陆后可以看到获取appid成功 4,…

企业文件加密防泄密软件系统——「天锐绿盾」

天锐绿盾是一款企业电子文件透明加密安全防泄密管理系统,采用文件过滤驱动技术,对电子文档进行实时动态保护,防止企业计算机信息被破坏、丢失、泄密等安全问题。 PC访问地址: 首页 以下是关于天锐绿盾的详细介绍: 透明…

密度图及山脊图绘图基础

文章目录 3 种绘制密度图方法对比多组数据、同一个核函数渐变颜色填充“山脊”图同一坐标系中多个密度图的绘制 Seaborn 的 kdeplot() 函数是 Python 中绘制密度图的方式之一,Matplotlib 在现阶段则没有具体的绘制密度图的函数,一般是结合 Scipy 库中的 …

又一关键系统上线,理想车云和自动驾驶系统登陆OceanBase

8 月 1 日,理想汽车公布 7 月交付数据,理想汽车 2023 年 7 月共交付新车 34,134 辆,同比增长 227.5%,并已连续两个月交付量突破三万。至此,理想汽车 2023 年累计交付量已经达到 173,251 辆,远超 2022 年全年…

异常处理

目录 异常处理 处理异常 方案一 方案二 小结 异常处理 程序开发过程中不可避免地会遇见异常现象在案例功能的实现中我们并没有设置如何对于程序出现异常时如何进行处理 在三层架构中,如果持久层程序运行出现错误,由于我们在三层架构中都没有设置如…