什么是顶点动画?

简单来说,通过改变网格顶点的位置,使网格变形从而做成的动画。顶点动画的灵活度要远远高于骨骼动画。骨骼动画是靠骨骼(一堆有层级结构的节点,数量应该是远远小于网格顶点的数量的)的变化来驱动网格的形变,从自由度上来说,顶点动画每个网格的顶点都可以发生变化,因此自由度要远高于骨骼动画,可以做出骨骼动画达不到的一些效果,例如像流体这种拓扑发生变化的物体。

如何在游戏引擎中使用顶点动画?

在动画的每一帧,网格的顶点的位置、数量、拓扑都可以发生变化,因此对于这种动画,我们只能把每一帧的数据都给保存下来(当然也有网格序列的压缩方法,例如利用类似 PCA 的方法等),因此数据量会很大。在游戏引擎中有两种常见的做法

  • 一种是在 CPU 侧,将数据存储为网格序列,然后按照一定的规则去播放这个网格序列,像 Unity 就支持 .abc (alembic)文件的格式的导入。
  • 一种是在 GPU 侧,将数据写入到一张或几张贴图中,然后在 shader 中贴图进行采样、还原,然后在 vertex shader 中根据贴图中的数据来改变顶点的位置,这就是本文要介绍的 “顶点动画贴图” (VAT)技术。

VAT 烘焙的流程

VAT 技术很灵活,因为核心思想只是在贴图中存了一些数据,至于这个数据怎么存?存什么?怎么解析?完全都是可以自己控制的,因此也没有什么规范之类的。在 Houdini 中是支持导出 VAT 的,也有配套的 Unity/UE 中解析的 shader,Blender 似乎是没有内置的导出 VAT 的能力,一般都是靠自己写或者相关插件之类。其实也不一定要从 DCC 软件中导出 VAT,只要这些模型文件(例如 .usd, .abc, .fbx, ...)中保存了网格序列必要的信息,我们可以直接去解析这些文件,来制作 VAT。除了保存数据的贴图外,还需要一个基础的网格来承载基础的顶点数据,因为必须要有网格数据,才能用 shader 来进行绘制,每次渲染都是绘制的这个网格,只不过我们在 shader 中利用 VAT 改变了这个网格的顶点数据而已。

我们可以简单的分一分几种动画类型:

  • 拓扑改变的:例如流体
  • 拓扑不变的:例如布料

每种类型的处理会稍稍有些区别:

拓扑改变的

  1. 首先需要遍历一下网格序列,找一下哪一帧的网格的面最多。原因是绘制的三角面的数量,如果我们随便找一帧作为基础网格,例如基础网格有 100 个三角面(face),而其他帧也许有 200 个三角面,那么无论如何也没法绘制 200 个三角面了,所以需要找一下最大的那个。对于某一帧的绘制,也许当前需要绘制的面的数量小于基础网格面的数量,这个也不要紧,可以将初始网格的所有顶点的位置都设置为 (0,0,0),所以多余的面也不会画出来。
  2. 计算贴图的尺寸,因为贴图的尺寸关系到我们如何进行采样。可以简单的计算一下,我们可以假设 y 方向代表的是不用的帧,而 x 方向代表的是同一帧内不同的顶点。例如一帧我们有 1000 个顶点(顶点可能会重复,例如 2 个面有 6 个顶点,不会共用顶点),那么我们可以选择 width = 512 的贴图,那么要存 1 帧的 1000 个顶点,需要 2 行,如果我们有 100 帧,那最终 VAT 的尺寸为 (512, 200)。
  3. 计算 顶点 uv 坐标,在计算完 VAT 的尺寸后,我们需要给基础网格的顶点计算 uv 坐标,来代表这个顶点在 VAT 对应的位置。如下:
