Unity通过偏移UV播放序列帧动画

  大家好,我是阿赵。
  在Unity引擎里面用shader播放序列图,估计很多人都有用到了,我自己而已写过好几个版本。这里大概介绍一下。

一、原理

  先说目的,我现在有一张这样的图片:
在这里插入图片描述

  这张图片上面,有9个格子,可以理解成是一个动画的9个序列帧,接下来,通过写一个简单的Shader,按照顺序逐个的显示出来,形成一个循环的动画:
在这里插入图片描述

ASE里面直接就有这样一个播放序列帧动画的节点,叫做Flipbool UV Animation节点:
在这里插入图片描述

从节点可以看出,做这个UV动画,需要的参数有这些:
1、原始的UV坐标
2、序列图的行列数,比如我刚才那张图就是3x3的行列式
3、播放速度
4、第几帧开始播放
5、当前播放的时间。
然后返回的结果,是一个新的UV坐标
  所以从原理上来说,这个序列帧播放其实是根据当前时间,算出当前需要播放第几帧,然后通过行列数,算出截取第几帧所在的图片的UV坐标,然后返回。

二、实现的代码

  这个UV序列帧动画的代码,我也写过好几个版本,但感觉还是ASE的看起来比较标准一点,所以我就参考ASE的Flipbool UV Animation节点,把它翻译成一个方法:

float2 GetSequenceAnimUV(float2 uv,float cols,float rows,float speed,float startFrame)
{float totalTiles = cols * rows;float colsOffset = 1.0f / cols;float rowsOffset = 1.0f / rows;float speedVal = _Time.y * speed;float2 offsetTiling = float2(colsOffset, rowsOffset);float currentIndex = round(fmod(speedVal + startFrame, totalTiles));currentIndex += (currentIndex < 0) ? totalTiles : 0;float lineNum = round(fmod(currentIndex, cols));float offsetX = lineNum * colsOffset;float rowCount = round(fmod((currentIndex - lineNum) / cols, rows));rowCount = (int)(rows - 1) - rowCount;float offsetY = rowCount * rowsOffset;float2 offsetXY = float2(offsetX, offsetY);float2 result = uv*offsetTiling +offsetXY;return result;
}

  使用的时候,传入uv、行列数、速度、开始帧这几个参数之后,就可以返回一个当前帧的UV,然后拿这个UV去采样整张图片就可以了;

三、扩展应用

1、自己控制时间流逝

从上面的代码可以看出,这个序列帧动画会自己播放,是因为使用了_Time.y,这是一个时间,代表了从加载场景完成到当前的时间,是会自己增加的。
如果想不用这个系统的时间,而是由自己来控制时间,有2个办法:

1.改变speed参数

speed可以使正数、负数或者是0。当speed越大时,播放得越快,当speed为负数时,动画就是倒着播放。当速度为0时,动画播放就停止了。
不过我觉得速度参数只是一个控制播放快慢的手段,不是控制时间的方式。

2.自己控制time

  这个方法是,不使用_Time.y,而是自己传入timeVal参数。这样,我们需要在其他脚本比如C#里面维护一个时间变量。
  这样做的好处是,在不改变播放正常速度时,我们可以任意的跳转到某一个时间点。比如现在需要做一个时光回退的效果,突然间整个世界都回溯到之前几秒钟,通过统一传入某个时间戳,所有动画都可以一起回退到之前的状态。
  当然,用time参数也可以实现加速减速和暂停。
自己控制time参数的方法如下:

float2 GetSequenceAnimUVByTime(float2 uv, float cols, float rows, float speed, float startFrame,float timeVal)
{float totalTiles = cols * rows;float colsOffset = 1.0f / cols;float rowsOffset = 1.0f / rows;float speedVal = timeVal * speed;float2 offsetTiling = float2(colsOffset, rowsOffset);float currentIndex = round(fmod(speedVal + startFrame, totalTiles));currentIndex += (currentIndex < 0) ? totalTiles : 0;float lineNum = round(fmod(currentIndex, cols));float offsetX = lineNum * colsOffset;float rowCount = round(fmod((currentIndex - lineNum) / cols, rows));rowCount = (int)(rows - 1) - rowCount;float offsetY = rowCount * rowsOffset;float2 offsetXY = float2(offsetX, offsetY);float2 result = uv * offsetTiling + offsetXY;return result;
}

