【游戏引擎之路】登神长阶(十七):Humanoid动画——长风破浪会有时,直挂云帆济沧海

发布于:2025-07-17 ⋅ 阅读:(11) ⋅ 点赞:(0)

游戏引擎开发记录:

2024年 5月20日-6月4日:攻克2D物理引擎。
2024年 6月4日-6月13日:攻克《3D数学基础》。
2024年 6月13日-6月20日:攻克《3D图形教程》。
2024年 6月21日-6月22日:攻克《Raycasting游戏教程》。
2024年 6月23日-7月1日:攻克《Windows游戏编程大师技巧》。
2024年 7月2日-7月6日:攻克《雅达利2600汇编游戏开发》。
2024年 7月7日-7月11日:攻克《x86/x64汇编语言》。
2024年 7月11日-7月22日:学习《3D游戏编程大师技巧》(阶段性)。
2024年 7月14日-7月18日:学习《游戏引擎架构》(完成)。
2024年 7月23日-7月30日:攻克Python语言学习。
2024年 7月31日-8月5日:攻克《3D游戏编程大师技巧》。
2024年 9月10日-9月20日:攻克游戏动画绑定
2024年 10月27日-10月31日:攻克《C++大师教程》
2024年 10月21日-11月02日:攻克《DirectX11教程》
2024年 11月02日-11月06日:攻克《CMake教程》
2024年 11月06日-11月10日:攻克《Vulkan教程》
2024年 11月11日-11月13日:攻克《OpenGL教程》
2024年 11月14日-11月29日:攻克《DirectX12龙书》
2024年 11月29日-2025年1月16日:《心火引擎》基础渲染部分,UI,基础游戏框架
2025年 1月16日-2月12日:载入骨骼部分。能够使蒙皮骨骼,动画载入。但有诸多问题。
2025年 2月19日-3月8日:制作了完整的小哪吒模型。自已的引擎,必须要自已建模适配。
2025年 3月10日-3月23日:制作骨骼动画,面对各种问题,各种崩溃,无法解决。
2025年 3月24日-3月27日:攻克《Lua教程》。把LUA加入引擎解决c++编译时间问题。
2025年 3月28日-4月11日:进行Maya的学习。掌握了Maya软件。
2025年 4月14日-4月19日:宁可碎此身,终不起此座!终于完美解决动画问题。
2025年 4月19日-5月30日:制作Humaniod动画。(史上最难)


(一)引子

也不知道是不是之前的节奏太快,还是消耗尽了我的洪荒之力,其实这个日志应该在六月份写的,现在写的时候已经是7月16日了。7月前半月的净工作时间是80小时,但其实工作的效率连40小时都不到,因为丢失了专注力。7月初因为抑郁症发作崩溃了。

其实我在6月的时候还信心满满,我6月结束的时候一篇总结就是我如何“战胜”了抑郁症。因为6月净工作时间300小时,没有任何水分,全是高强度工作,结果7月初因为牙痛,有一天晚上痛到根本睡不着,然后接下来几天节奏崩溃,然后再休息几天,就“一病不起”,直到现在才缓过来。

我感觉现在的我就和红军过雪山草地一样,我小学的时候学到的,你在这个过程之中,无论走得多慢,千万不能停,如果停下来休息,就再也没有站起来的机会了。小时候我对这个事情印象深刻,但也有一丝不理解,为什么?停下来休息一下,为什么就起不来了呢?对于这个东西的深层机理我现在仍然不明白,但是我知道,经验上就是如此。

入夏了我也去游泳了。我们这边游泳池居然有一个90岁的老人,他老婆也80多了,真是高寿啊。这么大年纪也还能游泳,而且他游泳永远不停,虽然游得很慢,但基本上不会休息。要知道我去的游泳池是我们这边的军队训练基地,不知道为什么,巨长无比,是一般的两倍,应该有100米长。我都只能游一半(除非是狗刨式)。

其实对于“力衰”的人,少量但持续的前进是最好的。抑郁症患者就属于“精神力衰”的情况。我现在周六周日也不会休息,这不是我工作多么积极,多么变态,而是这样是最好合理利用精力的办法。如果我周末躺上两天,人基本上就废了。


(二)Humaniod动画

这个技术是骨骼动画的印射技术,也就是将一个骨骼上面的动画,投射到另外一个骨骼上面去。在Unity里面叫Humanoid动画,其实不一定是叫这个名称,但是因为我以前是学Unity的,所以在我的引擎里面,也延长这个名称,应该不会有专利的问题吧?

