Mammals 的过程化生成与运动

runevisionRune Skovbo Johansen

过程化生物进展 2021 - 2024

Jan 10, 2025 in game development, procedural, The Big Forest, video

为了我的游戏 The Big Forest,我希望拥有过程化生成和动画化的生物。不出所料,这是一个相当大的研究挑战。

正如我在 2024 retrospective 中提到的,我花了 2024 年的最后六个月来研究这个课题 —— 三个月用于过程化模型生成,三个月用于过程化动画。 实际上,我对生物的研究开始得更早。 根据我的提交历史,我在为 PCVR 发布 Eye of the Temple 后,于 2021 年开始了这项工作,尽管我在 2024 年之前对它的研究是零星的。

虽然这些生物离它们需要达到的目标还很远,但我将在这里写一些关于我目前进展的内容。

目标

我需要大量的森林生物来用于 The Big Forest 的游戏玩法,其中一些玩法将围绕识别特定的生物,用于各种独特的目的。 我使用简单的精灵作为生物来 prototyped the gameplay,但最终的游戏需要完全 3D 且适合游戏 forest terrain 的生物。

creatures from prototype → replace with 3D procedural creatures → put into procedural terrain

我已经看过很多关于过程化生物的项目。 创建一个带有腿的简单躯干,随机化配置,并通过在直线或简单弧线中在脚步之间过渡脚来动画化运动并不难。

这对于昆虫、蜘蛛、蜥蜴和其他爬行动物,以及外星人和类似外星人的奇幻生物来说效果很好。 项目 Critter Crosser 正在 very cool things with this 方面做着非常酷的事情。 虽然它也以 Mammals 为特色,但我不确定它们是否能很好地转化为游戏有意降低分辨率、古怪的美学之外。

如果我们也考虑只有动画是过程化的游戏,Rain World 是另一个例子,它对其低清晰度但高度动态的类外星生物效果很好。 Spore 也是一个经典例子,尽管它的生物通常看起来既陌生又滑稽。

但对于 The Big Forest 来说,我希望生物感觉它们真正属于森林,其运动和设计让人联想到像狐狸、熊、猞猁、松鼠和鹿这样的四足 Mammals。 Mammals 的外观和移动方式太独特了,不能简单地“即兴发挥”——至少在我的游戏的美学中是这样。 实现逼真的 Mammals 生物需要彻底的研究,所以虽然我也计划包括非 Mammals 生物,但我现在主要关注 Mammals。

生物的过程化生成

基本问题是用一小套参数生成具有合理解剖结构的森林生物,并确保:

  1. 这些参数是 有意义的,因此我可以使用它们来获得我想要的结果。
  2. 参数的任何随机值都将始终创建有效的生物。

我的主要挑战是确定什么是有意义的参数。 这是我必须逐步发现的东西,从基于最小假设的大量低级参数开始,并随着我改进逻辑最终缩小到一小组高级参数。

从一开始,我就决定在可预见的未来专注于基本比例,而不必担心更微妙的形状细节。 因此,我将生成的网格限制为拉伸的矩形。 我必须从某个地方开始,这是光荣的第一个网格:

A very boxy creature.

后来,我将躯干、每条腿、每只脚、脖子、头部、下巴、尾巴和每只耳朵指定为多段拉伸矩形。 我发现这种方法很容易足以捕捉不同动物的肖像。 到 2023 年底,我已经制作了这三个生物以及在它们之间插值的能力:

Simple 3D models of a bull elk, a coyote and a cat.

这是基于非常精细的参数,本质上是具有对齐和厚度数据的骨骼列表。 每个骨骼长度、旋转值和皮肤与骨骼在各个方向上的距离都是输入参数,总计 503 个参数。

使用这些参数从头开始创建生物是不切实际的,因此我开发了一个工具来从蒙皮网格中提取数据。 该工具识别哪些顶点属于哪些骨骼,并从中导出厚度值。 然而,它很容易出错,部分原因是参考模型蒙皮不一致。 例如,在猫模型中,其中一个尾骨未用于蒙皮,这使我的脚本感到困惑。 这就是为什么上图中猫的尾巴的一部分缺失的原因。

我试图为这些边缘情况实施解决方法,以及各种手动指导脚本以获得每个生物的更好结果的方法,但是每个新的参考 3D 模型似乎都带有需要处理的新类型的怪癖。 在 2024 年恢复工作后,我有了这七个生物,它们的参考 3D 模型如下所示:

