1:I["d9f27c132951",[],"Layout",1] 2:I["37eafacc3f00",[],"Outlet",1] 3:I["37eafacc3f00",[],"UNSAFE_WithErrorBoundaryProps",1] 4:I["d9f27c132951",[],"ErrorBoundary",1] 5:I["11eb051da520",[],"ThemeSwitch",1] :HL["/assets/root-Bnzpi1uE.css","stylesheet"] 0:{"type":"render","basename":"/","clientVersion":"$undefined","routeDiscovery":{"mode":"lazy"},"actionData":null,"errors":null,"loaderData":{"root":null,"blog":null,"blog-page":null},"location":{"pathname":"/blog/pages/2","search":"","hash":"","state":null,"key":"default","mask":"$undefined"},"formState":"$undefined","matches":[{"clientAction":"$undefined","clientLoader":"$undefined","element":[[["$","link","css:/assets/root-Bnzpi1uE.css",{"rel":"stylesheet","precedence":"vite-rsc/importer-resources","href":"/assets/root-Bnzpi1uE.css","data-rsc-css-href":"/assets/root-Bnzpi1uE.css"}],"$undefined"],["$","$L1",null,{"children":[[["$","link","css:/assets/root-Bnzpi1uE.css",{"rel":"stylesheet","precedence":"vite-rsc/importer-resources","href":"/assets/root-Bnzpi1uE.css","data-rsc-css-href":"/assets/root-Bnzpi1uE.css"}],"$undefined"],["$","$L2",null,{}]]}]],"errorElement":[[["$","link","css:/assets/root-Bnzpi1uE.css",{"rel":"stylesheet","precedence":"vite-rsc/importer-resources","href":"/assets/root-Bnzpi1uE.css","data-rsc-css-href":"/assets/root-Bnzpi1uE.css"}],"$undefined"],["$","$L1",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{}]}]}]],"handle":"$undefined","hasAction":false,"hasComponent":true,"hasLoader":false,"hydrateFallbackElement":"$undefined","id":"root","index":"$undefined","links":"$undefined","meta":"$undefined","params":{"index":"2"},"parentId":"$undefined","path":"","pathname":"/","pathnameBase":"/","shouldRevalidate":"$undefined"},{"clientAction":"$undefined","clientLoader":"$undefined","element":[["$","$L5",null,{}],["$","$L2",null,{}]],"errorElement":"$undefined","handle":"$undefined","hasAction":false,"hasComponent":true,"hasLoader":false,"hydrateFallbackElement":"$undefined","id":"blog","index":"$undefined","links":"$undefined","meta":"$undefined","params":"$0:matches:0:params","parentId":"root","path":"blog","pathname":"/blog","pathnameBase":"/blog","shouldRevalidate":"$undefined"},{"clientAction":"$undefined","clientLoader":"$undefined","element":"$L6","errorElement":"$undefined","handle":"$undefined","hasAction":false,"hasComponent":true,"hasLoader":false,"hydrateFallbackElement":"$undefined","id":"blog-page","index":"$undefined","links":"$undefined","meta":"$undefined","params":"$0:matches:0:params","parentId":"blog","path":"pages/:index","pathname":"/blog/pages/2","pathnameBase":"/blog/pages/2","shouldRevalidate":"$undefined"}],"patches":"$@7"} 7:[{"clientAction":"$undefined","clientLoader":"$undefined","handle":"$undefined","hasAction":false,"hasComponent":true,"errorElement":"$undefined","hasLoader":false,"id":"blog-index","parentId":"blog","path":"$undefined","index":true,"links":"$undefined","meta":"$undefined"},{"clientAction":"$undefined","clientLoader":"$undefined","handle":"$undefined","hasAction":false,"hasComponent":true,"errorElement":"$undefined","hasLoader":false,"id":"blog-post","parentId":"blog","path":":id","index":"$undefined","links":"$undefined","meta":"$undefined"}] 8:I["4d29546c44ff",[],"PrefetchCurrentRoute",1] 9:I["ba0f37e54449",[],"BackButton",1] d:I["37eafacc3f00",[],"Link",1] e:I["45dc6c57fe5c",[],"default",1] 6:["$","main",null,{"className":"mx-auto max-w-2xl px-5 pt-20 pb-16 sm:pt-24","children":[["$","title",null,{"children":"Blog · 第 2 页"}],["$","$L8",null,{}],["$","$L9",null,{}],["$","header",null,{"className":"mb-8","children":[["$","h1",null,{"className":"text-3xl font-bold tracking-tight","children":"Blog"}],["$","p",null,{"className":"mt-2 text-sm text-muted-foreground","children":["共 ",13," 篇文章"]}]]}],["$","div",null,{"className":"flex flex-col gap-8","children":[["$","section","2025",{"aria-label":"2025 年","children":[["$","h2",null,{"className":"border-b pb-2 text-sm font-medium text-muted-foreground tabular-nums","children":2025}],["$","ul",null,{"className":"divide-y","children":["$La","$Lb","$Lc"]}]]}]]}],["$","nav",null,{"aria-label":"分页","className":"mt-10 grid grid-cols-3 items-center border-t pt-6 text-sm","children":[["$","div",null,{"children":["$","$Ld",null,{"to":"/blog/pages/1","prefetch":"intent","className":"flex items-center gap-1.5 rounded-md text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring","children":[["$","$Le",null,{"ref":"$undefined","icon":{"name":"arrow-left","size":24,"node":[["path",{"d":"m12 19-7-7 7-7","key":"1l729n"}],["path",{"d":"M19 12H5","key":"x3x0zl"}]]},"className":"size-4"}],"上一页"]}]}],["$","span",null,{"className":"text-center text-muted-foreground tabular-nums","children":[2," / ",2]}],["$","div",null,{"className":"flex justify-end","children":false}]]}]]}] f:Td0d,书接上回,PFNN是一种动态调整网络参数的一种motion生成模型,它在运行时根据当前的角色状态的Phase,来调整网络参数。调整方法是将Phase映射到一个周期样条函数,其输出为网络的参数。同时作者也提出,调整方法也可以是网络。那么这篇导读就是一个初步的尝试。 背景 MANN,全称“Mode-Adaptive Neural Networks for Quadruped Motion Control”。从标题上看,这是一种模式适应的生成网络,用于生成四足运动。 这篇文章和PFNN的主要不同是,动态更新网络参数的方法变为使用一个网络来调整,称为gating network。 其次研究对象变为了四足运动,相比于双足运动,其复杂度和多变性更大。由此引出了一些问题: 如何定义四足运动的Phase? gating network是何物? 首先是第一个问题,在PFNN中,Phase的定义是比较简单的,将左右脚着地的信号映射到 上,这么做的原因是PFNN的研究对象是human locomotion,更具体的说是很简单的人类移动。如果套用PFNN的方法,我们是很难定义四足动物的运动的Phase。比如MANN的具体对象是狼,它的locomotion的pattern相比于human locomotion更为复杂。如下图所示,同一类别的运动,四肢着地的方式就有四种不同(可能不止),同时某些肢体的着地时间还有交叠,这使得我们更难去定义Phase。 这里作者给出的方法是,用部分的肢体信息去隐式地表示Phase,让网络去学到这其中的”奥妙“。 对于第二个问题,其实比较好解释,如果还记得 中的Phase Function,那么这个gating network就是Phase Function。一样是在运行时调整生成网络的参数。如果小伙伴读过其它论文的话,有一个东西很像gating network,就是hyper network。 Overview 整个Pipeline如上图所示。其生成网络的输入与PFNN大同小异。同时使用了CCD full-body反向动力学来调整四肢与地面的接触,减少artifact。下面主要讲一下gating network Gating Network MANN 区别于 PFNN 的最主要不同点就是,计算 Blending 因子的方式。在这篇论文中,作者使用 gating network 来预测 blending 因子。相比于人为定义一个确定的函数计算,用网络的方式能生成更好地生成合适地 blending 因子。gating network 的输入 是生成网络输入的一个子集,包括 , 当前帧的动作类型(取路径窗口的中点) , 当前帧的期望速度大小(取路径窗口的中点) , 四只脚的速度 作者还尝试过向 gating network 中输入整个生成网络的输入 x,四脚的位置,或者是四脚的位置 速度朝向。发现这些都能分别生成不错的结果。其中的原因可能是因为,接触点的速度和 Phase 之间具有很强的关联。 而它的的输出就是我们在 PFNN 中详细介绍过的 blending 因子了,它会将专家权重 进行加权求和,得到最终用于生成动作的网络 总结 通过运行作者release的源码可以感觉的到,狼的运动的效果是很不错的。 这篇文章和 PFNN 在生成动作的思想上并没有很大的不同,同时 gating network + motion prediction network 的架构的引入,奠定了后面几篇文章的动作生成架构。 a:["$","li","PGINmXZt7r",{"className":"$undefined","children":["$","$Ld",null,{"to":"/blog/PGINmXZt7r","prefetch":"intent","className":"group -mx-3 grid gap-1 rounded-lg px-3 py-5 outline-none sm:grid-cols-[5rem_1fr] sm:gap-6 focus-visible:ring-2 focus-visible:ring-ring","children":[["$","time",null,{"dateTime":"2025-05-02T04:11:12.402Z","className":"text-sm text-muted-foreground tabular-nums sm:pt-1","children":"5月2日"}],["$","div",null,{"className":"min-w-0","children":[["$","h3",null,{"className":"text-lg leading-snug font-semibold tracking-tight decoration-muted-foreground/50 underline-offset-4 group-hover:underline","children":"⚓{0x02} MANN导读"}],["$","p",null,{"className":"mt-1.5 line-clamp-2 text-sm leading-relaxed text-muted-foreground","children":"$f"}],false]}]]}]}] 10:Td14,在一系列的努力操作下,我终于能读到心心念的计算机图形学了。但不得不说,我找导师的时间确实太晚了,应该在通知拟录取的时候就开始找老师了(其实最好就是在你准备考研的时候,去联系心仪的导师)。不过怎么说,现在算是稳定下来了。 刚到实验室,研究所给了台还算一般的工作站,双路E5-2670(垃圾佬u),Quadro M5000,64GG DDR4。普通的STAT固态硬盘,这就有点拉了,以后遇到IO瓶颈再升级。总的来说炼点小丹不在话下。 就我的一向习惯,在拿到一台机子的时候,首先就是全盘格式化重装一边Windows 11,然后才开始配置环境。主要是避免一些前任留下的奇怪问题。下面主要分三个部分讲,系统环境、编程环境、科研工具。这篇文章也算是一个记录,用于统一以后不同电脑的环境,打造家的味道。 系统环境 首先就是登录巨硬的账号,主要是可以自动同步一些Windows 11的设置。接下来就是进入正题了。 墙🔨 总得看看更广阔的世界,是吧(逃 这里使用Clash-Windows作为自己搭好的梯子的前端,选用它有两点原因:界面好看、支持多种不同协议的代理。至于如何搭建梯子,在这就不赘诉了。 WSL2 这里因为安装的是 Windows 11 所以可以直接根据下面的流程安装 WSL2 控制面板—>程序—>查看方式:大图标(在界面的右上角)—>程序与功能—>启用或关闭 Windows 功能—> 勾选Hyper-V和适用于 Linux 的 Windows 子系统—>确定,然后重启电脑 这里使用yuk7/ArchWSL作为我们的 wsl 系统。首先在仓库的 Release 中下载 Arch.zip,然后解压到一个具有权限的文件夹中,这里最好是解压到速度最快的硬盘(毕竟是系统、吃4K随机存储的速度),这里假设路径是path/to/arch 然后在path/to/arch中运行Arch.exe,这里建议安装好后添加一个新用户,然后运行在此目录下打开 cmd 运行命令Arch.exe config --default-user username,把username换成刚刚创建的用户名。最后在给他root的权限,以方便安装 package 最后运行wsl --update和wsl --set-default-version 2和wsl --set-version Arch 2来将 Arch Linux 升级成 wsl2 在先版本的Windows 11下的WSL2,可以支持Linux的图形界面功能,同时还可以在WSL2侧调用GPU,这也是在WSL2下使用GPU进行炼丹的必要条件。 在WSL下调用cuda,则需要安装最新的显卡驱动,以及在wsl侧安装cuda,这里可能会出现一个链接错误: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link 解决方法则是按照这条评论解决。 编程相关 VS Code 作为宇宙扩展性第一的编辑器,把它弄成一个好用的IDE通常需要自己慢慢调插件。我这里安装了如下插件: One Dark Pro(对眼睛最好的主题) GitLens(团队协作扯皮必备,点一下blame,直接找出代码中的💩是谁拉的,大概率是自己拉的) C/C++,CMake,CMake Tools,C++ TestMate(写C++必备) LaTeX Workshop(搞学术必备) TabOut(按 Tab 可以跳出括号,非常方便) Python,Pylance(用于Python开发,后者是更强大的language-server) Remote-SSH(用于远程SSH开发) WakaTime(记录写代码的时间) b:["$","li","KcpJdsp6vE",{"className":"$undefined","children":["$","$Ld",null,{"to":"/blog/KcpJdsp6vE","prefetch":"intent","className":"group -mx-3 grid gap-1 rounded-lg px-3 py-5 outline-none sm:grid-cols-[5rem_1fr] sm:gap-6 focus-visible:ring-2 focus-visible:ring-ring","children":[["$","time",null,{"dateTime":"2025-05-02T03:55:39.159Z","className":"text-sm text-muted-foreground tabular-nums sm:pt-1","children":"5月1日"}],["$","div",null,{"className":"min-w-0","children":[["$","h3",null,{"className":"text-lg leading-snug font-semibold tracking-tight decoration-muted-foreground/50 underline-offset-4 group-hover:underline","children":"⚓{0x00} 工欲善其事,必先利其器"}],["$","p",null,{"className":"mt-1.5 line-clamp-2 text-sm leading-relaxed text-muted-foreground","children":"$10"}],false]}]]}]}] 11:T1223,背景 在角色动画领域中,骨骼的动画是最重要的一种动画,一般称之为motion。受动物运动的启发,人们将角色动画简化为两步,骨骼的姿势变化(骨骼动画),以及皮肤受到骨骼的变化而变化(蒙皮)。 本文所介绍的这篇文章则是研究如何利用深度学习来生成和控制骨骼动画。生成的骨骼动画的好坏可以由下面几点来评判: 动画是否连续 动画是否自然 第一个点是最基础的,它限定骨骼的姿势变化不能太大,比如角色正在跑步,下一帧的骨骼姿势不应该突然变成非跑步姿势(比如站立)。那么这一点就可以基本上决定了这类生成模型大体都是自回归模型,那么就需要考虑误差累积的问题,减少误差累积有很多方法,有些方法还是场景特点的,在这就不一一介绍。 第二个点就比较主观,好在我们在使用深度学习研究时,一般是有数据集的,而数据集大都采自真实世界,我们可以设计一些距离函数来评判生成的动画是否和ground truth足够接近,从而来评判生成的动画是否自然。 此外为了加入控制,我们会在自回归的途中对输入进行一定的修改,以达到控制生成的动画。因此大致的流程可以由下图表示 在我们所讲的这篇文章中,有两个主要的工作: 为动作捕捉数据生成虚拟的地形,这是由于动作捕捉设备只捕捉人体mark点的空间运动,并不会扫描动捕场景的地形,因此需要为虚拟场景生成与动捕数据对应的地形。 提出所谓的Phase-Functioned Neural Network,即PFNN来生成自然的locomotion。 前者工作属于数据增强的方法,其大致思路是:根据现有的虚拟场景高度图,切割出大量地块,然后将这些地块去fit每个locomotion,选出最匹配的地块,之后再微调这些地块的高度,让其更匹配locomotion。这个方法比较暴力,论文中介绍了三种误差来表示地块和locomotion的匹配程度,这里不再赘述。 PFNN 上图就是PFNN的模型示意图,分成两个部分: 生成网络,即左侧的MLP, 用于动态调整MLP参数的一个模块——Phase Function。 现在我们先来看左半边的网络,即 motion 的生成网络。它的结构比较简单,由三层全连接层组 成,隐藏层的输出由 ELU 激活。 在讨论网络的输入输出之前,我们先整理一下需求是什么: 生成下一帧的 Pose,即关节点的位置, 能够有一定的控制,即控制角色的运动方向、运动速度、以及运动的形态(gait), 能够适应具有地形的场景,而不是一个平地场景。 现在我们可以开始说明输入输出的具体设计 网络输入 对于第 帧的motion生成,输入如下 在平面上的路径信息,我们一般通过这几个量来控制角色的运动。这些量也是定义于根节点空间 , 路径位置 , 路径方向 , 步态(gait), 包括走路、慢跑、奔跑、蹲伏走、跳跃。one hot 编码。 关节信息,定义于第 帧根节点的坐标系下,其中 $j$ 表示关节数 , 关节位置 , 关节速度 , 路径上的地形高度。由于场景是具有地形的,我们将路径投影到地形高度图,得到路径的高度。为了让网络能够感受到周围地形的变化,还在路径两边额外取了两个点。 在上面的路径信息一共有 个样点,这 个样点来自如下图所示的一个大小为 2s 的窗口。这个窗口的前半部分是历史路径信息,而后半部分由网络预测得出。当没有玩家控制时,网络就会沿着它的预测自回归地生成运动。当要控制角色的运动时(test阶段),我们就可以使用玩家的控制值来混合这个窗口。下图表示第i帧的控制混合,并作为网络的输入。 网络输出 我们需要的必要信息就是网络的输出。显然它包括下面几部分: 姿势信息,也就是关节的朝向,速度等, 路径信息,如之前所述,这是一个网络预测角色运动的信息窗口 相位更新,或者说,相位的增量 当得到网络输出后,我们就可以更新角色的状态,以及准备下一帧的网络输入。 损失函数 一个直觉的想法,我们需要网络能够完美的预测实际的motion,也就是说在训练过程中,我们需要网络的输出能够匹配上数据集中的motion。因此,Loss是一个欧式距离,且包含一个正则项。对于这类motion的预测生成模型,欧式距离基本都作为Loss的主要项。 Phase c:["$","li","fs3wXp3Wkn",{"className":"$undefined","children":["$","$Ld",null,{"to":"/blog/fs3wXp3Wkn","prefetch":"intent","className":"group -mx-3 grid gap-1 rounded-lg px-3 py-5 outline-none sm:grid-cols-[5rem_1fr] sm:gap-6 focus-visible:ring-2 focus-visible:ring-ring","children":[["$","time",null,{"dateTime":"2025-05-02T03:46:33.956Z","className":"text-sm text-muted-foreground tabular-nums sm:pt-1","children":"5月1日"}],["$","div",null,{"className":"min-w-0","children":[["$","h3",null,{"className":"text-lg leading-snug font-semibold tracking-tight decoration-muted-foreground/50 underline-offset-4 group-hover:underline","children":"⚓{0x01} 关于PFNN一些看法"}],["$","p",null,{"className":"mt-1.5 line-clamp-2 text-sm leading-relaxed text-muted-foreground","children":"$11"}],false]}]]}]}]