2、自己控制播放指定帧

  有时候做一些比较特殊的序列帧动画,需要根据情况播放特定很准确的某一帧,或者在某几帧之间重复。
  这样的情况如果使用Time作为控制,似乎就比较的不适合了。所以,根据实际情况改一下,可以把传入的速度参数和时间参数都去掉,变成传入想播放第几帧:

float2 GetSequenceAnimUVByIndex(float2 uv, float cols, float rows, float currentFrame)
{float totalTiles = cols * rows;float colsOffset = 1.0f / cols;float rowsOffset = 1.0f / rows;float2 offsetTiling = float2(colsOffset, rowsOffset);float currentIndex = currentFrame;currentIndex += (currentIndex < 0) ? totalTiles : 0;float lineNum = round(fmod(currentIndex, cols));float offsetX = lineNum * colsOffset;float rowCount = round(fmod((currentIndex - lineNum) / cols, rows));rowCount = (int)(rows - 1) - rowCount;float offsetY = rowCount * rowsOffset;float2 offsetXY = float2(offsetX, offsetY);float2 result = uv * offsetTiling + offsetXY;return result;
}

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

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

相关文章

使用errors.Wrapf()代替log.Error()

介绍不同语言的错误处理机制: Error handling patterns[1] Musings about error handling mechanisms in programming languages[2] 项目中 main调func1&#xff0c;func1调取func2... 这样就会出现很多的 if err ! nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要…

架构师成长之路|Redis key过期清除策略

Eviction policies maxmemory 100mb 当我们设置的内存达到指定的内存量时,清除策略的配置方式决定了默认行为。Redis可以为可能导致使用更多内存的命令返回错误,也可以在每次添加新数据时清除一些旧数据以返回到指定的限制。 当达到最大内存限制时,Redis所遵循的确切行为是…

美妆+七人拼团模式:如何打造新型社交电商营销方式

美妆是一个充满竞争和创新的行业&#xff0c;要想在市场上获得优势&#xff0c;就需要不断寻找新的营销方式&#xff0c;吸引和留住消费者。七人拼团模式就是一种结合了社交电商和拼购玩法的新型商业模式&#xff0c;它可以利用社交网络的裂变效应&#xff0c;增加品牌曝光度和…

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

《Go 语言第一课》课程学习笔记(十五)

并发 Go 的并发方案&#xff1a;goroutine 并行&#xff08;parallelism&#xff09;&#xff0c;指的就是在同一时刻&#xff0c;有两个或两个以上的任务&#xff08;这里指进程&#xff09;的代码在处理器上执行。 并发不是并行&#xff0c;并发关乎结构&#xff0c;并行关…

Playwright for Python:基础用法

写在前面 Playwright for Python&#xff1a;安装及初步使用 自动化交流 Playwright可以与HTML输入元素进行交互&#xff0c;例如文本输入框、复选框、单选按钮、下拉选项等。它可以模拟鼠标点击、输入字符、按键和快捷键&#xff0c;还可以上传文件并将焦点设置到元素上。 …

AndroidTV端:酒店扫码认证投屏DLNA

被老板叼了几次了&#xff0c;最近实在忍不了&#xff0c;准备离职&#xff1b; 但是担心离职后长时间没有办法找到工作 就想贡献一套平时琢磨出来的程序&#xff0c;请各位有能力的话带我熬过这凛冽的寒冬。 目前写出来的&#xff0c;有三个端&#xff1a;安卓TV端&#xf…

准备HarmonyOS开发环境

引言 在开始 HarmonyOS 开发之前&#xff0c;需要准备好开发环境。本章将详细指导你如何安装 HarmonyOS SDK、配置开发环境、创建 HarmonyOS 项目。 目录 安装 HarmonyOS SDK 配置开发环境 创建 HarmonyOS 项目 总结 1. 安装 HarmonyOS SDK HarmonyOS SDK 是开发 Harmo…

uni-app 之 scroll-view和swiper

uni-app 之 scroll-view和swiper <!-- vue2的<template>里必须要有一个盒子&#xff0c;不能有两个&#xff0c;这里的盒子就是 view--> <template><view><navigator url"/pages/home/home"><button style"background: #ff00f…

【Selenium2+python】自动化unittest生成测试报告