# + 0.5 是为了采样的时候在像素的中心位置
# 1.0 - 是因为 uv 坐标一般左下是 (0,0),而图像一般左上是 (0,0)
for i in range(1000):
u = ((i % 512) + 0.5) / 512
v = 1.0 - ((i // 512) + 0.5 / 200)
  1. 计算完成 uv 以后,我们就可以将 uv 数据写入网格顶点数据来,网格的顶点数据可以是 POS + TEXCOORD0 + NORMAL。
  2. 写入贴图,可以遍历每一帧,然后在每一帧按照面的顺序遍历每一个顶点,在贴图中,依次每 3 个顶点代表一个面。同理,法线数据(normal)也是类似顶点的方式,写入另一张贴图里。这里需要记得一件事情,如果是 RGB8,那么 RGB 和对应 xyz,但是 xyz 需要先归一化一下,即用 minmax 归一化的方法,因为 RGB 的只能存储 0-255。
  3. 保存元信息,这里的元信息可以保存帧数,所有顶点中的最大最小值,bbox 等自己可以用的到的信息。

这样我们最终得到了 VAT_pos, VAT_nor, mesh, meta 四个文件,分别对应顶点位置信息、法线信息、网格信息和元信息,有了这些数据就可以拿到游戏引擎中去解析了。

拓扑不变的

拓扑也可以按照拓扑改变的方法可以进行制作,不过可以省略一些步骤,例如遍历网格序列寻找最大的面数,因为拓扑不变,所以可以用第一帧的网格作为基础网格,其他的做法基本都一样

有了 VAT 如何使用?

有了 VAT 以后,需要有可以解析的 shader 进行支持,即在 shader 里将 VAT 里的数据读出来,这个 shader 根据自己的烘焙的规则,然后自己进行解析。github上有一些开源的 shader,或者是 Houdini 配套的 shader 可以使用。本文先介绍一下 VAT 的概念以后烘焙的方法,下一篇来介绍一下在 shader 中解析的方法。

[CG] 顶点动画贴图 (Vertex Animation Texture, VAT)的更多相关文章

  1. 《The Cg Tutorial》阅读笔记——动画 Animation

    这段时间阅读了英文版的NVidia官方的<The Cg Tutorial>,借此来学习基本的图形学知识和着色器编程. 在此做一个阅读笔记. 本文为大便一箩筐的原创内容,转载请注明出处,谢谢 ...

  2. Vertex Fetch Texture (VTF)

    http://www.opengl.org/wiki/Vertex_Texture_Fetch Vertex Texture Fetch     This article contains inacc ...

  3. unity下贴图混合(Texture Blending)

    在unity制作自定义时,经常会遇到自定义妆容等问题,美术会提供大量的眉毛/胡子/腮红等贴图,来供用户选择. 美术给出的眉毛的小贴图如下: 在用户选用不同的胡子眉毛,可以将选定的小贴图和皮肤base贴 ...

  4. 0UE3 材质概要

    材质概要 概述 参数 当创建材质时如何考虑颜色 材质表达式 Abs(求绝对值) 添加 AntialiasedTextureMask AppendVector(向量合并) BumpOffset(凸凹偏移 ...

  5. OpenGL之纹理贴图(Texture)

    学习自: https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 先上一波效果图: 实际上就是:画了一个矩形,然后 ...

  6. Texture 纹理贴图

    基础贴图Shader:只有纹理 1. 在属性中声明纹理贴图: _MainTex ("Texture", 2D) = "white" {} 2. 在Pass中声明 ...

  7. angr原理与实践(二)—— 各类图的生成(CFG CG ACFG DDG等)

    ​  本文系原创,转载请说明出处 Please Subscribe Wechat Official Account:信安科研人,获取更多的原创安全资讯 上一篇文章介绍了angr的原理,自此篇文章开始, ...

  8. 知识图谱-生物信息学-医学顶刊论文(Briefings in Bioinformatics-2021):生物信息学中的图表示学习:趋势、方法和应用

    4.(2021.6.24)Briefings-生物信息学中的图表示学习:趋势.方法和应用 论文标题: Graph representation learning in bioinformatics: ...

  9. cg tut

    Gesture Drawing with Alex Woo Gesture Drawing with Alex Woo and Louis Gonzales http://eisneim.com/?p ...

随机推荐

  1. 关于我用python表白成功这件事【表白成功】

    520,并非情人所属, 我们可以表白万物, 不管什么时候, 这都是一个特别的日子, 今天,我要表白所有, 心里有我的人! 在这个充满幸福的日子里, 我要把最美好的祝福, 送给心里有我的每一个人: 祝愿 ...

  2. 如何准备论文线上Presentation视频录制教程(Summary of Video Recording)

    0:前言 由于国外的疫情严重,目前大多数学术会议都是线上举办,因此往往需要制作presentation的视频录制.由于各种软件横飞,有的需要会员并且不熟悉操作,特别浪费时间.因此,我将这次的操作和遇到 ...

  3. 字节输入流_InputStream类&FileInputStream类介绍和字节输入流读取字节数据

    java.io.InputStream:字节输入流 此抽象类是表示字节输入流的所有类的超类 定义了所有子类共性的方法: int read()从输入流中读取数据的下一个字节 int read(byte[ ...

  4. 记录一次ubuntu安装mysql,远程无法登录问题的解决历程

    进入ubuntu的mysql配置文件 sudo vim debian.cnf [client] host = localhost user = debian-sys-maint password = ...

  5. Nginx工作模式

    Master-Worker模式 1.Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程.2.接收来自外界的信号,向各worker进程发送信号,每个进程都有可能来处理 ...

  6. 作业一、安装Ubuntu系统

    Ubuntu1804安装 一.安装环境 1.VMware Workstation 16 Pro 2.Ubuntu 18.04.6 LTS 二.部署系统 步骤1.进入VMware,点击创建新的虚拟机 步 ...

  7. linux nginx搭建与使用

    安装nginx yum -y install nginx 测试是否安装正确: nginx -t 打印如下: nginx: the configuration file /etc/nginx/nginx ...

  8. 【Java线程池】 java.util.concurrent.ThreadPoolExecutor 分析

    线程池概述 线程池,是指管理一组同构工作线程的资源池. 线程池在工作队列(Work Queue)中保存了所有等待执行的任务.工作者线程(Work Thread)会从工作队列中获取一个任务并执行,然后返 ...

  9. 如何记录分析你的炼丹流程—可视化神器Wandb使用笔记【1】

    本节主要记录使用wandb记录训练曲线以及上传一些格式的数据将其展示在wandb中以便分析的方法,略过注册安装部分(可使用pip intall wandb安装,注册相关issue可上网搜索),文章着重 ...

  10. Vue el与data的两种写法 && Object.defineProperty方法

    1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8" /> 5 & ...