Seven generated creatures. Five of them have hand-crafted reference 3D models below.

(我丢失了两个原始参考 3D 模型——土狼和公麋鹿——因为它们是 Maya 格式。由于我没有安装 Maya,当触发项目重新导入时,Unity 无法导入这些模型,它们消失了。由于将 Unity 导入的数据(Library 文件夹)提交到源代码管理不是标准做法,因此我无法恢复它们。)

无论如何,到目前为止,我所有的努力都集中在通过可以插值的统一结构来表示不同的生物,但是我尚未在定义更高级别的参数方面取得进展。

自动参数化尝试失败

一旦我将重点转移到定义更高级别的参数,我尝试的第一件事是使用主成分分析 (PCA) (Wikipedia) 根据我的七个示例动物自动识别这些参数。 从技术上讲,它奏效了。 PCA 算法创建了七个参数的参数化,这是一个视频,我在其中一次操纵一个参数:

正如我所怀疑的那样,结果没有用,因为每个参数一次影响许多特征,并且有很多重叠,使得参数 没有意义

为什么它创建了七个参数? 好吧,当你有 X 个例子时,很容易创建一个具有 X 个参数的参数化来表示所有参数。 你基本上分配参数 1 来表示“来自示例 1 的贡献”,参数 2 来表示“来自示例 2 的贡献”,依此类推。 这本质上是加权平均值或插值。 虽然这与主成分分析所做的不完全相同,但就我的目的而言,它同样无济于事。 操纵参数仍然 感觉 更像是插值示例,而不是控制特定特征。

当我谈论“有意义的参数”时,我指的是我可以理解的参数——我可以在“角色创建器”中使用它来轻松调整生物的特征以达到我想要的结果。 例如,诸如:

但是,PCA 并非以这种方式工作。 它产生的每个参数一次影响许多特征,使得一次控制一个特征成为不可能。 我在学术研究项目 The SMAL Model 中遇到了同样的问题。 虽然这个项目比我能做的要复杂得多,并且基于更大的示例动物集,但他们基于 PCA 的参数模型(which you can try interactively here)也存在同样的问题。 即使它可以代表各种各样的动物,我也不知道如何调整参数来创建一个特定的动物,而无需过多的反复试验。

我也相信将现代 AI 扔给这个问题也行不通。 这不仅需要更多的示例模型(我没有)和 AI 训练专业知识(我没有兴趣获得); 它仍然无法解决根本问题:自动化过程无法理解哪些相关性和参数对人类有意义。

自动参数的另一个问题是,它们似乎不能保证有效的结果。 在试验我自己的 PCA 设置或我链接到的 SMAL Model 时,很容易遇到产生变形故障模型的参数组合。 找到有意义的参数的一部分是弄清楚它们有意义的范围是什么。 例如,参数“尾巴根部的厚度”的范围可能从 0(最小尾巴厚度,如牛的尾巴)到 1(像鳄鱼或蜥脚类动物一样厚的尾巴)。

这确保了尾巴厚度不会意外地超过躯干。 这也意味着改变躯干厚度也可能影响尾巴厚度。 虽然这在技术上涉及“一次影响多个事物”,但它是以对人类(特别是对我)有意义且有意义的方式完成的。 自动化过程无法知道哪些“一次影响多个事物”的关系感觉有意义或任意。

手动参数化工作

在得出结论认为没有办法手动进行参数化之后,我开始编写一个具有高级参数的脚本,该脚本将产生低级参数(骨骼对齐和厚度)的值作为输出。

我复制了所有示例生物,因此现在有三行:原始参考模型,提取的生物(根据分析参考的蒙皮网格自动创建)以及我将尝试使用高级参数重新创建的新雕刻的生物。

Three rows of creatures.

最初,高级参数仅控制躯干厚度(水平和垂直)和锥度,而其他特征仍由提取的生物定义。 逐渐地,我扩展了高级参数的功能,确保结果不会与提取的模型相差太多——除非它们更接近参考模型。

为什么还要保留提取的模型,而不是直接与原始参考模型进行比较? 好吧,我仍然只使用拉伸的矩形,而且与高清参考模型相比,这种方法只能捕捉到这么多细节。 至少暂时而言,提取的模型提供了一个现实的目标来瞄准。