其实现代的人引擎使用者,不太理解这是一个什么东西,因为最流行的Unity的UE引擎天生支持骨骼动画的印射。现在的独立游戏开发者一开始就会用上这个技术,他们就会觉得,只要下载了一下动画,那当然所有的模型都能用,这不是天经地义的吗?

其实不然,在正常的情况下,一个骨骼的动画只能他自己使用。如果换给其它骨骼使用,就会出各种问题。

我最初尝试了一下最简单的骨骼印射,就是只将动画的名称改了,修正一下主轴的旋转,发现根本不行,得到的是一个崩溃的项目(其实后来我知道了,因为我的主模型的问题,其实如果我换一个其它的主模型,这样还行得通)。

其实我一开始打算不要钻牛角尖,因为我通过一段时间的学习,现在我能够自己做动画,而且我以后的主角和BOSS都会自己做动画,那么Humanoid的需求不是那么大。

可是后来我发现我需要做一个简单的动作系统,我现在暂时还不想自己做动画,因为我要先做出系统来,我去mixamo上面找动画,却发现只有行动的动画,攻击动作几乎没有。

综合考虑之后,我决定还是把这个技术攻克下来,毕竟我之前在Unity上可是买了一大堆的动画,加起来可是有一千多刀乐,算是我的一笔“大投资”,这些动画很多都质量很高,不用起来可惜了。关键是如果没有这个技术,以后那些小兵难倒也要每个做动画吗?所以想想看,这个Humanoid技术实用性实在太强了。

 

(三)最艰难的挑战

其实光是骨骼动画就已经够难了。但是我在Humanoid动画中遇到的挑战更难。最关键的问题就在于骨骼的异形。

骨骼动画其实说起来原理很简单,就是从根节点一路构建矩阵,然后能够播放动画。对的,原理其实就这么一句话,我当时学教程,用m3d的模型做,只要一天就把动画搞定,觉得好像没那么难嘛。

但实在没有想到这个过程中任何一个东西都是难点,其实到最后实现的代码也很简单,不超过100行,但你要越过这些各种各样异常的东西,其中任何一个环节出错都会导致异常,这就是最麻烦的。

而Humanoid更有甚之。

我最初找到了一个非常完整的,在csdn上面的骨骼动画印射攻略,其中的公式就是:

a2 - a1 = b2 - b1

原理就是其中a1是A骨架的参考姿势,b1是B骨架的参考姿势,动画中某一帧的姿势是a2,我们想得到的结果是b2,我们认为,a2与参考姿势a1的差异应当和b2与其对应的参考姿势b1的差异相同。

由此推导公式就是:

b2 = a2 - a1 + b2 = a2 + (b1 - a1)

以上引用自csdn文章《动画重定向技术分析及其在Unity中的应用》。

其实这个公式在原则上没有问题,但是不知道为什么,我在我的引擎中使用却导致骨骼崩溃了。只有我下载到的两个最相似的模型,一个Female一个Male,都是一个动画系的模型,这两个模型之间能够使用。但我平时用的主模型精灵Elf中却导致动画崩溃。

这几乎让我也崩溃了。


(四)工欲善其事,必先利其器

我反正怎么想也不对,中途一度打算放弃了。后来折腾了两天其它的,然后感觉斗志又恢复了,劳资就是不服输,王候将相,宁有种乎?

然后我就开始开发粒子系统。这粒子系统本来我是想之后开发的,但现在为了制作动画,先搞一个丐版的东西出来。因为我的引擎是自己的引擎,当时什么辅助的功能都没有,只能靠打印,但这打印出来的东西是纯数学,实在太反直觉了。

然后我开发了粒子系统(这严格来说不能算粒子系统,只是一个能够绘制点线Mesh的多实例绘制系统),但也算一个粒子系统雏形。然后我就能够绘制骨骼,这样,就能够通过直觉知道哪个地方的骨骼变换错了。

然后我做出这个系统之后,赫然发现我的Elf是一个异形骨骼。这个到底怎么解释呢?

我们用2D环境来说明更容易,假设有A,B,C三个骨骼。骨骼是自带有旋转和位移两个属性,骨骼一般都不缩放,所以缩放可以忽略(但计算中是要计算的)。

假如根骨骼A是在[0,0]位置,而B骨骼向上1米,在[0,1]位置。两个东西都不旋转,这属于最简单的一个位移骨骼。然而,其实真实骨骼创建的时候并不会这样,不然你用Maya或者Blender去创建一个骨骼,根骨骼在[0,0]的位置,下一个骨骼向上1米,它其实会将根骨骼旋转90度,然后再进行[1,0]的位移。

