[{"data":1,"prerenderedAt":2059},["ShallowReactive",2],{"blog-page-7":3,"blog-count":2058},[4,567,775,1287,1731],{"id":5,"title":6,"body":7,"date":544,"description":13,"extension":545,"meta":546,"navigation":549,"path":561,"seo":562,"stem":563,"tags":564,"__hash__":566},"blogs\u002F_legacy\u002F2020\u002F2020-10-25-kine-driver-note.md","辅助骨骼系统KineDriver笔记",{"type":8,"value":9,"toc":514},"minimark",[10,14,24,28,32,35,38,41,44,47,50,53,56,60,63,66,70,73,83,86,95,102,105,108,111,114,120,123,126,129,147,150,153,156,159,170,173,176,179,182,186,189,192,195,198,201,204,208,211,214,220,223,231,234,237,240,245,249,252,255,258,261,264,267,270,273,278,281,284,293,296,300,315,318,321,324,333,336,339,344,347,368,371,374,377,382,385,394,397,402,405,411,414,417,429,434,437,440,443,446,451,456,459,463,466,471,474,479,482,487,490,496,499,505,508,511],[11,12,13],"p",{},"这个是Square Enix在2019年分享的角色动画相关的笔记。",[11,15,16,17],{},"原文：",[18,19,23],"a",{"href":20,"rel":21},"http:\u002F\u002Fwww.jp.square-enix.com\u002Ftech\u002Flibrary\u002Fpdf\u002FCEDEC2019_KineDriver.pdf",[22],"nofollow","www.jp.square-enix.com\u002Ftech\u002Flibrary\u002Fpdf\u002FCEDEC2019_KineDriver.pdf",[25,26,27],"h2",{"id":27},"系统概要",[29,30,31],"h3",{"id":31},"辅助骨骼系统简介",[11,33,34],{},"辅助骨骼系统主要用于提升蒙皮动画的效果，其目的是为了提高骨骼动画的表现，所以并不与实际存在的骨骼完全对应。",[11,36,37],{},"在设计上，由骨骼进行驱动。通过骨骼的运动驱动数值，其结果不仅可以用于蒙皮动画的表现，也可以用于Shader和材质等特效。",[11,39,40],{},"因此，辅助骨骼系统并不仅是一个工作于资源制作环境下的工具，而是一个在资源制作和实际运行环境中同时存在，并且能够保证在两个环境下的运行效果一致性的系统。",[11,42,43],{},"这么做的好处主要有两个，首先，可以降低动画资源的大小，同时，还可以方便在运行时进行动态的调整。",[11,45,46],{},"版本历史上看，一开始是使用softimage的，后面换到了maya上，到3.0版本已经支持使用图形化界面来拖节点的编辑形式了。",[11,48,49],{},"由于提供了中间文件，可以方便的在各种引擎环境下运行，也能导入到MotionBuilder中，但是辅助骨骼的制作还是使用的Maya。",[29,51,52],{"id":52},"功能和概念",[11,54,55],{},"系统内共有三种控制器(operator)，source、target和constraint。",[57,58,59],"h4",{"id":59},"源和目标控制器",[11,61,62],{},"源控制器可以从多个骨骼获取需要的状态并对其进行插值混合。",[11,64,65],{},"坐标空间上，默认使用父节点作为local space的坐标参考，同时也支持指定其他骨骼作为坐标参照。",[67,68,69],"h5",{"id":69},"旋转表现",[11,71,72],{},"旋转表现有两种方式",[74,75,76,80],"ol",{},[77,78,79],"li",{},"Bend&Roll，将旋转分解到水平方向和竖直方向，方便美术理解",[77,81,82],{},"Expmap，使用四元数的对数，主要用于程序自动生成逻辑",[11,84,85],{},"对于Bend&Roll，在欧拉角的处理上有一些问题。首先，欧拉角在计算上具有一些复杂度，而且同一个状态所对应的欧拉角并不唯一，例如(0,90,60)和(-30,90,30)是同一个姿势。同时，在运行时通常引擎内部都是采用四元数的，将其转换回欧拉角时便无法保证能够回到预期的那个欧拉角。",[11,87,88,89,94],{},"因此最终采用了",[18,90,93],{"href":91,"rel":92},"https:\u002F\u002Fzh.wikipedia.org\u002Fzh\u002F%E7%90%83%E6%A5%B5%E5%B9%B3%E9%9D%A2%E6%8A%95%E5%BD%B1",[22],"球极平面投影","的方法，来对旋转角度中的水平角度进行处理。处理方式上，将起始位置的朝向分解为vx，vy和vz。将到达目标旋转vx'所需要的角度分解为θh和θv。详细的公式可以看图：",[11,96,97],{},[98,99],"img",{"alt":100,"src":101},"旋转转换","\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002F%E5%9C%96%E7%89%87.png",[11,103,104],{},"Bend&Roll在实际使用时，水平旋转和竖直旋转的应用顺序可以根据不同的骨骼进行配置，方便在使用时进行直观的理解。",[11,106,107],{},"Expmap则没有顺序上的问题，程序内部直接计算结果并进行控制。",[67,109,110],{"id":110},"缩放表现",[11,112,113],{},"缩放同样采用对数空间进行内部控制，采用对数是为了获得更大的精度空间，如下图所示：",[11,115,116],{},[98,117],{"alt":118,"src":119},"对数空间的优势","\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002F%E5%9C%96%E7%89%87-1.png",[11,121,122],{},"不过ppt里面说没有实装。",[67,124,125],{"id":125},"节点图支持",[11,127,128],{},"可以使用图形化的方式对控制器进行操作，主要提供了以下的节点：",[130,131,132,135,138,141,144],"ul",{},[77,133,134],{},"EZParamLinkLinear(线性插值)",[77,136,137],{},"EZParamLink(简单贝塞尔插值)",[77,139,140],{},"LinkWith(DrivenKey位置链接)",[77,142,143],{},"RBFInterp(支持多个输入输出的链接)",[77,145,146],{},"Expr(自定义表达式)",[11,148,149],{},"节点名和功能微妙的没有对上，但是原文就是这样的。",[11,151,152],{},"DrivenKey，查了下是maya的功能，就不详细的去看了。RBF后面有说明。",[57,154,155],{"id":155},"约束控制器",[11,157,158],{},"与节点图不同的，基于约束的控制器。",[130,160,161,164,167],{},[77,162,163],{},"Position：位置约束，可以基于多个源进行计算",[77,165,166],{},"Orientation：朝向约束，可以基于多个源进行计算",[77,168,169],{},"Dirction：让旋转指向目标，3点模式可以额外控制水平旋转",[67,171,172],{"id":172},"紧贴表面",[11,174,175],{},"约束控制器也提供紧贴表面的功能，根据Position和Orientation约束以及目标表面的骨骼权重进行计算。",[11,177,178],{},"在制作Bonamik的引导骨骼的时候经常用到。",[25,180,181],{"id":181},"工作流",[29,183,185],{"id":184},"maya中的资源制作","Maya中的资源制作",[11,187,188],{},"似乎是使用了maya的插件功能，节点图部分使用了C++的实现，导出和界面之类的功能使用了Python。",[11,190,191],{},"节点在显示时使用的是惯用的单位，在连接节点时会自动插入UnitConversion统一进行单位换算。",[29,193,194],{"id":194},"中间文件",[11,196,197],{},"中间文件采用xml的形式进行输出。",[11,199,200],{},"文件中保存了各种控制器的的节点的输出，以及节点之间的连接。",[11,202,203],{},"在进行文件输出时，可以指定缩放倍数，方便在使用不同单位的引擎中进行使用。",[29,205,207],{"id":206},"ue4插件","UE4插件",[11,209,210],{},"为了方便在项目中复用，进行了插件化。",[11,212,213],{},"模块构成，直接上图：",[11,215,216],{},[98,217],{"alt":218,"src":219},"image","\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb.png",[11,221,222],{},"使用上提供了两种方式",[74,224,225,228],{},[77,226,227],{},"动画节点：使用标准的动画控制流程，无法预览KineDriver的功能",[77,229,230],{},"Component版：作为SkeletonMesh的子组件，在tick中对骨骼进行更新，可以预览效果",[11,232,233],{},"提供了动画通知用于在动画的分段中关闭KineDriver。",[11,235,236],{},"对于与Bonamik的兼容关系，分开使用的时候会使用AddTickPrequist来决定调用顺序。另外似乎还有将KineDriver和Bonamik统合在一起的插件。",[11,238,239],{},"数据流程直接上图：",[11,241,242],{},[98,243],{"alt":218,"src":244},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-1.png",[57,246,248],{"id":247},"assetuserdata","AssetUserData",[11,250,251],{},"使用了AssetUserData进行数据的存储，方便在骨骼数据上直接添加和修改数据，通过引用指向具体的导入资源。",[11,253,254],{},"将数据放在骨骼上的好处是可以不必调整componnet的属性就直接对辅助骨骼的资源进行修改。",[57,256,257],{"id":257},"缩放传递",[11,259,260],{},"在Maya中，对骨骼的缩放不会传递到子骨骼。",[11,262,263],{},"而在UE4中则会进行缩放的传递，为了保持效果的一致性，在UE4中作了处理，对于TargetScaleOp的骨骼的子骨骼进行缩放的重新设置。",[25,265,266],{"id":266},"功能实装",[29,268,269],{"id":269},"表达式",[11,271,272],{},"提供基本的表达式支持，语法尽量的精简化了，不会使用for这些循环的语句。",[11,274,275],{},[98,276],{"alt":218,"src":277},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-2.png",[11,279,280],{},"主要使用一些内置的函数，同时添加对三维向量和四元数的支持。运算上支持了基本的四则运算和括号。",[11,282,283],{},"对于输入的参数，则转换到x1,x2,...,xn的形式进行记录。",[11,285,286,287,292],{},"在maya内部使用时，会将转换后的表达式使用[",[18,288,291],{"href":289,"rel":290},"https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002F%E8%B0%83%E5%BA%A6%E5%9C%BA%E7%AE%97%E6%B3%95",[22],"调度场算法","]进行转换和计算。如果要存储到中间文件的话，会将二进制代码转换为汇编语句的格式。各个游戏引擎加载时则重新将汇编语句转换为二进制代码。",[11,294,295],{},"之所以会用到表达式是因为有很多的分支需求，同时有的用几行表达式就能做好的事情用节点就要拖半天，所以需求也比较大。即便初期有预先设置很多功能节点，但是最后还是使用表达式具有更高的灵活性。",[29,297,299],{"id":298},"rbf插值","RBF插值",[11,301,302,303,308,309,314],{},"RBF总之就是一种拟合的方式，RBF本身可以参考[",[18,304,307],{"href":305,"rel":306},"https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002F%E5%BE%84%E5%90%91%E5%9F%BA%E5%87%BD%E6%95%B0",[22],"径向基函数","]，RBF插值可以参考[",[18,310,313],{"href":311,"rel":312},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRadial_basis_function_interpolation",[22],"Radial basis function interpolation","]。",[11,316,317],{},"这边有很大的篇幅中介绍这个算法的实现和原理，其实主要的目的是让插值变得更加平滑。",[29,319,320],{"id":320},"辅助骨骼自动生成",[11,322,323],{},"通过在特定姿态时美术已经调好的mesh状态，与完全没有调节的默认骨骼在这个状态的表现之间对比，自动的生成辅助骨骼。",[11,325,326,327,332],{},"使用了[",[18,328,331],{"href":329,"rel":330},"http:\u002F\u002Fgraphics.cs.uh.edu\u002Fwp-content\u002Fpapers\u002F2012\u002F2012_SA_SSDR_preprint.pdf",[22],"Smooth Skinning Decompostion with Rigid Bones","] ，简称SSDR。",[11,334,335],{},"主要的功能就是，对具有J个顶点的模型，使用N个形变示例动画，尝试生成D个骨骼来做一个蒙皮的操作。",[11,337,338],{},"由于很难同时对骨骼的位置和蒙皮的权重同时进行最优化处理，所以会分别进行十次来试图逼近最优解。",[11,340,341],{},[98,342],{"alt":218,"src":343},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-3.png",[11,345,346],{},"进行简单的列出",[348,349,350,353,356,359,362,365],"blockquote",{},[11,351,352],{},"a. 主骨骼没有调整的情况下，使用SSDR对权重进行最优化处理",[11,354,355],{},"b. 添加指定数量的辅助骨骼",[11,357,358],{},"c1. 使用SSDR进行权重最优化处理",[11,360,361],{},"c2. 暂时指定辅助骨骼的父骨骼",[11,363,364],{},"c3. 使用SSDR对辅助骨骼的位置进行最优化处理",[11,366,367],{},"d. 决定辅助骨骼的父骨骼，以及自动控制用的RBF插值设定。",[11,369,370],{},"其中c的步骤就是要执行10次的步骤。",[57,372,373],{"id":373},"添加指定数量的辅助骨骼",[11,375,376],{},"这个过程只会执行一次，但是其操作内部需要进行多次迭代才能完成。",[11,378,379],{},[98,380],{"alt":218,"src":381},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-4.png",[57,383,384],{"id":384},"蒙皮权重最优化",[11,386,387,388,393],{},"对一开始的公式中的[",[18,389,392],{"href":390,"rel":391},"https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002F%E4%BA%8C%E6%AC%A1%E8%A7%84%E5%88%92",[22],"二次规划","]中的w进行单独求解。",[11,395,396],{},"在整个过程中会多次使用到，虽然角标写的是SSDR。但是额外参考了Computer Graphics Gems JP 2015的向井老师的分享。在辅助骨骼的生成中，为了使得最优化的求解过程更加安定，进行了以下的优化：",[74,398,399],{},[77,400,401],{},"移除参考动画中的重复顶点",[11,403,404],{},"在对角色的姿态进行学习时，从单独的顶点来看会有完全没有移动的帧存在",[74,406,408],{"start":407},2,[77,409,410],{},"对骨骼进行合并",[11,412,413],{},"会出现对于某一个顶点而样，有多个骨骼的给出的变换结果相同的情况。此时对这些骨骼进行合并作为一个骨骼来计算，获得的最优化权重结果则按照原本的权重比例分散回去。",[57,415,416],{"id":416},"辅助骨骼的位置最优化",[11,418,419,420,424,425,428],{},"步骤c3，参考的还是上面的CGG JP2015的分享，同时参考了",[421,422,423],"span",{},"Horn 1987","以及",[421,426,427],{},"Mukai 2018","的缩放传递控制。",[11,430,431],{},[98,432],{"alt":218,"src":433},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-5.png",[11,435,436],{},"以点群为单位进行适配，来获得最佳的位置、旋转和缩放。",[11,438,439],{},"这里面原文是Transform，所以包含了Translation，Rotation和Scale。只是一时找不到合适的中文替代所以翻成了位置。",[57,441,442],{"id":442},"暂时指定辅助骨骼的父骨骼",[11,444,445],{},"步骤c2，这个步骤只有在使用了scale的计算时才会需要，在进行辅助骨骼计算时，为了计算的稳定性，是在本地旋转为0的情况下进行的。此时应用缩放会产生较大的误差，因此要暂时寻找到父骨骼并转换到骨骼空间之后再进行缩放处理，这个父骨骼可以随便找一个，主要的目的是为了将计算转换到骨骼空间去。",[11,447,448],{},[98,449],{"alt":218,"src":450},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-6.png",[11,452,453],{},[98,454],{"alt":218,"src":455},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-7.png",[11,457,458],{},"说实话还没有仔细看过计算过程，所以只是把自己的猜测描述了下。",[57,460,462],{"id":461},"决定父骨骼以及rbf配置","决定父骨骼以及RBF配置",[11,464,465],{},"最终的步骤d，计算出辅助骨骼以及其被主骨骼驱动的形式。",[11,467,468],{},[98,469],{"alt":218,"src":470},"\u002Fwp-content\u002Fuploads\u002F2020\u002F10\u002Fimage_thumb-8.png",[11,472,473],{},"生成辅助骨骼的自动控制总共有四个步骤：",[74,475,476],{},[77,477,478],{},"从蒙皮权重来寻找候补驱动者",[11,480,481],{},"从本辅助骨骼所驱动的顶点来寻找原本驱动这些顶点的主骨骼",[74,483,484],{"start":407},[77,485,486],{},"从候补驱动中寻找父骨骼",[11,488,489],{},"在所有的候补中寻找误差最小的",[74,491,493],{"start":492},3,[77,494,495],{},"从剩余的候补中选择RBF用骨骼",[11,497,498],{},"选择能够尽量覆盖RBF插值的1~2个骨骼",[74,500,502],{"start":501},4,[77,503,504],{},"RBF关键点修正",[11,506,507],{},"从没有关键点的情况下误差最大的地方开始插入关键点",[25,509,510],{"id":510},"总结",[11,512,513],{},"本来是从FF7的动画分享过来的，整个系统的原理其实还是挺清晰的。只是后面自动生成的部分使用了很复杂的计算逻辑，由于没有太过深入的打算，所以详细的公式以及额外引用的论文就没有去参考了，所以可能会有意思不明确的地方。",{"title":515,"searchDepth":407,"depth":492,"links":516},"",[517,524,532,543],{"id":27,"depth":407,"text":27,"children":518},[519,520],{"id":31,"depth":492,"text":31},{"id":52,"depth":492,"text":52,"children":521},[522,523],{"id":59,"depth":501,"text":59},{"id":155,"depth":501,"text":155},{"id":181,"depth":407,"text":181,"children":525},[526,527,528],{"id":184,"depth":492,"text":185},{"id":194,"depth":492,"text":194},{"id":206,"depth":492,"text":207,"children":529},[530,531],{"id":247,"depth":501,"text":248},{"id":257,"depth":501,"text":257},{"id":266,"depth":407,"text":266,"children":533},[534,535,536],{"id":269,"depth":492,"text":269},{"id":298,"depth":492,"text":299},{"id":320,"depth":492,"text":320,"children":537},[538,539,540,541,542],{"id":373,"depth":501,"text":373},{"id":384,"depth":501,"text":384},{"id":416,"depth":501,"text":416},{"id":442,"depth":501,"text":442},{"id":461,"depth":501,"text":462},{"id":510,"depth":407,"text":510},"2020-10-25","md",{"layout":547,"status":548,"published":549,"author":550,"author_login":552,"author_email":553,"wordpress_id":554,"wordpress_url":555,"date_gmt":556,"excerpt":557},"post","publish",true,{"display_name":551,"login":552,"email":553,"url":515},"风铃","flinkor","flinkor@foxmail.com",3087,"\u002F?p=3087","2020-10-25 13:24:15 +0000",{"type":8,"value":558},[559],[11,560,13],{},"\u002F2020-10-25-kine-driver-note",{"title":6,"description":13},"_legacy\u002F2020\u002F2020-10-25-kine-driver-note",[565],"Animation","TfXlUuRjzV9y-L1RkRFoOxZUtX1_A8Nk1XSHmiIagGE",{"id":568,"title":569,"body":570,"date":759,"description":574,"extension":545,"meta":760,"navigation":549,"path":769,"seo":770,"stem":771,"tags":772,"__hash__":774},"blogs\u002F_legacy\u002F2020\u002F2020-09-26-blender-plugin-note.md","Blender插件制作笔记",{"type":8,"value":571,"toc":750},[572,575,578,581,584,588,591,598,601,604,607,610,620,623,626,632,635,638,641,647,650,654,657,660,667,670,673,676,679,682,688,691,696,699,710,713,719,722,725,728,731,734,738,741,747],[11,573,574],{},"这里记录的都是Blender相关的，和Python基础错误关系不大。",[11,576,577],{},"当前的blender版本为2.83.5 。",[11,579,580],{},"暂时打算停留在lts版本上，主干的开发速度太快了，跟不上节奏",[11,582,583],{},"blender的api文档有些难以查询，有的时候想要特定的功能反而直接求助于搜索引擎比较快……",[25,585,587],{"id":586},"ui禁用","UI禁用",[11,589,590],{},"对于有些UI需要禁用而不是不绘制的，直接操作UI的enabled属性就可以了。",[11,592,593,594],{},"UILayeout相关的文档可以在这里看到：",[18,595,596],{"href":596,"rel":597},"https:\u002F\u002Fdocs.blender.org\u002Fapi\u002Fcurrent\u002Fbpy.types.UILayout.html",[22],[25,599,600],{"id":600},"类型注册",[11,602,603],{},"所有的blender相关的类型必须经过register_class才能使用，要留意在插件解除注册的时候同时unregister_class。",[11,605,606],{},"对于需要注册的属性也同样，属性可以注册在Object上，这样每个物品都会有。注册在Scene上的属性只有Scene会有。",[11,608,609],{},"从别人的插件里面看到，把class放到一个列表里面统一操作的方式比较好：",[611,612,617],"pre",{"className":613,"code":615,"language":616},[614],"language-text","def register():\n    from bpy.utils import register_class\n    for cls in classes:\n        register_class(cls)\n\ndef unregister():\n    from bpy.utils import unregister_class\n    for cls in reversed(classes):\n        unregister_class(cls)\n","text",[618,619,615],"code",{"__ignoreMap":515},[25,621,622],{"id":622},"物品选择",[11,624,625],{},"对于想要选择的物品，在UI中想要限定类型的话，需要在注册PointerProperty的时候指定",[611,627,630],{"className":628,"code":629,"language":616},[614],"map_target: bpy.props.PointerProperty(\n    type=bpy.types.Object,\n    name=\"FollowTarget\",\n    poll=lambda self, obj: obj.type == 'ARMATURE' and obj != bpy.context.object\n    )\n",[618,631,629],{"__ignoreMap":515},[11,633,634],{},"这样的话，在进行属性显示时使用layout.prop就能只选择ARMATURE类型了。",[25,636,637],{"id":637},"属性",[11,639,640],{},"属性的变更需要注册update",[611,642,645],{"className":643,"code":644,"language":616},[614],"source_follow_rotation: BoolProperty(\n    update=OnSourceFollowTypeChange, default=True)\n\n\n",[618,646,644],{"__ignoreMap":515},[11,648,649],{},"update传入时的self就是这个属性本身，很方便。",[25,651,653],{"id":652},"uilist","UIList",[11,655,656],{},"ui基本上按照固定的流程来操作就不会有问题。",[11,658,659],{},"遇到问题比较多的是UIList，这个文档描述有些不清晰，导致使用上很多靠猜，而Python又没有类型检查，真的很苦恼。",[11,661,662,663],{},"官方的文档在这里：",[18,664,665],{"href":665,"rel":666,"title":665},"https:\u002F\u002Fdocs.blender.org\u002Fapi\u002Fcurrent\u002Fbpy.types.UIList.html",[22],[11,668,669],{},"主要的问题是对初次接触的人很不友好，如果你和我一样对Python也不是很熟悉的话会一头雾水。原因是第一个例子太简单，而第二个例子太复杂。",[11,671,672],{},"其实，对于UIList而言，一般只要重载draw_item就可以了，在里面可以和其他UI一样执行绘制。",[11,674,675],{},"如果需要过滤功能的话，默认的就可以了。但是如果你需要过滤的属性不是name的话，才需要重写filter_items，不然过滤会不成功。",[11,677,678],{},"如果需要添加一些自定义的过滤的话，才需要最复杂的处理：额外的重载draw_filter来绘制额外的属性，在filter_itmes根据属性进行过滤。",[11,680,681],{},"列表示例：",[611,683,686],{"className":684,"code":685,"language":616},[614],"# ListBox\n# Show list of retarget cell\nclass QM_UL_ControlCell(UIList):\n    \"\"\"\n    List box for retarget cells, this is the list in side panel\n    \"\"\"\n    # Constants (flags)\n    # Be careful not to shadow FILTER_ITEM!\n    VGROUP_EMPTY = 1 \u003C\u003C 0\n\n    # Custom properties, saved with .blend file.\n    use_filter_name_reverse: bpy.props.BoolProperty(name=\"Reverse Name\", default=False, options=set(),\n                                                    description=\"Reverse name filtering\")\n\n    use_order_name: bpy.props.BoolProperty(name=\"Name\", default=False, options=set(),\n                                           description=\"Sort groups by their name (case-insensitive)\")\n\n    use_filter_linked: bpy.props.BoolProperty(name=\"Linked\", default=False, options=set(),\n                                              description=\"Filter linked only\")\n\n    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):\n        row = layout.row()\n\n        subrow = row.row(align=True)\n        subrow.prop(item, \"source_name\", text=\"\", emboss=False)\n\n        subrow = subrow.row(align=True)\n        if len(item.target_name) > 0:\n            subrow.prop(item, \"source_follow_location\", text=\"\",\n                        toggle=True, icon=\"CON_LOCLIKE\")\n            subrow.prop(item, \"source_follow_rotation\", text=\"\",\n                        toggle=True, icon=\"CON_ROTLIKE\")\n\n    def invoke(self, context, event):\n        pass\n\n    def draw_filter(self, context, layout):\n        # Nothing much to say here, it's usual UI code...\n        row = layout.row()\n\n        subrow = row.row(align=True)\n        subrow.prop(self, \"filter_name\", text=\"\")\n        icon = 'ZOOM_OUT' if self.use_filter_name_reverse else 'ZOOM_IN'\n        subrow.prop(self, \"use_filter_name_reverse\", text=\"\", icon=icon)\n\n        icon = 'LINKED' if self.use_filter_linked else 'UNLINKED'\n        subrow.prop(self, \"use_filter_linked\", text=\"\", icon=icon)\n\n        subrow = layout.row(align=True)\n        subrow.label(text=\"Order by:\")\n        subrow.prop(self, \"use_order_name\", toggle=True)\n\n    # Filter\n    # 1. we use [source_name] not [name]\n    # 2. provide filter for targeted cell\n    def filter_items(self, context, data, propname):\n        statelist = getattr(data, propname)\n        helper_funcs = bpy.types.UI_UL_list\n\n        # Default return values.\n        flt_flags = []\n        flt_neworder = []\n\n        # Filtering by name\n        if self.filter_name:\n            flt_flags = helper_funcs.filter_items_by_name(self.filter_name, self.bitflag_filter_item, statelist, \"source_name\",\n                                                          reverse=self.use_filter_name_reverse)\n        if not flt_flags:\n            flt_flags = [self.bitflag_filter_item] * len(statelist)\n\n        # Filtering cell with target\n        if self.use_filter_linked:\n            for i, item in enumerate(statelist):\n                if len(item.target_name) == 0:\n                    flt_flags[i] &= ~self.bitflag_filter_item\n\n        # Reorder by name\n        if self.use_order_name:\n            flt_neworder = helper_funcs.sort_items_by_name(\n                statelist, \"source_name\")\n\n        return flt_flags, flt_neworder\n\n",[618,687,685],{"__ignoreMap":515},[11,689,690],{},"最终结果是这样的：",[11,692,693],{},[98,694],{"alt":218,"src":695},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-24.png",[11,697,698],{},"主要起作用的其实就是",[130,700,701,704,707],{},[77,702,703],{},"draw_item: 绘制单个列表",[77,705,706],{},"draw_filter: 绘制下面的过滤区域，这个不指定也会有一个默认的",[77,708,709],{},"filter_item: 用于实际对列表的元素进行过滤",[11,711,712],{},"在列表绘制时可以指定列表元素和选中的index：",[611,714,717],{"className":715,"code":716,"language":616},[614],"layout.template_list(\"QM_UL_ControlCell\", \"\",\n    qm_state, \"quickmap_celllist\",\n    qm_state, \"quickmap_celllist_index\"\n    )\n",[618,718,716],{"__ignoreMap":515},[11,720,721],{},"这样就可以在选中指定列表元素时根据index的update来得到通知了。",[25,723,724],{"id":724},"文件读写",[11,726,727],{},"python对json的支持比较好，读写很方便。",[11,729,730],{},"文件本身需要让operator继承ExportHelper和ImportHelper才能分别进行blender封装好的文件操作。",[11,732,733],{},"本身很简单，网上随便就能找到例子，这里就不列出占位置了。",[25,735,737],{"id":736},"collection","Collection",[11,739,740],{},"这部分操作有点迷，在网上抄了一段代码直接用就好了：",[611,742,745],{"className":743,"code":744,"language":616},[614],"# Collection Operate\ndef make_collection(collection_name):\n    if collection_name in bpy.data.collections:  # Does the collection already exist?\n        return bpy.data.collections[collection_name]\n    else:\n        new_collection = bpy.data.collections.new(collection_name)\n        bpy.context.scene.collection.children.link(\n            new_collection)  # Add the new collection under a parent\n        return new_collection\n",[618,746,744],{"__ignoreMap":515},[11,748,749],{},"主要是collection的注册关系需要留意，不过别人封好了就不用管了~",{"title":515,"searchDepth":407,"depth":492,"links":751},[752,753,754,755,756,757,758],{"id":586,"depth":407,"text":587},{"id":600,"depth":407,"text":600},{"id":622,"depth":407,"text":622},{"id":637,"depth":407,"text":637},{"id":652,"depth":407,"text":653},{"id":724,"depth":407,"text":724},{"id":736,"depth":407,"text":737},"2020-09-26",{"layout":547,"status":548,"published":549,"author":761,"author_login":552,"author_email":553,"wordpress_id":762,"wordpress_url":763,"date_gmt":764,"excerpt":765},{"display_name":551,"login":552,"email":553,"url":515},3062,"\u002F?p=3062","2020-09-26 13:07:30 +0000",{"type":8,"value":766},[767],[11,768,574],{},"\u002F2020-09-26-blender-plugin-note",{"title":569,"description":574},"_legacy\u002F2020\u002F2020-09-26-blender-plugin-note",[773],"Blender","vSpYGo9iGu31hKuBi00WOCDKGYNSEyUQhAZypHcrca8",{"id":776,"title":777,"body":778,"date":759,"description":782,"extension":545,"meta":1272,"navigation":549,"path":1281,"seo":1282,"stem":1283,"tags":1284,"__hash__":1286},"blogs\u002F_legacy\u002F2020\u002F2020-09-26-princess_connect_re_dive_animation_flow_note.md","公主连结Re:Dive的UB动画制作手法",{"type":8,"value":779,"toc":1247},[780,783,790,793,796,800,803,806,809,820,823,826,829,832,836,839,842,845,848,851,856,859,864,867,870,873,876,879,884,887,890,893,896,899,904,907,910,918,921,924,927,938,954,959,962,965,970,973,984,987,992,995,998,1001,1004,1007,1012,1015,1020,1023,1026,1031,1034,1039,1042,1047,1050,1053,1056,1061,1064,1067,1072,1075,1078,1081,1092,1095,1098,1103,1106,1111,1114,1117,1120,1123,1126,1129,1134,1137,1142,1145,1148,1153,1156,1159,1162,1167,1170,1173,1176,1179,1184,1187,1192,1195,1198,1201,1206,1209,1214,1217,1222,1225,1228,1233,1236,1238,1241,1244],[11,781,782],{},"翻CEDEC的slide的时候看到的，PCR官方的UB动画制作分享。",[11,784,785,786],{},"CEDEC2020：",[18,787,788],{"href":788,"rel":789},"https:\u002F\u002Fcedec.cesa.or.jp\u002F2020\u002Fsession\u002Fdetail\u002Fs5e61f1793b481",[22],[11,791,792],{},"pcr最近有在玩，因为基本每天登陆下就可以了，所以还是比较轻松的。虽然开B服的时候有不少人吐槽战斗是几年前国内页游的水平，但是实际上还是有很多让玩家感到舒服的精巧的设计的。",[11,794,795],{},"这边的分享更加倾向于制作手法，没有什么技术上的点，所以贴图的情况比较多~",[25,797,799],{"id":798},"pcr的ub演出","PCR的UB演出",[11,801,802],{},"首先要看的是pcr的战斗模式：使用SD角色进行战斗，在UB时播放动画。",[11,804,805],{},"一般单场战斗己方可以上五个角色，然后在行动过程中会累计TP，TP满了就可以放UB。和FGO的宝具差不多，总体而言就是大招。看完这个分享就多少有点理解为何FGO官方一直不肯跳过宝具动画了，大概……",[11,807,808],{},"主要介绍的内容为",[74,810,811,814,817],{},[77,812,813],{},"将动画演出融入游戏的方法",[77,815,816],{},"手描动画与组件动画的融合和制作流程",[77,818,819],{},"SD与动画的统一感",[29,821,822],{"id":822},"流程对比",[11,824,825],{},"动画与游戏在制作流程上有很大的不同：",[11,827,828],{},"动画通常会有数个月到半年左右的规划，制作上很难进行回退",[11,830,831],{},"游戏则需要连续性的不断推出短的动画，在必要的时候也会对动画进行替换或重制",[29,833,835],{"id":834},"ub动画的作用","UB动画的作用",[11,837,838],{},"最大限度的表现角色的魅力",[11,840,841],{},"通过2秒的动画让战斗场景更生动",[11,843,844],{},"过场动画和剧情动画的统一感",[29,846,847],{"id":847},"部件动画",[11,849,850],{},"PCR的战斗SD与UB都是采用部件动画的形式：",[11,852,853],{},[98,854],{"alt":218,"src":855},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb.png",[11,857,858],{},"UB动画：",[11,860,861],{},[98,862],{"alt":218,"src":863},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-1.png",[29,865,866],{"id":866},"使用组件动画的理由",[11,868,869],{},"一开始是使用手绘动画的，但是与SD动作的节奏感融合感不够，导致感知上不够顺滑。而战斗的节奏感是PCR的体验核心，所以这里的违和感是致命的。",[11,871,872],{},"对前作进行参考的话，前作的技能切入过场是使用Flash制作的，当然使用的是部件动画。由于与SD使用的是同样的方法，在切入技能过场时有统一的节奏感。同时，由于使用部件的形式，可以在减少成本的同时获得不错的演出效果。",[29,874,875],{"id":875},"制作流程的变更",[11,877,878],{},"更多的流程留在了工作室内部，外包的方式不同，对制作流程有了更好的控制。",[11,880,881],{},[98,882],{"alt":218,"src":883},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-2.png",[11,885,886],{},"使用部件动画的UB的好处之一是：需要绘制的原画数量变少了",[11,888,889],{},"使用动画流程的话，一个UB需要16张原画。使用组件动画的话，由于动作是按照分割部件的形式来实现的，只需要最多7张就够了。",[11,891,892],{},"同时广泛使用部件动画能够在内部形成足够的技术累计，最终由专门的团队来负责组件动画的制作。",[25,894,895],{"id":895},"制作流程",[11,897,898],{},"总体的制作流程分为四个阶段：分镜、作画、动画、摄影",[11,900,901],{},[98,902],{"alt":218,"src":903},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-3.png",[11,905,906],{},"使用的工具：Clip studio paint ex、Adobe animate 、Adboe After effect",[11,908,909],{},"分享中使用的制作实例是：似似花的UB，这个角色具有以下特征：",[130,911,912,915],{},[77,913,914],{},"七冠-强力角色",[77,916,917],{},"变身和分身制作的能力",[29,919,920],{"id":920},"事前商议",[11,922,923],{},"基于规划者提出的演出计划进行讨论",[11,925,926],{},"确定UB的整体印象",[74,928,929,932,935],{},[77,930,931],{},"从什么地方开始进行切入过场动画演出",[77,933,934],{},"如何与SD的演出保持关联性",[77,936,937],{},"UB整体的色彩氛围和方向性的确立",[11,939,940,941,945,946,949,950,953],{},"演出计划：在自己的",[942,943,944],"strong",{},"面前","生成",[942,947,948],{},"数字化","的分身，在",[942,951,952],{},"躁点演出","后实体化",[11,955,956],{},[98,957],{"alt":218,"src":958},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-4.png",[29,960,961],{"id":961},"分镜",[11,963,964],{},"有3种分镜方案",[11,966,967],{},[98,968],{"alt":218,"src":969},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-5.png",[11,971,972],{},"最后使用的是C，分镜由于不全所以不是很懂为什么说是C。选择C的理由是",[130,974,975,978,981],{},[77,976,977],{},"有作弊感的数字特效和动作",[77,979,980],{},"万花镜一般的效果演出",[77,982,983],{},"提高转到SD部分的期待感",[11,985,986],{},"万花镜的特效在SD演出阶段也会使用，最后作为魔法阵演出保留在场景内",[11,988,989],{},[98,990],{"alt":218,"src":991},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-6.png",[11,993,994],{},"同时保证整体动画的前进方向与战斗的前进方向保持一致。",[11,996,997],{},"分镜阶段的作用：通过共通的总体印象来将UB与世界观统一在一起，分镜会为后面动画制作树立一个参照，同时让所有的制作人员能够比较轻松的对最终的目标动画形成一个印象。",[11,999,1000],{},"分镜使用Clip studie paint ex和Adobe animate制作。",[29,1002,1003],{"id":1003},"作画",[11,1005,1006],{},"使用软件为Clip studie paint ex，最终输出原画4~7张",[11,1008,1009],{},[98,1010],{"alt":218,"src":1011},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-7.png",[11,1013,1014],{},"与动画的制作流程不同，因为是部件动画，直接在原画分割后的部件上作补间。",[11,1016,1017],{},[98,1018],{"alt":218,"src":1019},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-8.png",[11,1021,1022],{},"相对于传统动画而言，必要的原画数量变少了。但是对单张原画的品质要求导致在每张原画上花费的成本也变高了。",[11,1024,1025],{},"下面的是单张原画的流程，由于都是图片所以直接贴出来了",[11,1027,1028],{},[98,1029],{"alt":218,"src":1030},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-9.png",[11,1032,1033],{},"需要遵守作画参考资料，正确的把握各个角色的特色",[11,1035,1036],{},[98,1037],{"alt":218,"src":1038},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-10.png",[11,1040,1041],{},"部件的划分基于分镜进行",[11,1043,1044],{},[98,1045],{"alt":218,"src":1046},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-11.png",[11,1048,1049],{},"作画流程：通过节省原画的枚数，在保证质量的同时提升量产能力。在单张原画上投入更多的时间也就可以保证与监修之间的意见沟通，防止动画中角色的个性出现崩坏。",[29,1051,1052],{"id":1052},"动画",[11,1054,1055],{},"使用After Effect，因其具有优秀的Mesh处理功能，可以方便的对部件动画进行制作。同时，后面的摄影流程也使用同样的工具，可以避免在不同的工具之间导入导出产生的各种问题。",[11,1057,1058],{},[98,1059],{"alt":218,"src":1060},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-12.png",[11,1062,1063],{},"在制作过程中留意视线诱导，使得角色的脸或者武器的动作更加突出的表现出来。由于PCR的战斗是向右进行的，所以在制作过程中要尽量保证动作整体是向右前进的。",[11,1065,1066],{},"为了让效果更接近传统动画的表现，逐帧的对动作进行控制，而不是使用关键帧来带过，让动作幅度产生连续感。",[11,1068,1069],{},[98,1070],{"alt":218,"src":1071},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-13.png",[11,1073,1074],{},"对于似似花，通过角色具有的拷贝能力和水晶的印象进行联想，使用万花镜特效来表达角色特性。",[11,1076,1077],{},"特效部分使用ClipStudio和Photoshop进行手绘。手绘的特效以传统动画的表现为目标，例如运动的轨迹会在画面中进行表现残留。对于破碎和扩散的特效，使用手绘动画也能更好的进行表现。",[11,1079,1080],{},"整个动画流程中重要的点",[74,1082,1083,1086,1089],{},[77,1084,1085],{},"留意动画的易懂性和连续性：在设计中对战斗的前进和方向与视线诱导进行重复考量",[77,1087,1088],{},"尽量接近传统动画的表现：使用逐帧变化、采用手绘特效",[77,1090,1091],{},"注重角色特性：设计演出时考虑该角色的特性",[29,1093,1094],{"id":1094},"摄影",[11,1096,1097],{},"这个流程使用Adobe After Effect，并不是指单纯的对动画进行摄影输出。而是指添加各种后期特效",[11,1099,1100],{},[98,1101],{"alt":218,"src":1102},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-14.png",[11,1104,1105],{},"一些特殊的UB还会添加逆光、闪光特效或者Motion Graphic",[11,1107,1108],{},[98,1109],{"alt":218,"src":1110},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-15.png",[29,1112,1113],{"id":1113},"流程总结",[11,1115,1116],{},"整体流程的目标是让UB的过场切入与战斗的SD保持演出上的一致性，通过采用关键帧的动画，投入更多的时间到单帧的同时提高制作速度。在制作时追求传统动画的效果来精细的调节动作以及对特效采用手绘，最终制作出充满角色个性的UB动画。",[25,1118,1119],{"id":1119},"新尝试",[11,1121,1122],{},"通过各种新的尝试，比以往的过程动画更加华丽，更接近于传统动画的风格。",[29,1124,1125],{"id":1125},"系统",[11,1127,1128],{},"将SD与过程动画更多的融合在一起",[11,1130,1131],{},[98,1132],{"alt":218,"src":1133},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-16.png",[11,1135,1136],{},"将各个部分融合成一个完整的动画以特破演出表现的限制",[11,1138,1139],{},[98,1140],{"alt":218,"src":1141},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-17.png",[29,1143,1144],{"id":1144},"演出",[11,1146,1147],{},"这边是以公主UE的UB为例子，通过背景的表现让演出感变得宏大，同时对摄像的移动进行精细控制让空间感变得更强。",[11,1149,1150],{},[98,1151],{"alt":218,"src":1152},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-18.png",[11,1154,1155],{},"不过很想吐槽：这个UB是真的长，但是却没有伤害，白瞎了特效……",[29,1157,1158],{"id":1158},"世界观",[11,1160,1161],{},"主要强调与世界观的一致性，在蝶妈的UB表现上，采用了与游戏内剧情动画一致的演出和摄影特效。",[11,1163,1164],{},[98,1165],{"alt":218,"src":1166},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-19.png",[29,1168,1169],{"id":1169},"制作流程变动",[11,1171,1172],{},"在流程上先确立UB的分镜，然后通过分镜同时对SD的动画和UB动画进行制作。",[11,1174,1175],{},"这样可以在保证动作一致性的同时对特效的绘制进行一定程度的共享。",[11,1177,1178],{},"最后在摄影流程中对特效进行融合以及加上翅膀的特殊处理",[11,1180,1181],{},[98,1182],{"alt":218,"src":1183},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-20.png",[11,1185,1186],{},"新流程的尝试：",[11,1188,1189],{},[98,1190],{"alt":218,"src":1191},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-21.png",[29,1193,1194],{"id":1194},"新的问题",[11,1196,1197],{},"添加过多演出要素导致动画过程破坏战斗的节奏。",[11,1199,1200],{},"例子是蝶妈的UB，有时候确实会因为这个UB太长而不让她上场……",[11,1202,1203],{},[98,1204],{"alt":218,"src":1205},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-22.png",[11,1207,1208],{},"基于节奏感在AfeterEffect中对场景的明暗切换进行精细调整",[348,1210,1211],{},[11,1212,1213],{},"S.C. （スイッチチェンジ）＝一瞬に照明を変化させる事 （カットチェンジとも言う）",[11,1215,1216],{},"另外在系统上可以关闭UB演出，以及Shadow类敌人的动画都会导致演出控制上遇到麻烦",[348,1218,1219],{},[11,1220,1221],{},"Shadow是PCR的一种特殊敌人，相当于敌方持有己方的角色来使用",[11,1223,1224],{},"如果关闭了UB演出的话，则从整个演出中比较好接上的部分开始动作播放。",[11,1226,1227],{},"对于shadow角色的UB则额外的进行制作：",[11,1229,1230],{},[98,1231],{"alt":218,"src":1232},"\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage_thumb-23.png",[11,1234,1235],{},"这个在玩的时候真的没注意到是分开制作的，可能是动画的流程不一样？脸比较黑没抽到这个角色……",[25,1237,510],{"id":510},[11,1239,1240],{},"UB动画相当于2秒中的“角色PV”，是能够重复的表现出角色的魅力和个性的地方。",[11,1242,1243],{},"制作手法充其量只是将想要表现的事物实现出来的手段，为了达到这个目的去寻找最好的制作手法是创作者的使命。",[11,1245,1246],{},"PCR的UB动画的目标是：将角色的魅力传达给玩家。",{"title":515,"searchDepth":407,"depth":492,"links":1248},[1249,1256,1264,1271],{"id":798,"depth":407,"text":799,"children":1250},[1251,1252,1253,1254,1255],{"id":822,"depth":492,"text":822},{"id":834,"depth":492,"text":835},{"id":847,"depth":492,"text":847},{"id":866,"depth":492,"text":866},{"id":875,"depth":492,"text":875},{"id":895,"depth":407,"text":895,"children":1257},[1258,1259,1260,1261,1262,1263],{"id":920,"depth":492,"text":920},{"id":961,"depth":492,"text":961},{"id":1003,"depth":492,"text":1003},{"id":1052,"depth":492,"text":1052},{"id":1094,"depth":492,"text":1094},{"id":1113,"depth":492,"text":1113},{"id":1119,"depth":407,"text":1119,"children":1265},[1266,1267,1268,1269,1270],{"id":1125,"depth":492,"text":1125},{"id":1144,"depth":492,"text":1144},{"id":1158,"depth":492,"text":1158},{"id":1169,"depth":492,"text":1169},{"id":1194,"depth":492,"text":1194},{"id":510,"depth":407,"text":510},{"layout":547,"status":548,"published":549,"author":1273,"author_login":552,"author_email":553,"wordpress_id":1274,"wordpress_url":1275,"date_gmt":1276,"excerpt":1277},{"display_name":551,"login":552,"email":553,"url":515},3056,"\u002F?p=3056","2020-09-26 03:29:25 +0000",{"type":8,"value":1278},[1279],[11,1280,782],{},"\u002F2020-09-26-princess_connect_re_dive_animation_flow_note",{"title":777,"description":782},"_legacy\u002F2020\u002F2020-09-26-princess_connect_re_dive_animation_flow_note",[1285],"Pipeline","iL162DNsiBd6Brv4tyWTQWKWG-H1KOnN3wMWryLIWrI",{"id":1288,"title":1289,"body":1290,"date":1713,"description":1294,"extension":545,"meta":1714,"navigation":549,"path":1726,"seo":1727,"stem":1728,"tags":1729,"__hash__":1730},"blogs\u002F_legacy\u002F2020\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation.md","FF7重置版动画技术笔记",{"type":8,"value":1291,"toc":1676},[1292,1295,1302,1305,1308,1311,1317,1320,1323,1326,1330,1333,1336,1339,1345,1349,1352,1356,1359,1363,1371,1374,1383,1392,1396,1399,1402,1405,1409,1412,1415,1418,1421,1425,1428,1431,1435,1438,1441,1445,1448,1451,1455,1458,1461,1467,1470,1473,1476,1487,1490,1496,1499,1503,1506,1510,1513,1516,1519,1522,1525,1528,1531,1535,1543,1547,1555,1559,1562,1566,1569,1582,1586,1589,1592,1595,1598,1601,1605,1608,1611,1614,1617,1621,1624,1627,1630,1634,1637,1640,1643,1646,1649,1652,1658,1665,1668,1670,1673],[11,1293,1294],{},"CEDEC2020上的FF7的技术分享的笔记，不过我没赶上直播，事后看的PPT。",[11,1296,1297,1298],{},"CEDEC页面：",[18,1299,1300],{"href":1300,"rel":1301},"https:\u002F\u002Fcedec.cesa.or.jp\u002F2020\u002Fsession\u002Fdetail\u002Fs5e58c8811bc98",[22],[11,1303,1304],{},"FF7是UE4做的，所以可以参考的部分就会多一些。",[25,1306,1307],{"id":1307},"动画结构",[11,1309,1310],{},"首先是整个角色动画的结构的概览，如果只是想要粗略的了解的话，看这张图就够了：",[11,1312,1313],{},[98,1314],{"alt":1315,"src":1316},"animation-struct","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-300x121.png",[11,1318,1319],{},"左边上边两个，首先是游戏场景动画，然后到过场动画的动画。这两个是串行的，由于没有玩过FF7R，猜测可能过场动画是以游戏场景为基础直接播放的，而不是作出固定的Sequence动画。",[11,1321,1322],{},"左边下边的两个，是LipSync到过场动画的Facial动画，也就是嘴唇的动作叠加到过场动画的表情动画上。",[11,1324,1325],{},"其他的都和中文的表意差不多，下面会有列出，就不赘述了。",[25,1327,1329],{"id":1328},"primary-animation","Primary Animation",[11,1331,1332],{},"主动画部分根据当前角色的状态完成主要的动作更新，例如当前的行走、攻击等动作的播放应该都在这边。",[29,1334,1335],{"id":1335},"游戏场景动画",[11,1337,1338],{},"上面那张图左上角的Filed Body(フィールドボディ)，就只是简单的列出了下结构",[11,1340,1341],{},[98,1342],{"alt":1343,"src":1344},"field-animation","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-1-300x140.png",[57,1346,1348],{"id":1347},"locomotion","Locomotion",[11,1350,1351],{},"Locomotion上是针对所有角色的基础移动动画逻辑，这个应该和大多数游戏的实现是一样的，根据StateMachine以及其他State的差分来应用不同的动画叠加。通过切换动作的配置可以实现动态的切换，这里的MotionPack不是很确定具体指的是什么。从实现上看，动画蓝图中引入的motion是可以在C++层面动态指定的。但FF7R具体在什么时间切换这些并没有具体说明，不过这个根据游戏逻辑不同会有不同，写出来其实也没什么太大的参考意义。",[57,1353,1355],{"id":1354},"action","Action",[11,1357,1358],{},"角色固有的动作动画。根据运行时游戏逻辑中玩家的输入进行动态的切换，通常的攻击动画应该都是在这里进入动画逻辑的。动作根据类型定义，可以根据不同的角色进行任意的状态管理。对于同一层的Action，如果有新的玩家输入进来的话，会进行中断和替换处理。",[57,1360,1362],{"id":1361},"resident","Resident",[11,1364,1365,1366,1370],{},"一些装饰性物品的动画，比如尾巴这些与Locomotion的状态管理无关的东西的动画处理。由于用的是",[1367,1368,1369],"em",{},"常驻","这样的描述，不是很确定头发和衣服是否在其中。尾巴应当算是装饰物，可能我对词语的理解有偏差，话说有角色有尾巴的吗？没玩过原作不是很确定。总之实际上就是那些与主动画循环关系不大的部分放在主动画更新完成后进行一次更新。",[29,1372,1373],{"id":1373},"惯性补间",[11,1375,1376,1377,1382],{},"在混合的时候不考虑源动画，只朝着目标动画进行计算的方式。在减少运算量的同时提高动画的流畅感，但是会增加一些内存消耗。PPT里面列了很多计算的公式和内部的设计的原理，由于在UE4.24已经作为引擎功能提供了，直接在动画蓝图中使用",[18,1378,1381],{"href":1379,"rel":1380},"https:\u002F\u002Fdocs.unrealengine.com\u002Fzh-CN\u002FEngine\u002FAnimation\u002FNodeReference\u002FBlend\u002Findex.html",[22],"Inertialization","动画混合方式就可以了。",[11,1384,1385,1386,1391],{},"想要详细的了解技术方面可以参考之前的GDC分享：",[18,1387,1390],{"href":1388,"rel":1389},"https:\u002F\u002Fwww.gdcvault.com\u002Fplay\u002F1025331\u002FInertialization-High-Performance-Animation-Transitions",[22],"Inertialization-High Performance Animation Transitions","，当然也可以去看UE4的源码实现方式。",[29,1393,1395],{"id":1394},"pose-matching","Pose Matching",[11,1397,1398],{},"在目标动画有好几个候补的时候，通过对这几个动画进行比较来决定使用哪一个动画。例如，从行走到停止的状态，会事先设定一些候补的动画，然后根据当时状态选择一个最合适的。",[11,1400,1401],{},"候补的动画列表可以按照角色进行不同的配置，同时也可以使用动画通知对候补列表进行追加和限制。",[11,1403,1404],{},"进行动画比较时并不是使用全体的骨骼进行评估，而是使用事先设定的骨骼进行比较。例如，二足行走的时候使用下半身的基础骨骼进行比较。",[25,1406,1408],{"id":1407},"secondary-animation","Secondary Animation",[11,1410,1411],{},"次要动画在主要动作确立之后对动作进行微调，通常的足IK、手部IK都在这里。",[29,1413,1414],{"id":1414},"输入补正",[11,1416,1417],{},"根据来自玩家或者AI的输入对骨骼进行动态的旋转补正，通过IK Control Rig进行配置所以可以在角色间公用，同时可以在编辑器中进行动态的预览。这个记得之前ALS里面也有类似的实现，可以给用户输入一个细节上的反馈，例如在向前加速的过程中有一个向前倾的动作。",[11,1419,1420],{},"输入补正的配置资源保存在IK Control Rig中，运行时直接进行叠加。",[29,1422,1424],{"id":1423},"look-at","Look At",[11,1426,1427],{},"LookAt的处理只使用惯性补间和线性补间，可以针对每个骨骼进行其重量和角速度的设定。使用惯性补间时，对其到达时间进行一个随机的基础数值叠加。在角度的限制上区分了Pitch和Yaw。在进行姿态维持时，可以将骨骼的目标按照Mesh的空间进行指定。",[11,1429,1430],{},"LookAt在操作上可以在具体的动作中通过动画通知暂时的关掉。",[29,1432,1434],{"id":1433},"aim","Aim",[11,1436,1437],{},"Aim的处理只使用EaseOut和线性补间，不使用惯性补间的原因是目标在不断的进行移动时惯性补间的效果很差。通过AimGroup来针对每个骨骼进行重量和角度设定，并在动画蓝图通知中对不同的AimGroup进行选择。",[11,1439,1440],{},"Aim的设定主要在AimGroup中，动画只能指定不使用Aim，运行时也不会调整这些参数。",[29,1442,1444],{"id":1443},"hand-ik","Hand IK",[11,1446,1447],{},"使用FABRIK算法，IK的目标分为两种：指定世界坐标的固定目标和使用特效等的相对位置的锁定目标。使用锁定目标的IK时，由于使用的是补间之前的位置，可以充当LookAt和FootIK的反动作。",[11,1449,1450],{},"与Aim相同，运行时只能使用设定好的HandGroup，具体的配置是在资源中固化的。",[29,1452,1454],{"id":1453},"footik-hip-control","FootIK & Hip Control",[11,1456,1457],{},"与其他游戏一样检出地面的凹凸来调整脚的位置，同时根据脚的目标位置(FootLock)对腰的骨骼施加一个动态的偏移。战斗中防御动作时，对腰部施加了一个额外的向下10cm的偏移来表现重心的下落。",[11,1459,1460],{},"为了避免滑步移动的现象，会对当前脚的最低点到地面的距离Base Height进行维护。",[11,1462,1463],{},[98,1464],{"alt":1465,"src":1466},"foot-ik-base-hegith","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-2-150x150.png",[11,1468,1469],{},"在站立或行走时，会根据脚接触地面的最低的位置来调整腰部的下落。同时根据地面的倾斜度来调整root骨骼的旋转以反应腰部的骨骼位置补正。",[29,1471,1472],{"id":1472},"平衡控制",[11,1474,1475],{},"由于Foot Ik与Hip Control导致角色的中心出现偏移时，通过倾斜角度对骨骼的旋转进行调整。调整的内容包括：",[130,1477,1478,1481,1484],{},[77,1479,1480],{},"根据Pitch计算补正值",[77,1482,1483],{},"根据Pitch的绝对值进行补正",[77,1485,1486],{},"根据Roll进行补正",[11,1488,1489],{},"这个中心偏移，原文描述的是类似人物的中轴线的感觉。当人站在斜坡上时，为了保持平衡，其站立方向应该还是向上的。如下图：",[11,1491,1492],{},[98,1493],{"alt":1494,"src":1495},"ballance-control","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-3-150x150.png",[11,1497,1498],{},"模拟的是人在斜坡上的一种后倾的维持平衡的动作。",[29,1500,1502],{"id":1501},"control-rig的必要性","Control Rig的必要性",[11,1504,1505],{},"Control Rig可以方便对动画蓝图中的补正进行运行时效果进行观察和调整，有时这种运行时的效果调试比设定专门的预览环境更加能够有效的达到目的。尤其是根据背景物体和周围角色而表现不同的地方，在游戏环境中直接测试能够更好的对效果进行控制和调整。",[29,1507,1509],{"id":1508},"bodydriver","BodyDriver",[11,1511,1512],{},"是内部研发的一种物理动画特效。用于击倒动画中，与通常的RagDoll不同，会有角色按住受击部位的同时后退的演出。",[11,1514,1515],{},"目测，应该就是在击倒动画时有一部分骨骼是开启了物理的，然后另一部分叠加了按住受击部分等的动画控制。通过这样可以为击倒动画添加不同的表现，提升演出效果。",[11,1517,1518],{},"一般的RagDoll直接打开的话总是会有很大的概率出现非常鬼畜的效果，所以FF7R的对应方式值得参考一下。",[29,1520,1521],{"id":1521},"物理拘束补正",[11,1523,1524],{},"通过Position base dynamice添加基于物理拘束的补正处理。通过将约束条件进行Preset化并保存到Mesh的用户数据中。",[11,1526,1527],{},"通过物理拘束补正，可以表现鱼在沿着Spline移动时身体的扭动。对于与部分的角色，会将物理拘束补正与受击反馈结合起来，表现出更好的受击效果。由于是工作在Mesh空间的，成本较低，对于一些简单的背景物体也可以使用。",[11,1529,1530],{},"PBD本身使用物体的速度计算出位置，然后将所有的约束叠加到物体上得到新的位置，根据这个位置重新推断出速度来。可以在运行时调整物理的开关以及速度和重力等属性。",[29,1532,1534],{"id":1533},"kinedriver","KineDriver",[11,1536,1537,1538,1542],{},"辅助骨骼：",[18,1539,1540],{"href":1540,"rel":1541},"https:\u002F\u002Fcedil.cesa.or.jp\u002Fcedil_sessions\u002Fview\u002F2007",[22],"，这个还没仔细看过，大体上是由实际的运动骨骼去驱动一个虚拟的骨骼，然后这个虚拟的骨骼可以决定Mesh的显示、特效等其他的参数。看演示效果，应该主要是用于实现一些无法单纯用骨架来实现的模型形变。",[29,1544,1546],{"id":1545},"bonamik","Bonamik",[11,1548,1549,1550,1554],{},"参考资料：",[18,1551,1552],{"href":1552,"rel":1553},"https:\u002F\u002Fcedil.cesa.or.jp\u002Fcedil_sessions\u002Fview\u002F1583",[22],"。这个挺复杂的，简单的看了下，似乎是基于Position Based Dynamic的原理来基于骨骼进行一些物理模拟的辅助，主要用于防止衣服等物体穿模。",[25,1556,1558],{"id":1557},"facial-animation","Facial Animation",[11,1560,1561],{},"表情动画能够让角色的表现更加自然，FF7R制定了一套程序化生成的表情动画流程。",[29,1563,1565],{"id":1564},"saccade","Saccade",[11,1567,1568],{},"眼球運動，人的眼球在稳定凝视点和转移凝视点的时候的一种非自主反射运动……总之在FF7中专注于两种眼球运动的模拟，一种是在视角移动时的眼球运动，频率在12.5～17.5Hz，单次移动的角度是有限制的。另一种是注视的时候的微小眼动，频率和幅度更小的线性运动。",[11,1570,1571,1572,424,1576,1581],{},"想要详细了解的可以参考维基百科的描述，由于是专业外，很多术语并不是很明确的了解，就不去强行解释了。参考链接：",[18,1573,1565],{"href":1574,"rel":1575},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSaccade",[22],[18,1577,1580],{"href":1578,"rel":1579},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMicrosaccade",[22],"Microsaccade","。",[57,1583,1585],{"id":1584},"saccade眼睑联动","Saccade眼睑联动",[11,1587,1588],{},"眼球运动的话会带动眼睑的运动，实际过程应该是相反的？我不是很了解生物学也就不去纠结了。",[11,1590,1591],{},"添加这个联动主要是为了让Saccade的运动变得更加明显，将Yaw和Pitch作为输入对眼皮的上下左右运动进行Blend。",[57,1593,1594],{"id":1594},"自动生成",[11,1596,1597],{},"Saccade可以使用身体和脸的朝向自动生成的，使用jenkins对所有的角色动画进行曲线的烘培。",[11,1599,1600],{},"自动生成的流程只在动画不被LookAt控制的时候使用，通常用于攻击动画等时机。原理上面有提到，在视角目标变动的时候会有额外的眼动逻辑。",[29,1602,1604],{"id":1603},"gaze-diversion","Gaze diversion",[11,1606,1607],{},"人在注视的时候会无意识的移开视线的现象，尤其在对话中的非语言交流更加能体现，因为凝视会被视为敌对表现。由于详细的对条件进行设定在实现上会有很多麻烦，实际上只是添加了在表现过程中随机的移开视线。",[29,1609,1610],{"id":1610},"眨眼",[11,1612,1613],{},"眨眼以2～10秒的间隔周期性的随机发生，当视角大规模移动时的反射性眨眼则在LookAt的对象移动位置很大的时候发生。",[11,1615,1616],{},"眨眼没有很多动画，在闭眼动作的基础上进行blend来实现。单次眨眼并不一定完全闭上眼睛，而是在0.5～1.0之间进行随机。",[29,1618,1620],{"id":1619},"happysadface","HappySadFace",[11,1622,1623],{},"是一套LipSync系统，通过语音和文本生成统一的格式，可以在Maya和UE4中进行嘴唇动画的控制。可以处理日语、英语、法语和德语。",[11,1625,1626],{},"从语音中抽出音素，使用音素对形变动画生成时间轴变化。针对每种语言的音素到形变采用的是不同的映射方式。同时，针对语音的情感状态，也会采用不同的形变预设。也就是说，根据下面的情感推定的结果，会针对不同的情感状态采用不同的嘴唇动画。",[11,1628,1629],{},"这个系统的一个问题是在流程上容易出错，如果文本有误或者声优进行了即兴演出的话，会导致生成的精读下降。同时，虽然在没有语音时产生嘴唇动画很容易排查，但是如果出现嘴形对不上的问题很难逐一进行目视确认。",[29,1631,1633],{"id":1632},"voiceattack","VoiceAttack",[11,1635,1636],{},"通过对话的音量对眉毛进行控制，动画上只是通过音量值传入然后对眉毛向上的动画进行blend。",[11,1638,1639],{},"同时也会通过音量来让上体和头部有一个额外的摇动动作，这个动作是配在Ik control rig中的，在运行时会随机的决定一个预设来使用。",[29,1641,1642],{"id":1642},"表情生成",[11,1644,1645],{},"使用ST Emotion通过语音来推定情感，通过情感的指数对各个表情动画进行混合。推定的情感指数是一种时间线数据，并不是针对单句语音，而是会在一个语音中有表情的变化。",[11,1647,1648],{},"情感推定的精读在70%左右，但是单单只是给表情添加了变化就能带来很大的表现提升。",[11,1650,1651],{},"情绪指数参考Russel的情感圆环模型针对所有的角色进行设置。根据情绪指数的不同其在情感圆环中的采样位置就会不同，为了避免线性插值导致的生硬变化，使用自定义的曲线进行插值。",[11,1653,1654],{},[98,1655],{"alt":1656,"src":1657},"emotion-circle","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002FFF7-circle-150x150.png",[11,1659,1660,1661,1581],{},"Russel情感圆环应该是这篇：",[18,1662,1663],{"href":1663,"rel":1664},"https:\u002F\u002Fpsycnet.apa.org\u002Frecord\u002F1981-25062-001",[22],[11,1666,1667],{},"ST Emotion可以实时的对情感进行检出，对五种情感每一种检出到10个精度上。对应的情感为：喜悦、愤怒、悲伤、平常和兴奋。",[25,1669,510],{"id":510},[11,1671,1672],{},"FF7R的整体角色动画流程的处理有非常多的值得参考的部分，虽然一些技术细节并没有公布，但是并没有什么影响。因为根据项目需求的不同其实很多地方也会不一样，即便拿到源代码后面能用的部分也不多。",[11,1674,1675],{},"ST Emotion是商业项目，由于官方网站没有标价所以不是很确定使用成本，不过情感推定作为人工智能领域的一个广泛研究的主题，应该也能找到好的替代品，如果对开发周期特别敏感的话也可以尝试购买使用。",{"title":515,"searchDepth":407,"depth":492,"links":1677},[1678,1679,1688,1701,1712],{"id":1307,"depth":407,"text":1307},{"id":1328,"depth":407,"text":1329,"children":1680},[1681,1686,1687],{"id":1335,"depth":492,"text":1335,"children":1682},[1683,1684,1685],{"id":1347,"depth":501,"text":1348},{"id":1354,"depth":501,"text":1355},{"id":1361,"depth":501,"text":1362},{"id":1373,"depth":492,"text":1373},{"id":1394,"depth":492,"text":1395},{"id":1407,"depth":407,"text":1408,"children":1689},[1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700],{"id":1414,"depth":492,"text":1414},{"id":1423,"depth":492,"text":1424},{"id":1433,"depth":492,"text":1434},{"id":1443,"depth":492,"text":1444},{"id":1453,"depth":492,"text":1454},{"id":1472,"depth":492,"text":1472},{"id":1501,"depth":492,"text":1502},{"id":1508,"depth":492,"text":1509},{"id":1521,"depth":492,"text":1521},{"id":1533,"depth":492,"text":1534},{"id":1545,"depth":492,"text":1546},{"id":1557,"depth":407,"text":1558,"children":1702},[1703,1707,1708,1709,1710,1711],{"id":1564,"depth":492,"text":1565,"children":1704},[1705,1706],{"id":1584,"depth":501,"text":1585},{"id":1594,"depth":501,"text":1594},{"id":1603,"depth":492,"text":1604},{"id":1610,"depth":492,"text":1610},{"id":1619,"depth":492,"text":1620},{"id":1632,"depth":492,"text":1633},{"id":1642,"depth":492,"text":1642},{"id":510,"depth":407,"text":510},"2020-09-17",{"layout":547,"status":548,"published":549,"author":1715,"author_login":1716,"author_email":1717,"author_url":1718,"wordpress_id":1719,"wordpress_url":1720,"date_gmt":1721,"excerpt":1722},{"display_name":1716,"login":1716,"email":1717,"url":1718},"chaoshikari","chaoshikari@gmail.com","\u002F",2939,"\u002F?p=2939","2020-09-17 15:05:58 +0000",{"type":8,"value":1723},[1724],[11,1725,1294],{},"\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation",{"title":1289,"description":1294},"_legacy\u002F2020\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation",[565],"Q3LKOb2a2Rno6CG5WMb56TEjju4Tp3M8biDAcy2nBEo",{"id":1732,"title":1733,"body":1734,"date":2042,"description":1738,"extension":545,"meta":2043,"navigation":549,"path":2052,"seo":2053,"stem":2054,"tags":2055,"__hash__":2057},"blogs\u002F_legacy\u002F2020\u002F2020-09-13-subspace-neural-physics-note.md","Subspace neural physics笔记",{"type":8,"value":1735,"toc":2025},[1736,1739,1742,1749,1757,1760,1763,1767,1774,1778,1781,1785,1788,1791,1794,1797,1800,1961,1964,1967,1970,1973,1976,1979,1983,1992,1996,1999,2003,2011,2017,2019,2022],[11,1737,1738],{},"去年GDC看到育碧的基于神经网络的物理交互模拟，终于找到时间仔细的看了下。",[11,1740,1741],{},"这边只是记录一些笔记，原始的分享其实就说明的很详细了。",[11,1743,1744,1745],{},"效果演示：",[18,1746,1747],{"href":1747,"rel":1748},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=yjEvV86byxg",[22],[11,1750,1751,1752],{},"论文：",[18,1753,1756],{"href":1754,"rel":1755},"http:\u002F\u002Ftheorangeduck.com\u002Fpage\u002Fsubspace-neural-physics-fast-data-driven-interactive-simulation",[22],"Subspace Neural Physics",[25,1758,1759],{"id":1759},"物理模拟",[11,1761,1762],{},"首先是对现有的物理模拟方式的总结，并不是介绍引擎，而是更多的在学术方面进行描述。",[29,1764,1766],{"id":1765},"position-based-dynamic","Position based dynamic",[11,1768,1769,1770,1581],{},"这个是在商业引擎的布料模拟中已经使用到的模拟方式，基于位置的模拟方式可以更高效的进行碰撞解算也能很有效的避免穿插。详细的内容可以参考这篇论文：",[18,1771,1766],{"href":1772,"rel":1773},"https:\u002F\u002Fmatthias-research.github.io\u002Fpages\u002Fpublications\u002FposBasedDyn.pdf",[22],[29,1775,1777],{"id":1776},"subspace-simulation","Subspace simulation",[11,1779,1780],{},"子空间模拟的思路很简单，就是将物体的碰撞形态简化来提高模拟的效率。虽然听起来和UE4中的simple collision很相似，但是这里其实是更加直白的使用方式。只是对大的物体进行子空间的划分，不会将起简化为基础碰撞形态。",[29,1782,1784],{"id":1783},"data-driven-simulation","Data-Driven Simulation",[11,1786,1787],{},"这个方法比较直白，就是将事先模拟的结果存储起来。然后在运行时根据外部变量直接取出模拟结果。",[25,1789,1790],{"id":1790},"神经网络",[11,1792,1793],{},"论文中使用的方法，是将Data-Driven和Subspace结合的一种思路。在数据上，首先对模拟对象进行Subspace划分，然后将数据“存储”在神经网络中。",[29,1795,1796],{"id":1796},"数据生产",[11,1798,1799],{},"使用的训练数据全部是使用Maya的nCloth进行模拟导出的，这里直接引用原文中的训练数据：",[1801,1802,1803,1828],"table",{},[1804,1805,1806],"thead",{},[1807,1808,1809,1813,1816,1819,1822,1825],"tr",{},[1810,1811,1812],"th",{},"Scene",[1810,1814,1815],{},"Material",[1810,1817,1818],{},"Verts",[1810,1820,1821],{},"Frames",[1810,1823,1824],{},"FPS",[1810,1826,1827],{},"Time",[1829,1830,1831,1852,1869,1886,1906,1923,1943],"tbody",{},[1807,1832,1833,1837,1840,1843,1846,1849],{},[1834,1835,1836],"td",{},"Ball&Sheet",[1834,1838,1839],{},"T-Shirt",[1834,1841,1842],{},"2601",[1834,1844,1845],{},"1,000,000",[1834,1847,1848],{},"7.6",[1834,1850,1851],{},"36h",[1807,1853,1854,1857,1859,1861,1863,1866],{},[1834,1855,1856],{},"Four Pins",[1834,1858,1839],{},[1834,1860,1842],{},[1834,1862,1845],{},[1834,1864,1865],{},"15.5",[1834,1867,1868],{},"18h",[1807,1870,1871,1874,1876,1878,1880,1883],{},[1834,1872,1873],{},"Flag",[1834,1875,1839],{},[1834,1877,1842],{},[1834,1879,1845],{},[1834,1881,1882],{},"10.9",[1834,1884,1885],{},"25h",[1807,1887,1888,1891,1894,1897,1900,1903],{},[1834,1889,1890],{},"Skirt",[1834,1892,1893],{},"Denim",[1834,1895,1896],{},"3000",[1834,1898,1899],{},"650,000",[1834,1901,1902],{},"3.1",[1834,1904,1905],{},"60h",[1807,1907,1908,1911,1913,1915,1917,1920],{},[1834,1909,1910],{},"Cape",[1834,1912,1839],{},[1834,1914,1842],{},[1834,1916,1899],{},[1834,1918,1919],{},"1.9",[1834,1921,1922],{},"95h",[1807,1924,1925,1928,1931,1934,1937,1940],{},[1834,1926,1927],{},"Bunny",[1834,1929,1930],{},"Rubber",[1834,1932,1933],{},"2503",[1834,1935,1936],{},"200,000",[1834,1938,1939],{},"0.4",[1834,1941,1942],{},"129h",[1807,1944,1945,1948,1950,1952,1955,1958],{},[1834,1946,1947],{},"Dragon",[1834,1949,1930],{},[1834,1951,1896],{},[1834,1953,1954],{},"500,000",[1834,1956,1957],{},"1.0",[1834,1959,1960],{},"138h",[11,1962,1963],{},"后文也有提到，这个方法的缺点之一，就是需要大量的生产训练数据。",[29,1965,1966],{"id":1966},"训练模型",[11,1968,1969],{},"总体思路上，认为当前的物理状态可以由前两帧的状态计算出来。详细的模型可以参考论文，训练使用的是feed-forwad neural network。",[11,1971,1972],{},"训练中预测的是到下一帧需要的每个点需要的步进量。为了防止过度拟合，训练时对一个区间的帧进行预测和评估，而关于模型中的参数A和B，在文章的末尾有提到获取的方式。由于这个是决定在没有外力的情况下从一帧到下一帧的演变的，所以对整体的训练数据做一个帧之间的计算，并对结果进行线性最小二乘拟合就得到两这个参数。",[11,1974,1975],{},"在显示上，其实还使用了Vertex Normal Prediction的过程来对法线进行计算。同时为了防止在显示层面的穿模，对Shader进行了一些特殊处理。",[25,1977,1978],{"id":1978},"额外名词",[29,1980,1982],{"id":1981},"pca","PCA",[11,1984,1985,1986,1991],{},"文中只是简短的说使用PCA对模型进行子空间的划分。由于不是很了解这个，稍微查了下，PCA就是主成分分析，详细的可以在维基百科",[18,1987,1990],{"href":1988,"rel":1989},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPrincipal_component_analysis",[22],"Principal component analysis","看到。",[29,1993,1995],{"id":1994},"ablation-study","Ablation Study",[11,1997,1998],{},"由于之前没接触过神经网络，这个是第一次看到。其实是源于生物学的一种处理方式，就是将系统的一部分进行移除来观察系统会如何运作。以验证某个部分在系统中发挥的是什么样的作用。",[29,2000,2002],{"id":2001},"verlet-intergration","Verlet intergration",[11,2004,2005,2006,2010],{},"文中最后通过推导，表明模型的公式就是",[18,2007,2002],{"href":2008,"rel":2009},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVerlet_integration",[22],"的一种表示，这个是韦尔莱积分法：",[611,2012,2015],{"className":2013,"code":2014,"language":616},[614],"韦尔莱算法是一种用于求解牛顿运动方程的数值方法，被广泛应用于分子动力学模拟以及视频游戏中。韦尔莱算法的优点在于：数值稳定性比简单的欧拉方法高很多，并保持了物理系统中的时间可逆性与相空间体积元体积守恒的性质。\n",[618,2016,2014],{"__ignoreMap":515},[25,2018,510],{"id":510},[11,2020,2021],{},"从演示的效果来看，这种布料模拟方式还是有一定的实践作用的。尤其是对于人物的布料模拟，只是目前还没有成熟的流程。尤其是在训练数据生产这方面还是有些让人望而却步。",[11,2023,2024],{},"由于应用场景有些特化，不知以后会不会有进一步的优化和商业产品。",{"title":515,"searchDepth":407,"depth":492,"links":2026},[2027,2032,2036,2041],{"id":1759,"depth":407,"text":1759,"children":2028},[2029,2030,2031],{"id":1765,"depth":492,"text":1766},{"id":1776,"depth":492,"text":1777},{"id":1783,"depth":492,"text":1784},{"id":1790,"depth":407,"text":1790,"children":2033},[2034,2035],{"id":1796,"depth":492,"text":1796},{"id":1966,"depth":492,"text":1966},{"id":1978,"depth":407,"text":1978,"children":2037},[2038,2039,2040],{"id":1981,"depth":492,"text":1982},{"id":1994,"depth":492,"text":1995},{"id":2001,"depth":492,"text":2002},{"id":510,"depth":407,"text":510},"2020-09-13",{"layout":547,"status":548,"published":549,"author":2044,"author_login":1716,"author_email":1717,"author_url":1718,"wordpress_id":2045,"wordpress_url":2046,"date_gmt":2047,"excerpt":2048},{"display_name":1716,"login":1716,"email":1717,"url":1718},2932,"\u002F?p=2932","2020-09-13 04:07:52 +0000",{"type":8,"value":2049},[2050],[11,2051,1738],{},"\u002F2020-09-13-subspace-neural-physics-note",{"title":1733,"description":1738},"_legacy\u002F2020\u002F2020-09-13-subspace-neural-physics-note",[2056],"physics","Il9cRhQaN0vWKkfnE8a41GjMeUE9rfO4t7Sh5bcRM4c",222,1788763178646]