从那里开始,我朝着更多高级参数发展的方法是,并且仍然是:

  1. 逐渐识别示例生物中参数之间的相关性,并将这些相关性编码到生成代码中。 目标是通过将多个较低级别的参数组合为较少的高级别参数来减少参数数量,同时确保仍然可以使用这些较高级别参数生成所有示例生物。
  2. 随着参数越来越少且越来越高级,添加更多示例生物变得更容易,这为进一步研究相关性提供了更多数据。

只要滚动随机参数值仍然不会产生合理的结果,我就会重复这些步骤。

这是一个凌乱的进行中的工作:

为了帮助我发现参数之间的相关性,我编写了一个工具,该工具可以可视化所有参数对之间的相关系数,并在将光标悬停在特定对上时显示角落中的原始数据。 (在此视频中,该工具尚未显示所有参数类型,因此缺少很多参数。)

专注于体内关节的放置

在 2024 年,我将参数化的大部分重点都放在了生物体内关节的合理放置上。 例如,在所有有膝盖的生物中,膝盖关节的位置都比腿的后部更靠近腿的前部。 虽然膝盖的放置相当简单,但在具有截然不同比例的生物中确定臀部、肩部和颈部关节的放置被证明更具挑战性。

我的许多参考 3D 模型从外部看起来很合理,但从解剖学角度来看,它们的装配(关节的位置)值得怀疑且不一致。

Comparison of anatomy of cat 3D model with anatomical picture of a cat's skeleton.

各种动物的骨骼和关节的解剖参考图也经常不一致。 我可以找到狗、猫和马的多个角度的详细参考资料,但没有其他更多的东西。 例如,鳄鱼解剖结构的描述差异很大:有些显示颈部的脊柱居中,而另一些则将其放置在颈部的后部附近。

Comparison of four different reference images showing the skeleton within a silhouette of a crocodile. The spine in the neck is inconsistent across them.

所有这些不确定性意味着我一直在猜测关节的位置——无论是考虑过程化生成应该如何工作,还是在添加新的示例生物时。 我想一劳永逸地解决这个问题,这样我就不必担心了。

解决关节放置问题还可以简化添加其他示例生物的过程,因为我可以只专注于使它们“从外部”看起来正确,而无需担心关节放置问题。 最终,我确实在很大程度上解决了这个问题。 到目前为止,我已经建立了 106 个高级参数,可以控制所有 503 个低级参数。

加速创建其他示例生物

一旦关节放置大部分自动化,我就想出了一个主意,即使用梯度下降 (Wikipedia) 加速示例生物的创建。 我的目标是实现一个基于梯度下降的工具,该工具可以自动调整生物参数,以使生物与参考 3D 模型的形状相匹配。

令我惊讶的是,该方法实际上奏效了。 在下面的视频中,我创建的工具调整了生物的 106 个参数,使其形状与长颈鹿的轮廓对齐:

该工具的工作原理是(一次)从参考模型的多个角度以及(在迭代梯度下降过程的每个步骤中)从过程模型捕获轮廓。 它计算过程轮廓与参考轮廓的差异程度,并将此差异用作梯度下降的惩罚函数。

为了测量两个轮廓之间的差异,该方法从要比较的两个轮廓创建一个 Signed Distance Field (SDF)。 为了加快此过程,我使我选择的 SDF 生成器与 Burst 兼容(available here)。 对于轮廓边界附近的每个像素(距离值接近零的像素),该过程从另一个 SDF 中检索相应像素的距离值,以确定另一个轮廓边界在该点的距离。 惩罚函数将所有轮廓对中所有被测像素的这些距离相加,从而得出总体惩罚。

这解释了为什么在视频中,生长的腿是第一个改变的特征。 增加腿的长度一次减少了最多的距离惩罚。 之后,延长脖子的长度具有最大的影响。

值得注意的是,此过程无法正确获得长颈鹿的耳朵。 参考模型既有耳朵又有角,而我的生成器还无法创建角。 因此,旨在尽可能紧密地匹配轮廓的梯度下降过程使耳朵变得又大又圆,因此它们可以有效地兼作耳朵和角。 后来,我通过隐藏参考模型的角来解决了这个问题。

我还尝试了一种称为“Adam”优化器的标准优化方法,但是 results were not good。 最终,自动化过程并不完美,但它补充了我的手动调整,可以在一定程度上加速示例生物的创建。