所以说,在你的视觉里面,好像是根骨骼在[0,0],B骨骼在[0,1],两个骨骼都没有旋转,然后就完了。然而,实际上是根骨骼位置是[0,0],旋转是[90,0],B骨骼是[1,0],因为旋转之后,轴向也变了,本来B骨骼是向Y轴延伸一米,但是因为根骨骼是在X轴旋转了90度,所以向Y轴延伸一米,在B骨骼的本地坐标轴上,是延X延伸一米,这样才能匹配旋转。

然后在这里问题就来了,如果A->B->C三个骨骼,只有A旋转了90度,那如果你面对一个其它的骨骼,比如说A不旋转,或者旋转-90度,你只需要在根骨骼上进行一个旋转的动画匹配,这样就行了。但是,如果你的A骨骼旋转90度,然后B骨骼再旋转90度,然后C骨骼再旋转45度,那你怎么办?

如果你对于数学有一个直觉,你就知道,在坐标轴上看似一根直线的A[0,0], B[0,1], C[0,2],实际上根据旋转的不同,有无限多的组合。而且你在进行蒙皮骨骼绑定的时候,不管怎么样的数据,都可以正确得到结果,因为它只是违反直觉,而不是违反运算。

这东西就是“异形骨骼”。

我最初之所以使用Elf得不到正确的结果,就是因为Elf是一个异形骨骼。当我制作出骨骼粒子显示器之后,我才知道这骨骼异形得有多变态。

上面的正常公式在这种异形骨骼面前得到一个非常错误的结果,只有两个骨骼相似,而且不出现异形骨骼的状态下,才能够得到正确结果。

如果你是一个工作室,你可以要求工作室出品的每一个模型都按照规定制作,这样用简单的直接的算法也可以得到正确的结果,但对于独立游戏开发者来说,显然是没有这个奢侈的。

所以,这是一个必须解决的问题。


(五)数学的力量

但这前面是一片黑暗,我找不到任何文献讨论这方面的问题。为此我还下去下载了其它的独立游戏开源引擎,比如Anki3D什么的,希望在这些引擎里面找到一些骨骼动画支持的项目。但是我发现这些引擎要么就没说支持骨骼动画,要么就像Anki3D一样,翻开源码,对骨骼动画的支持居然还不如我。

我真是有点惊奇了。做游戏,操作角色,执行动画这不是一个游戏最基本的功能吗?这些引擎在干什么吃的?

你要说这些人水平不行也不是的,比如Anki3D,为了跨平台,他居然自己写了SIMD的数学库。其实简单的数学库我也不是不能写,我以前学《3D游戏编程大师》的时候,因为要使用软光栅,数学库当然只有自己来写。Vector,Matrix这些都是自己实现的。

但那时候我有一个优势,就是我不用太过注重性能,所以我只需要完成运算就行了。但显然Anki的数学库是一个性能非常优质的数学库。他都有能力写数学库了,为什么对于骨骼动画的支持如此贫瘠呢?

无论是文献也好,代码也好,我都找不到参考,没办法,只有自己推导了。还好我小时候数学学得也不差,我数学不算好的,就是能考80分那种(我那时满分100分),但也不差。我总觉得数学学那么多高深的东西有什么卵用?

事实上,这个看法算是对了一半。因为学的那些东西的确在之后的人生中根本没有卵用,全忘记完了。就比如说,我在学软光栅的时候,需要对于三角函数有直觉的理解,但是我那时候只记得cos和sin是边的比值,但sin是什么边对什么边我都记不住了。我小时候读书的时候还是能解题的,但是几十年不用,这些全忘记得干净。

于是我就翻出初中的课本,然后加上B站的教程,又重新学习三角函数,从初中的数学开始学。等于是重新学了一遍。然后我掌握了这些知识之后,才继续向前进步。

那你说这些知识有用吗?我20年都没用到,如果我不开发引擎,我做的是一般的游戏设计,可能也用不到三角函数,以前我做动作系统的时候,的确用到一些三角函数,比如说求夹角判断索敌范围,但我只需要套用公式就行,我不需要建立起直觉。我只需要哪个公式让我求出夹角,夹角是什么我还是有直觉的,但里面用的acos是什么我根本不知道,我只知道里面套这个公式就行。

但你要开发引擎了,这方面的直觉必须建立起来,不然寸步难行。但是,如果没有之前学习数学的基础,你需要一个人从0去领悟这些东西有多难?我并不知道,因为我没有经历过,也许对有些人来说不难,但是做为一个学过的人,我还是觉得当年学习数学有价值。因为它在你的思维中留下来数学思维的直觉。

