Motion Matching
Motion Matching
输入: 预期轨迹和其他特征的 feature
输出: 最匹配的 pose
具体来说一个传统的motion matching分为以下几步:
- Projection: 当用户输入的轨迹和查找到的目标 Frame 的轨迹不一致(或是出路很大),则需要重新搜索,搜索的过程主要是通过用户模拟的轨迹和当前 pose 的状态来去 database 中进行 match,然后作为修正的 Frame
- Decompression: 要把当前的目标 Frame 重新映射回目标 Pose
- Stepping: index++ 逐步推出下一个的 Frame
在MM的三个步骤中,Decompression 和 Stepping 的难度都不是很大,因为表示 feature 的 x 和 对应的 pose y 都被储存在database 中,所以MM中玩家与角色之间的交互可以表示为:
使用的时候直接读取就OK了,在这个算法中耗时间空间的主要是 Projection ,育碧同样给出了他们的解决思路:
- LOD
- KD-Tree
先来看看MM 的代码思路,其实很简单
- 每一帧都是在database 中对index++
- 在需要搜索的时候,在database 中搜索,如果 best_index 可用则切换
// 判断是否为最后一帧
bool end_of_anim = database_trajectory_index_clamp(db, frame_index, 1) == frame_index;
if (force_search || search_timer <= 0.0f || end_of_anim){// 在数据库中寻找最匹配帧database_search();// 更新 pose 数据if (best_index != frame_index){trns_bone_positions = db.bone_positions(best_index);trns_bone_velocities = db.bone_velocities(best_index);trns_bone_rotations = db.bone_rotations(best_index);trns_bone_angular_velocities = db.bone_angular_velocities(best_index);inertialize_pose_transition();frame_index = best_index;}// Reset search timersearch_timer = search_time;
}
// Tick frame
frame_index++; // Assumes dt is fixed to 60fps// 查询下一 frame_index 对应的 Pose
curr_bone_positions = db.bone_positions(frame_index);
curr_bone_velocities = db.bone_velocities(frame_index);
curr_bone_rotations = db.bone_rotations(frame_index);
curr_bone_angular_velocities = db.bone_angular_velocities(frame_index);
curr_bone_contacts = db.contact_states(frame_index);
具体搜索是怎么算的呢
best_cost = 0.0;
for (int i = 0; i < nfeatures; i++){best_cost += squaref(query_normalized(i) - features(best_index, i));
}
在 database_search() 中用的是欧氏距离,再看看维数,MM 总的特征对比按照如下计算
D i s s i m i l a r i t y ( e i , e c ) = w v × D i s t v ( v i , v c ) + w p × D i s t p ( p i , p c ) + w t × D i s t t ( t i , t c ) Dissimilarity(ei,ec)=w_v×Dist_v(v_i,v_c)+w_p×Dist_p(p_i,p_c)+w_t×Dist_t(t_i,t_c) Dissimilarity(ei,ec)=wv×Distv(vi,vc)+wp×Distp(pi,pc)+wt×Distt(ti,tc)
总的特征对比由 velocity、position 和 trajectory,三个变量得到,其中velocity、position为三维变量,trajectory是二维变量,假设取两个关节的velocity、position,三个未来trajectory,此时的维度:
d i m ( D i s s i m i l a r i t y ) = ( 3 + 3 ) ∗ 2 + 2 ∗ 3 = 18 dim(Dissimilarity) = (3+3)*2+2*3=18 dim(Dissimilarity)=(3+3)∗2+2∗3=18
按照KD-tree的定义有:
2 18 = 262 , 144 ≪ d a t a b a s e f r a m e n u m b e r 2^{18}=262,144 \ll database\ frame\ number 218=262,144≪database frame number
结论:方案可行
以下给出kd-tree 的 python 代码,参考资料:
k-d tree算法的研究
class KDNode(object):def __init__(self, value, split, left, right):# value=[x,y]self.value = valueself.split = splitself.right = rightself.left = leftclass KDTree(object):def __init__(self, data):# data=[[x1,y1,...],[x2,y2,...],...]# 维度k = len(data[0])def CreateNode(split, data_set):if not data_set:return None# 排序data_set.sort(key=lambda x: x[split])# 取中位数split_pos = len(data_set) // 2median = data_set[split_pos]# 计算下一维度split_next = (split + 1) % kreturn KDNode(median, split, CreateNode(split_next, data_set[: split_pos]),CreateNode(split_next, data_set[split_pos + 1:]))self.root = CreateNode(0, data)def search(self, root, x, count=1):nearest = []for i in range(count):nearest.append([-1, None])self.nearest = np.array(nearest)def recurve(node):if node is not None:axis = node.splitdaxis = x[axis] - node.value[axis]if daxis < 0:recurve(node.left)else:recurve(node.right)dist = sqrt(sum((p1 - p2) ** 2 for p1, p2 in zip(x, node.value)))for i, d in enumerate(self.nearest):# 如果当前nearest内i处未标记(-1),或者新点与x距离更近if d[0] < 0 or dist < d[0]: # 插入比i处距离更小的self.nearest = np.insert(self.nearest, i, [dist, node.value], axis=0) self.nearest = self.nearest[:-1]break# 找到nearest集合里距离最大值的位置,为-1值的个数n = list(self.nearest[:, 0]).count(-1)# 切分轴的距离比nearest中最大的小(存在相交)if self.nearest[-n - 1, 0] > abs(daxis):if daxis < 0: # 相交,x[axis]< node.data[axis]时,去右边(左边已经遍历了)recurve(node.right)else: # x[axis]> node.data[axis]时,去左边,(右边已经遍历了)recurve(node.left)recurve(root)return self.nearest# 最近坐标点、最近距离和访问过的节点数
result = namedtuple("Result_tuple", "nearest_point nearest_dist nodes_visited")data = [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]]
# 创建KD-tree
kd = KDTree(data)#[3, 4.5]最近的3个点
n = kd.search(kd.root, [3, 4.5], 3)
print(n)#[[1.8027756377319946 list([2, 3])][2.0615528128088303 list([5, 4])][2.692582403567252 list([4, 7])]]
Motion Matching相关推荐
- 对《Mode-Adaptive Neural Networks for Quadruped Motion Control》一文的理解(上)
该篇文章发表于SIGGRAPH2018,作者HE ZHANG † , University of Edinburgh.SEBASTIAN STARKE , University of Edinburg ...
- Learned Motion Matching-动作生成算法
Learned Motion Matching 来源: SigGraph2021 研究方向: 动作生成 链接: https://dl.acm.org/doi/pdf/10.1145/3386569.3 ...
- 做过《战神》《死亡搁浅》的光子动捕专家,怎么理解动捕?
10月9日,在2021年腾讯游戏开发者大会上(TGDC),腾讯互动娱乐光子技术中心Lead Motion Technician Kevin Wang以<捕风捉影,让虚拟更现实>为主题,立足 ...
- 角色动作系统概述:战斗、3C相关
*有一个很重要的点我忘记说了,就是游戏策略-实际上在制作动作系统的时候要考虑兼容各种策略,但是在调手感前,要先想清楚自己的战斗策略,所为战斗策略是指博弈方式,以及对玩家的操作进行约束,约束具体是指你需 ...
- 角色动画(Character Animation)的现状与趋势
逆向运动学(Inverse Kinematics)求解 一.个人需求 需求: 靠游戏手柄(用户)以虚拟人物的根轨迹trajectory来控制用户朝向,同时通过控制输入来合成出人难以做到的动作. 若缺少 ...
- 汇编指令lmm_动画视频角色的LMM神经网络
汇编指令lmm Researchers at Ubisoft have proposed an alternative to the Motion Matching algorithm for aut ...
- Unity的Package了解(2020.3)
unity 更新很快,很多package如果不及时了解,很容易造很多轮子或走很多弯路. 一.已验证包 ------------------------------------------------- ...
- 【游戏开发阅读列表2】动画(Anima2D、粒子、物理等)
游戏中动画的实现有很多不同方法,帧动画.骨骼动画.基于物理的动画.基于Shader的动画.粒子等. 在这篇文章中,列出了我最近读到过的不同种类动画入门级的文章.视频.关于Unity动画状态机这一类太常 ...
- 2022.5.12 腾讯魔方客户端暑期实习 一面凉经
完全裸考,,,只能当作是长经验了,,,随便记录一下吧/(ㄒoㄒ)/~~太菜了 1.自我介绍 2.实习项目经历 2.1 你在项目中负责的工作 A:负责游戏角色手部的抓取和放下动作的开发,基于UE的C++ ...
最新文章
- 常用 Linux 命令
- Linux进程-命令行参数和环境列表
- python xlwt写入excel_python xlwt模块写入excel超过65536行报错问题解决方法
- 简单地发布EJB程序的过程
- c语言各类随机函数,怎样让c语言中的随机函数真正随机?
- ant 安装及基础教程 !
- camel 调用soap_使用Apache Camel通过soap添加WS-Security
- 敏捷开发中提高软件生产率的方法
- 这个机器人不学数据集,“纯玩”get各类家务技能,LeCun觉得很赞
- 金蝶k3服务器的操作系统,金蝶k3服务器配置工具
- java基础热门侠客养成_侠客养成手册攻略大全 新手攻略开局任务流程汇总[多图]...
- 鸿鹄功能架构图:实现一站式异构数据分析
- 网页音乐制作器(网页钢琴)-- MusicMaker
- python 日期运算_Python中关于日期的计算总结
- 微信卡死代码 java_能让微信卡死的代码是什么 微信整人代码大全
- unity steamworksdk简单接入
- python实现烤羊肉串(类)
- C语言实验——一元二次方程Ⅱ
- 解读Linux零拷贝之mmap
- LVM-HOWTO/学习笔记(五)