到目前为止,我在 2024 年花了三个月的时间进行过程化生物生成,并开发了 11 个涵盖各种形状的示例生物。 我最终放弃了“提取的生物”,因为高级参数化和梯度下降工具的结合使它们不必要地成为中间步骤。

Eleven creatures.

但是,我还没有接近足够的高级参数化。 感到需要改变节奏,我决定将重点转移到生物的过程化动画上。

中场休息

在写这篇文章时,我意识到虽然我确信我还没有实现确保“参数的任何随机值都将始终创建有效生物”的目标,但我实际上还没有对其进行测试。 因此,我快速编写了一个脚本来为所有高级参数分配随机值。 这些是结果:

正如我所期望的那样,虽然有些结果看起来很酷,但大多数结果都不接近我的标准。 尽管如此,此随机化器可能会在将来证明有用。 它可以帮助我确定生成的哪些方面仍然不足以及原因,从而指导我进一步完善过程化生成。

无论如何,回到 2024 年发生的事情。

生物的过程化动画

在过程化动画方面,我的优势在于我于 2009 年撰写了关于 Automated Semi-Procedural Animation for Character Locomotion 的硕士论文,并附带了一个名为 Locomotion System 的实现。 这是基于修改手工制作的动画以适应任意路径和不平坦的地形。

甚至在此之前,早在 2002 年,当我 18 岁时,我就实现了完全过程化(预渲染)的动画。

在 2022 年夏天,我尝试基本上重新创建它,但是这次是实时和交互式的。 作为起点,我使用了我的 2009 Locomotion System,剥离了与传统动画剪辑相关的部分。 相反,我编写了代码来让脚只是沿着从一个脚步位置到下一个位置的基本弧线移动。 为了对其进行测试,我手动创建了一些带有各种腿部配置的程序员艺术“生物”。

在 2024 年,我恢复了这项工作,现在将其应用于我过程化生成的生物模型。

结果看起来有点不错,但是非常僵硬,并且该方法仅适用于迈小步。 正如我之前提到过的,对过程化的、类似 Mammals 的生物进行动画处理以使其看起来自然是一个艰巨的挑战:

即使以我的经验来看,这也很难,但是,嘿,我喜欢一个好的挑战。

我对过程化动画的方法纯粹是运动学的,依赖于正向运动学 (FK) 和逆向运动学 (IK)。 这意味着我编写代码来直接控制身体和肢体的运动,而不考虑驱动它们运动的力。 换句话说,没有涉及物理模拟,也没有涉及训练或进化算法(like this one)。

基于训练的方法对于运行时生成的生物是不可行的,而且坦率地说,我对追求它不感兴趣。 动画与游戏引擎物理系统交互的唯一方式是使用射线投射来确定脚步应放置在地面的位置。

爆笑场面接踵而至

顺便说一句,从事过程化动画的有趣部分之一是,正在进行中的工作通常看起来 goofy。 当我第一次将过程化动画应用于过程化生成的生物时,我不耐烦,并且在实现指定不同腿部相对于彼此的时间的界面之前就运行了它。 正如我在社交媒体上写道,“可能很难相信,但是此动画实际上是 100% 过程化的。

该系统本身已经支持腿部计时,因为它继承自 Locomotion System,在该系统中,计时是根据分析动画剪辑自动设置的。 但是,在修改后的完全过程化版本中,我还没有实现手动输入计时数据的方法。 一旦我这样做了,事情看起来就更加合理了,如上一个视频所示。

其他人对荒谬动画的评论有时会激励我创建更多愚蠢的动画,只是为了好玩。 “有人评论说,过程化的蜘蛛和过程化的狗注定要战斗,但实际上它们是朋友,它们是最好的伙伴,并且喜欢一起冒险。

大约在这个时候,我想通过将过程化动画与手工制作的动画直接进行比较来更好地评估我的过程化动画。 为此,我将过程化动画应用于从 Asset Store 购买的 3D 模型,并将其与这些模型附带的动画剪辑进行比较。

继续以愚蠢为主题,我第一次尝试进行这种比较时,出现了一个非常荒谬的错误,以至于它成为我在 Twitter、[Bluesky](https://blog.runevision.com/2025/01/<https:/bsky.app/profile/runevision.bsky.social/post/3lb3ci