就比如说,做引擎肯定得用c++,而我是学c/c++起步的,我11岁的时候就开始学c/c++了。后来因为工作的原因,我转到C#,再转到Java,回头到我学引擎的时候,我几乎30年没用过c/c++语言了,但是我一点也不怕,我拥有一种c/c++就是我的“母语”的信念。后来证明事实也是如此,我做引擎之前还是专门学习了c++,学了一个50小时的《c++大师教程》。当然,里面有些熟悉的内容我是跳过的。现在我用c++用起来如鱼得水,没有任何障碍。

但在那之前,我连public,继承,构造函数怎么写都忘记了。一边写还得一边问AI。可是慢慢地找了回来,颇有点像重伤之后的“康复训练”。

所以说,你说在学习编程的一开始学习c/c++有没有用?当然有用。如果没有这个基础,我甚至不会有想写引擎的念头。

说得太远了,回到数学的问题。我虽然找不到任何参考,但是我有一个信念,既然别人能够做到,我也能够做到。所有3D上面的问题,都是数学上的问题,那他必然可以通过纯数学的方式来进行解。

然后我就一边在草稿纸上做公式,一边去实验。终于给我研究出一套方式。也就是说,从t-pose的矩阵向最终的骨骼矩阵进行印射,再通过这个差值进行印射的思路。原来的公式只有A1A2等四个要素,我的印射需要8个要素,因为涉及到了t-pose。

我这时突然理解到为什么Unity需要t-pose做为骨骼动画的基础了。原来在CSDN上面的那个文章根本没有说到t-pose的价值。

其实将骨骼动画印射为t-pose也是一个技术难题,但是我不需要去解决这个难题,因为Unity拥有这个功能。

在这里,我突发奇想,大家想到Unity和Blender的时候,脑中浮现的想法是什么?是不是Unity是一个游戏引擎,Blender是一个工具?

但为什么Unity不能是一个工具呢?

所以在这里就把Unity当成一个工具,而这个工具就拥有将日常骨骼印射为t-pose的功能,我只需要编写一个插件,然后把Unity里面的t-pose数据打印为XML文档即可。

总而言之,我自己研究出了一个使用8个要素完成骨骼印射的功能。然后非常惊奇地发现非常好用。

之后也出现了很多其它的问题,比如说骨骼的方向导致骨骼扭曲的问题,因为RootMotion导致的悬空问题。因为之前有了我自己通过纯数学方式推导Humanoid算法的这一个过程,我发现解决这些问题都是“迎刃而解”。

这个挑战和实现基础动画的挑战还不一样。实现基础动画,其实最大的问题是“麻烦”,因为里面涉及的东西太多,一个环节出错,导致另外一个环节也出错。但说到底,整个过程没有太多的技术难题。

但Humanoid则完全不同,我找不到任何参考,只有通过自己的数学直觉来求解这个问题。直到我得到公式的时候,我才知道t-pose的价值。在这之前,我心中并没有这个“直觉”。

所以这个求解的过程让我觉得自己的思维和技术得到一个“升华”。虽然我不太想用这么装逼的词汇,但我真的这样感觉。

自从那以后,我感觉自己无所不能。

我已经无敌。


(六)无敌道心

做事情最重要的是相信你自己能够做到。以前金一南教程的“心胜”让我印象深刻,“心胜”说的是战胜对手有两次,第一次在内心中,第二次是在实践中。你要在实践中战胜对手,你必须在内心中先战胜对手。

以前我在和别人讨论《旷野之息》的时候,很多黑子就攻击我,因为在他们心中,任天堂就是无敌的,别人“抄都抄不来”,是无法被模仿的。当时我的理念,就是任天堂能做的,我们也能做。就是这么一个理念,让这些人像是肺管子被戳了一样,对我进行各种恶毒的攻击。

说实话,我个人也是任天堂的粉丝,我说任天堂能做的我也能做,这也不是针对任天堂。比如《战神》我也不止一次说要对标《战神》,我是对在座的其它游戏公司,游戏工作室也是一样的态度,你们外国人能做的,为什么我们中国人不能做?难倒中国人比外国人矮一截?

我之所以会投身于制作游戏引擎,就是因为我内心中有这样的“心胜”的信念。而这种信念,他会随着你在这条路上走得越远而变得越坚实。

他是你的能力与信念的融合体。而达到一个境界之后,会有一种玄奇的变化,而在修仙界,这就称之为“无敌道心”。

下一个日志,我将介绍我的这个“无敌道心”获得之后,一周就做出一个Galgame引擎的事情。


网站公告

今日签到

点亮在社区的每一天
去签到