前言 批量执行完用例后&#xff0c;生成的测试报告是文本形式的&#xff0c;不够直观&#xff0c;为了更好的展示测试报告&#xff0c;最好是生成HTML格式的。 unittest里面是不能生成html格式报告的&#xff0c;需要导入一个第三方的模块&#xff1a;HTMLTestRunner 一、导…

leetcode1288. 删除被覆盖区间(java)

删除被覆盖区间 题目描述贪心法代码演示 题目描述 难度 - 中等 leetcode1288. 删除被覆盖区间 给你一个区间列表&#xff0c;请你删除列表中被其他区间所覆盖的区间。 只有当 c < a 且 b < d 时&#xff0c;我们才认为区间 [a,b) 被区间 [c,d) 覆盖。 在完成所有删除操作…

MySql学习笔记05——DML

DML 插入数据insert insert into 表名(字段名1&#xff0c;字段名2&#xff0c;字段名3...)values(值1&#xff0c;值2&#xff0c;值3)&#xff1b;字段名和值要一一对应&#xff08;顺序对应&#xff0c;数据类型对应&#xff09; insert into t_student(no,name,sex,age,…

Docker使用数据卷挂载进行数据存储与共享

一、挂载和数据卷 在 Docker 中&#xff0c;挂载&#xff08;Mounting&#xff09;和数据卷&#xff08;Data Volumes&#xff09;是用于在容器和宿主机之间共享数据的机制。 挂载&#xff1a;将宿主机文件系统中的目录或文件与容器中的目录或文件进行关联的过程。数据卷&…

收入下降,亏损扩大,利润率急剧恶化,蔚来仍充满风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 蔚来第二季度财报分析 猛兽财经从蔚来&#xff08;NIO&#xff09;2023年第二季度财报中&#xff0c;获得的最大收获并不是该公司的收入下降或亏损扩大&#xff0c;而是由于价格竞争加剧&#xff0c;中国电动汽车行业整体上…

什么是安全运营中心(SOC),应该了解什么

安全运营中心&#xff08;SOC&#xff09; 是一种企业监视和警报设施&#xff0c;可帮助组织检测安全威胁、监视安全事件和分析性能数据以改进公司运营。 什么是安全运营中心&#xff08;SOC&#xff09; 安全运营中心&#xff08;SOC&#xff09;是一个中央监视和监视中心&a…

第二次作业

1.编写脚本for1.sh,使用for循环创建20账户&#xff0c;账户名前缀由用户从键盘输入&#xff0c;账户初始密码由用户输入&#xff0c;例如: test1、test2、test3、.....、 test10 编写脚本for1.sh 执行脚本&#xff1a;bash for.sh 2&#xff0c;编写脚本for2.sh,使用for循环,通…

springboot 集成 lucene

简介 数据每分钟产生200条&#xff0c;使用mysql储存。目前有数据超过700M。按照日期查询&#xff0c;按月查询包含每次超过20w条以上&#xff0c;时间比较长。计划使用lucene优化查询&#xff0c;不适用es是因为项目较小&#xff0c;没有更富裕的资源。 基本步骤 引入依赖。…

工业级大模型应用长啥样

我们可以通过开源工具&#xff0c;搭建大模型应用的“原型系统”&#xff0c;但是我要来“泼冷水”&#xff0c;因为这距离工业级大模型应用&#xff0c;还是有很大的差距。 这篇文章主要讨论这种”原型系统“可能带来的认知误区以及工业级大模型应用需要考量的因素。 “原型…

模糊测试面面观 | 模糊测试是如何发现异常情况的?

协议模糊测试是一种用于评估通信协议、文件格式和API实现系统安全性和稳定性的关键技术。在模糊测试过程中&#xff0c;监视器扮演着关键角色&#xff0c;它们能够捕获异常情况、错误响应、资源利用等&#xff0c;为测试人员提供有价值的信息&#xff0c;有助于发现潜在漏洞和问…

ceph Monitor原理和代码流程介绍

Monitor介绍 Monitor在Ceph集群中扮演管理者的角色&#xff0c;维护了整个集群的状态&#xff0c;集群的状态被抽象成几个Map对象&#xff0c;包括monmap、osdmap、mdsmap、authmap、logmap等&#xff0c;保证集群的相关组件在同一时刻能够达成一致&#xff0c;相当于领导层。…