python 人形自动标注

The humanoid animation option in Unity 4 makes it possible to retarget the same animations to different characters. The characters can have different proportions and skeleton rigs where the bones have different names etc. But before you can take advantage of that, the bones in your character have to be matched up with the authoritative “human bones” that Mecanim uses. Fortunately, for the majority of models this otherwise lengthy setup process is completely automatic. Let’s have a look at how that works…

Unity 4中的人形动画选项使将相同动画重新定位到不同角色成为可能。 角色可以具有不同的比例和骨骼,骨骼的名称也各不相同,等等。但是在您利用骨骼之前,必须先将角色中的骨骼与Mecanim所使用的权威“人骨”相匹配。 幸运的是 ,对于大多数模型而言,原本冗长的设置过程是完全自动的。 让我们看看它是如何工作的……

阿凡达地图涉及什么 (What Avatar Mapping Involves)

Setting up a humanoid Avatar in Unity involves matching every “human bone” to one of the transforms in the model. It’s possible to do this manually in Unity by clicking Configure… under the Rig tab of the Model Importer. Without fingers there’s up to 24 bones to map – and 30 more if you have finger bones too. For every one of those you have to drag the transform into the corresponding slot in the GUI when you use the manual method. When I first joined the effort to improve the interface for Mecanim, that was the only way to setup characters. For anyone who wanted to experience the Mecanim awesomeness with their own characters, there was first these 24-54 bones to drag in with the mouse, one by one. Things like that don’t leave an exciting first impression. So I began looking into how to do that automatically.

在Unity中设置人形头像需要将每个“人的骨骼”与模型中的变换之一进行匹配。 通过在Model Importer的Rig选项卡下单击Configure… ,可以在Unity中手动执行此操作。 如果没有手指,则最多可以映射24根骨骼;如果您也有手指骨骼,则最多可以映射30根骨骼。 对于其中的每一个,当您使用手动方法时,都必须将转换拖到GUI中的相应插槽中。 当我第一次加入为Mecanim改进界面的工作时,那是设置角色的唯一方法。 对于想用自己的角色体验Mecanim的超凡体验的人,首先要用鼠标将这些24-54根骨头一一拖入。 这样的事情不会给人留下令人兴奋的第一印象。 因此,我开始研究如何自动执行此操作。

提示 (Hints to Go By)

How do you make a computer figure out what transforms correspond to which human bones? There is more than one way to go about it…

您如何使计算机确定哪些转换对应于哪些人体骨骼? 有多种解决方法……

骨骼名称 (Names of Bones)

One seemingly straightforward option is to use the names of the transforms. But unfortunately, some of the most commonly used terms are actually used to describe different bones in different models.

一个看似直接的选项是使用转换的名称。 但不幸的是,实际上一些最常用的术语用于描述不同模型中的不同骨骼。

Naming for bones in the spine is often a total anarchy since the number of bones is completely variable, and sometimes a bone called “neck” even has the left and right shoulder as children (due to a flaw in a popular software used for rigging), meaning the mapping have to assign it as the chest bone despite its name. Furthermore, finger bones are often simply named “finger_0” to “finger_14” or similar, with no convention of which numbers mean what. And bones for eyeballs and jaw have a ridiculous amount of variation for what they’re called, including helpful things like “nurbsToPoly2”. So while names of bones often give us certain useful hints, they don’t contain sufficient information on their own to cover a wide variety of models.

由于骨骼的数量是完全可变的,因此脊椎中骨骼的命名通常是完全无政府状态,有时称为“颈部”的骨骼甚至在儿童的左右肩上也存在(由于流行的用于装配的软件存在缺陷) ,这意味着尽管映射已命名,但仍必须将其指定为胸骨。 此外,手指骨骼通常被简单地命名为“ finger_0”至“ finger_14”或类似名称,没有约定哪个数字表示什么意思。 眼球和颌骨的骨骼被称为“ nurbsToPoly2”之类的有用东西,其变化程度可笑。 因此,尽管骨骼名称经常给我们提供一些有用的提示,但它们本身并没有包含足够的信息来涵盖各种各样的模型。

副关键字 (Side Keywords)

Just determining if a bone is for the left or right side is a mini challenge by itself. Obviously if the word “left” or “right” is included in the name it’s a given, but a lot of the time only the letter “l” or “r” is used. However, those letters can also be part of a word, so I only regard them as side keywords if they stand by themselves, separated from the rest of the string by spaces, punctuation, or similar.

仅确定骨骼是左侧还是右侧本身就是一个小挑战。 显然,如果名称中包含单词“ left”或“ right”,这是给定的,但很多时候仅使用字母“ l”或“ r”。 但是,这些字母也可以是单词的一部分,因此,如果它们独立存在,并以空格,标点符号或类似字符与字符串的其余部分分开,则我只会将它们视为辅助关键字。

骨方向 (Bone Directions)

Some information can be inferred by looking at the direction of a bone. While there’s no guarantee about the pose of the character at the time when the auto-mapping happens, it’s generally more likely that bones in the right side point towards +x and that bones in the spine point towards +y while bones in the legs point towards -y etc. For each human bone we have specified a “correct” direction. Direction matches of different child transforms are computed using dot products of the normalized transform direction compared to a target human bone direction, and a score is awarded accordingly. Where the bone direction information really shines is in figuring out the mapping for the fingers, where there is often nothing else to go by.

通过查看骨骼的方向可以推断出一些信息。 虽然无法保证自动映射发生时角色的姿势,但通常更有可能是右侧的骨骼指向+ x,而脊椎的骨骼指向+ y而腿部的骨骼指向朝向-y等。我们为每个人体骨骼指定了“正确”方向。 使用标准化变换方向与目标人骨方向的点积计算不同子变换的方向匹配,并相应地授予分数。 骨骼方向信息真正发挥作用的地方在于找出手指的映射关系,而这些地方通常没有其他选择。

骨长比 (Bone Length Ratios)

While proportions of different models differ, there are usually some aspects of the proportions that are consistent for most models. For example, the upper leg and lower leg usually have roughly the same length, while the length of the foot is typically much shorter. The length of the upper arm bone is usually about twice as long as the length of the collar bone, when present. The length ratios contribute a lot to ensuring sensible mappings. Imagine for example a model that has no collar bone, and the upper arm bone is called “shoulder”. The upper arm also has a bone in between the shoulder joint and elbow joint used for twisting of the upper arm (but nothing in the name necessarily indicates this). Looking at the names of the bones alone, the computer would be inclined to map the bone called “shoulder” to the human collar bone and map the upper arm twist bone to the upper arm human bone. This would be completely wrong. But thanks to the length ratios, this scenario is almost always avoided and the bones are mapped correctly. Another place where the length ratios shine is for the bones in the spine. The spine in a model can consist of any number of bones, but they have to be mapped in a sensible way to just the following human bones: Hips, spine, chest (optional), neck (optional), and head. If you have, say, 8 transforms in the spine, how should they be mapped? The names are no use, and the bone directions are all the same. Just attempting an even distribution gives terrible results. Instead we strive towards these length ratios: spine-chest should be 1.4 times as long as hip-spine. Chest-neck should be 1.8 times as long as spine-chest. Neck-head should be 0.3 times as long as chest-neck. (Humanoids generally bend mostly in the area below the chest since the chest itself is more rigid.) The result is a mapping that produces bending in the spine that looks natural within the confines of the bones in the model. The algorithm chooses bone assignments that matches the desired length ratio as closely as possible. Calculating “closeness” in this case requires converting both the actual ratio and the desired ratio to a logarithmic scale and measuring the difference of those. The logarithmic scale ensures than a length that’s twice as longs as it’s supposed to be is penalized by the same amount as a length that’s half as long as it’s supposed to.

尽管不同模型的比例不同,但是对于大多数模型而言,通常存在某些比例方面是一致的。 例如,大腿和小腿通常具有大致相同的长度,而脚的长度通常要短得多。 上臂骨骼的长度通常约为颈圈骨骼长度(如果存在)的两倍。 长度比对确保合理的映射起了很大的作用。 例如,想象一个没有领骨的模型,而上臂骨被称为“肩膀”。 上臂在肩关节和肘关节之间也有一根骨头,用于上臂的扭转(但名称中的任何内容都不一定表示这一点)。 仅查看骨骼的名称,计算机将倾向于将称为“肩膀”的骨骼映射到人的颈圈骨骼,并将上臂扭曲骨骼映射到上臂人类骨骼。 这将是完全错误的。 但是由于长度比的原因,几乎总是可以避免这种情况,并且可以正确绘制骨骼。 长度比发光的另一个地方是脊柱中的骨头。 模型中的脊椎可以包含任意数量的骨骼,但是必须以明智的方式将它们映射到以下人体骨骼:臀部,脊椎,胸部(可选),颈部(可选)和头部。 例如,如果您在书脊中有8个变换,应如何映射它们? 名称没有用,并且骨骼方向都相同。 仅仅尝试平均分配都会带来可怕的结果。 取而代之的是,我们朝着这些长度比例努力:脊柱-胸部应该是臀部-脊柱的1.​​4倍。 胸颈的长度应为脊柱胸部的1.8倍。 颈头的长度应为胸颈的0.3倍。 (类人动物通常会在胸部以下区域弯曲,因为胸部本身会更坚硬。)结果是映射在脊柱中产生弯曲,在模型的骨骼范围内看起来很自然。 该算法选择与期望的长度比尽可能接近的骨骼分配。 在这种情况下,计算“接近度”需要将实际比率和所需比率都转换为对数刻度,并测量两者之间的差。 对数刻度确保的长度是应被惩罚的长度的两倍,而长度是应被补偿的长度的一半。

拓扑结构 (Topology)

Last but not least, the “topology” of the bones play a major role. For example, the neck and the left and right arm must all be children of the chest, so a mapping where one bone is mapped to the neck, but children of that bone are mapped to the left and right shoulder is not an option. Contrary to the other factors described above, the topology requirements work as a hard constraint. The requirements are specified in the form like this

最后但并非最不重要的是,骨骼的“拓扑”起着重要作用。 例如,颈部和左右臂都必须是胸部的子项,因此,不能选择将一根骨骼映射到脖子,而将那个骨骼的子项映射到左右肩膀的映射。 与上述其他因素相反,拓扑要求是硬约束。 要求以这种形式指定

  • The RightShoulder human bone must be a child to the Chest human bone, placed 1-3 levels further down the hierarchy. (1 level would be a child; 2 levels would be a child of a child etc.)

    RightShoulder人类骨骼必须是胸部人类骨骼的孩子,并在层次结构中进一步下移1-3级。 (1个级别将是一个孩子; 2个级别将是一个孩子的孩子,等等。)

  • The RightUpperArm human bone must be a child to the RightShoulder human bone, placed 0-2 levels further down. (A level of 0 means they are the same bone. This is permitted when one of the bones are optional, like the Shoulder ones are.)

    RightUpperArm人体骨骼必须是RightShoulder人体骨骼的子代 ,其位置进一步向下放置0-2。 (0级表示它们是同一根骨骼。当其中一根骨骼是可选的(如“ ”骨)是允许的时,允许这样做。)

  • The RightLowerArm human bone must be a child to the RightUpperArm human bone, placed 1-2 levels further down.

    RightLowerArm人体骨骼必须是RightUpperArm人体骨骼的子级, 并向下放置1-2级。

Most bones allows for a range of levels in between the mapping of itself and its parent. This is because different models have different amounts of transforms in between the principal human bones. For example there might or might not be a twist bone in between an upper arm bone and an elbow bone. The range also function as an optimization, since transforms that are further down the bone hierarchy than the number of levels allowed do not need to be considered as potential matches.

大多数骨骼在其自身与其父对象的映射之间允许一定范围的级别。 这是因为不同的模型在主要人体骨骼之间具有不同数量的变换。 例如,上臂骨和肘骨之间可能有也可能没有扭骨。 该范围还可以用作优化,因为与骨骼层次相比允许的级别数更远的变换无需视为潜在匹配。

最佳映射作为搜索问题 (Optimal Mapping as a Search Problem)

We’ve looked at various hints that can be used as part of the mapping algorithm, but how is it all combined? The solution I arrived at is to treat the mapping as a search problem. Consider the function EvaluateBoneMatch which evaluates a match between a human bone (for example Chest) and a transform (for example “MyModel_Chest”). This function evaluates the match itself according to the keyword, direction, and length ratio hints described above. The result is a score that indicates how good this match is. But the EvaluateBoneMatch function goes further than that. It iterates through all the child human bones. (For the Chest human bone, the children would be LeftShoulder, RightShoulder, and Neck.) For each of those it gathers all the transforms that are potential matches according to the topology requirements, i.e. all transforms n levels down the hierarchy, where n depends on which human bone is being mapped. And for each of those pairs of a child human bone and a transform it calls EvaluateBoneMatch. Since the function calls itself, this is called a recursive function. Each of those calls return a score value that determines how good the match is. Now the function determines the best match for each of the child human bones (LeftShoulder, RightShoulder, and Neck). This is based mostly on the scores, but it can’t simply choose the top ranking choice for each of them, since multiple child bones sometimes pick the same transform as their top choice! More on that later. Anyway, the score for each of the picked child human bone matches is added to the score of the current bone match itself, and the result is what the EvaluateBoneMatch function returns. Confused? It is common for it to take a little while and some effort to wrap one’s head around a recursive function and it sure did for me as I implemented the algorithm. Having many different inter-related hierarchical structures in parallel didn’t make it easier (the human bone hierarchy, the transform hierarchy, and the search graph hierarchy). But the gist of it is that the EvaluateBoneMatch function returns a score that represents not just how good that specific match is in itself, but including the entire child hierarchy of best matches. This in effect means that every bone mapping gets chosen not just based on how good that match is by itself, seen in isolation, but also based on how well it fits as a piece in the entire mapping. Remember how I mentioned that a lot of models incorrectly have the arms as children of a bone called “neck”? Imagine this conversation:

我们已经研究了可以用作映射算法一部分的各种提示,但是如何将它们组合在一起? 我得出的解决方案是将映射视为搜索问题。 考虑一下函数EvaluateBoneMatch ,该函数评估人的骨骼(例如Chest )和变换(例如“ MyModel_Chest”)之间的匹配。 此函数根据上述关键字,方向和长度比率提示来评估匹配项本身。 结果是一个得分,表明该比赛的水平。 但是EvaluateBoneMatch函数的作用远不止于此。 它遍历所有儿童骨骼。 (对于胸部的人类骨骼,子代将为LeftShoulderRightShoulderNeck 。)对于每个子代它将根据拓扑要求收集所有可能匹配的变换,即所有变换在层次结构中向下n个层次,其中n取决于在其上绘制人体骨骼的位置。 对于每对儿童骨骼和转换,它都称为EvaluateBoneMatch。 由于该函数调用自身,因此称为递归函数。 这些调用中的每个调用都会返回一个得分值,该得分值确定匹配的程度。 现在,该功能将确定每个子人体骨骼( LeftShoulderRightShoulderNeck )的最佳匹配。 这主要基于分数,但是不能简单地为每个分数选择排名最高的选项,因为多个子骨骼有时会选择与他们的首选相同的变换! 以后再说。 无论如何,每个被选中的子人类骨骼匹配的分数都将添加到当前骨骼匹配本身的分数中,结果就是EvaluateBoneMatch函数返回的结果。 困惑? 花费一些时间和精力将头绕在递归函数上是很常见的,当我实现该算法时,它确实对我有用。 并行具有许多不同的相互关联的层次结构并没有使它变得更容易(人骨层次,变换层次和搜索图层次)。 但要点是EvaluateBoneMatch函数返回的分数不仅代表特定匹配本身的良好程度,还代表最佳匹配的整个子层次。 实际上,这意味着每个骨骼贴图的选择不仅取决于孤立地单独看到匹配的好坏,而且还取决于它在整个贴图中适合的程度。 还记得我曾提到过很多模型错误地将手臂作为称为“脖子”的骨骼的子代吗? 想象一下这个对话:

Ah, so this is the Neck bone! It’s called “neck” and points upwards and has a good length ratio, so it seems to match. The neck should only have the Head as a child, but there’s some other transform children as well that don’t seem to match any bones in the head. Oh well. … later … Hmm, alternatively we can try to map the bone called “neck” as the Chest bone. This doesn’t score well in terms of keyword matches but let’s try it anyway. This Chest has child transforms that seem to match the LeftShoulder and RightShoulder as well as the Neck. And those left and right shoulders have children that matches the various bones in the arms, and so on. All those matches are worth a lot of points so it ends up being better to match the transform “neck” to the Chest than to the Neck, based on the points obtained from the hierarchy further down.

啊,这就是脖子上的骨头! 它被称为“颈部”,指向上方且具有良好的长度比,因此看起来很匹配。 脖子应该只有一个孩子的头部 ,但是还有其他一些变形的孩子,这些孩子似乎没有与骨头匹配。 那好吧。 ……稍后……嗯,或者我们可以尝试将称为“颈部”的骨骼映射为胸骨 。 就关键字匹配而言,这得分不高,但还是请尝试一下。 这个箱子的子变形似乎与LeftShoulderRightShoulder以及颈部匹配。 那些左,右肩膀上有与手臂各个骨骼相匹配的孩子,依此类推。 所有这些比赛都是值得一分不少,因此它最终被更好地配合改造“脖子”到胸部 ,而不是脖子 ,基于从层级进一步下跌所获得的积分。

With a search based algorithm you get seemingly “smart” considerations like this for free all over the place. It’s very similar to the problem of trying to solve a maze: In order to get to the exit that you know is to the North, you may have to go in the wrong direction some of the way first. Knowing the right direction for even the first step requires knowing the entire solution.

使用基于搜索的算法,您可以在整个地方免费获得看似“智能”的注意事项。 这与尝试解决迷宫的问题非常相似:为了到达您知道向北的出口,您可能必须先朝某些错误的方向前进。 即使第一步也要知道正确的方向,也需要了解整个解决方案。

解决儿童冲突 (Child Conflict Resolution)

Multiple child human bones sometimes pick the same transform as their best matching choice choice. For example the human bone LeftHand have the child human bones ThumbProximal, IndexProximal, MiddleProximal, RingProximal, and LittleProximal. And maybe both RingProximal and LittleProximal picked the transform called “Finger_2” as the first choice. Now what to do? The same finger can’t be both the ring finger and the little finger! For each of the human bones we keep not just the first choice, but a ranked list of choices. To make sure that each transform is only mapped to one human bone, and that the transforms are assigned to the human bones in the best possible way, a function called GetBestChildMatchChoices is called. First we make a list that contains the current choice for each human bone. Initially they’re all set to 0 (the first choice) even if that means there are potential conflicts. We pass that list of current choices to the function, and the function then goes through these steps:

多个儿童骨骼有时会选择相同的变换作为其最佳匹配选择。 例如,人类骨骼LeftHand具有子人类骨骼ThumbProximalIndexProximalMiddleProximalRingProximalLittleProximal 。 也许RingProximalLittleProximal都选择了名为“ Finger_2”的转换作为首选。 现在该怎么办? 同一根手指不能同时是无名指和小指! 对于每个人的骨骼,我们不仅保留第一选择,还保留选择的排名列表。 为确保每个变换仅映射到一个人体骨骼,并确保以最佳方式将这些变换分配给人体骨骼,将调用一个名为GetBestChildMatchChoices的函数。 首先,我们创建一个列表,其中包含每个人体骨骼的当前选择。 最初,它们都设置为0(第一选择),即使这意味着存在潜在的冲突。 我们将当前选择的列表传递给函数,然后函数执行以下步骤:

  1. For each of those human bones, try out an alternative list of current choices where this human bone retains its current choice and all the other human bones in the conflict have to use their next choice on their priority lists. For each of those alternative lists of current choices, call the GetBestChildMatchChoices function. (Yes it’s a recursive function again.)

    对于每个人骨,尝试一个当前选择的替代列表,其中该人骨保留其当前选择,而冲突中的所有其他人骨必须在其优先级列表上使用其下一个选择。 对于每个当前选择的替代列表,请调用GetBestChildMatchChoices函数。 (是的,它又是一个递归函数。)

This procedure basically tests all permutations and chooses the best scoring one. Before I came up with this approach I had initially just implemented an approach where the human bone with the best scoring match got its first choice, the human bone with the next best scoring match would get its first choice excluding the already picked, and so on. This was faster computationally and easier to understand, but unfortunately it often resulted in incorrect results. The illustration below demonstrates the difference between picking the best individual match versus the best overall match for all siblings.

此过程基本上测试所有排列并选择得分最高的一个。 在我提出这种方法之前,我最初只是采用了一种方法,其中得分最高的人的骨骼获得了第一选择,得分次高的人的骨骼将获得其选择的第一选择,依此类推。 。 计算速度更快,更容易理解,但是不幸的是,它经常导致错误的结果。 下图说明了为所有兄弟姐妹选择最佳个人比赛与最佳整体比赛之间的区别。

最佳化 (Optimizations)

Since the search evaluates many hundreds of possible mappings for a typical avatar, the auto-mapping started to get a bit slow at some point. A lot of the time was spent with string handling related to trying to match keywords, but other parts of the evaluations also took up significant time. I realized that the same pair of human bone and transform was being evaluated many times as part of different possible mappings. The biggest optimization was achieved by caching the results of such an evaluation and simply use the cached result the next time the same pair needed to be evaluated. Different parts of the cached data needed to be cached differently because they had different amounts of needed context. A keyword evaluation only needs the human bone and transform themselves, but the evaluation of bone length ratios need the parent match and grandparent match as well, since they are used for calculating the lengths. In the end I used a design where I cache the result of an entire EvaluateBoneMatch call based on a pair and the parent and grandparent pairs. If a potential pair needs to be evaluated and the cache already has an existing evaluation for the same pair with the same parent and grandparent, that result is used and the call to EvaluateBoneMatch is skipped altogether for that pair. If it doesn’t exist, EvaluateBoneMatch is called to do the evaluation, but some of the sub-routines that evaluate keywords etc. use their own caching that requires less context and hence is more likely to have already been evaluated before. Using these cached result sped up the evaluation times by a factor of 8. After that, it was fast enough that the entire Auto-Setup process was no longer a bottleneck. (It usually takes less than a second which is a fraction of what the model import process takes.) Doing high-level optimization like this is often very satisfying since it can change the fundamental time complexity of an algorithm which can often result in very big improvements.

由于搜索为典型的化身评估了数百种可能的映射,因此自动映射有时会变得有点慢。 与尝试匹配关键字相关的字符串处理花费了大量时间,但是评估的其​​他部分也占用了大量时间。 我意识到,作为不同可能映射的一部分,同一对人的骨骼和变换正在被多次评估。 最大的优化是通过缓存这种评估的结果,并在下次需要评估同一对时简单地使用缓存的结果来实现的。 缓存数据的不同部分需要进行不同的缓存,因为它们具有不同数量的所需上下文。 关键字评估只需要人的骨骼并进行自我转换,但是骨骼长度比率的评估也需要父匹配和祖父母匹配,因为它们用于计算长度。 最后,我使用了一种设计,在该设计中,我基于一对以及父对和祖父母对缓存了整个EvaluateBoneMatch调用的结果。 如果需要评估一个可能的对,并且缓存中已经具有相同的对以及具有相同的父级和祖父母的现有评估,则将使用该结果,并且将完全跳过对该对EvaluateBoneMatch的调用。 如果不存在,则会调用EvaluateBoneMatch进行评估,但是一些评估关键字等的子例程将使用自己的缓存,这些缓存需要较少的上下文,因此很有可能之前已经被评估过。 使用这些缓存的结果将评估时间缩短了8倍。此后,它足够快,以至于整个自动设置过程不再是瓶颈。 (通常花费不到一秒钟的时间,这只是模型导入过程所需时间的一小部分。)进行这样的高级优化通常是非常令人满意的,因为它可以改变算法的基本时间复杂度,这通常会导致很大的结果改进。

特殊处理 (Special Handling)

The Auto-Mapping algorithm was designed for to be primarily data-driven. I wanted to avoid a solution that had all kinds of hard-coded rules for different parts of the body, since code like that is often brittle and error-prone, and doesn’t lend itself to the kind of search-based solution I could see would be necessary for good results. Nevertheless, some compromises ended up being necessary. One compromise is that the search for the body mapping stops at the hands rather than including all the fingers. The fingers include more bones than the entire rest of the body, and excluding all that from the body mapping search reduced the search time significantly. Instead, the fingers are mapped by themselves starting from the hand bones found in the body mapping search. Another thing that’s handled in a special way is the assumption about body orientation. As mentioned earlier, the search algorithm takes hints from the directions of the various bones. However, sometimes a model is imported in Unity with a completely arbitrary rotation and all the assumptions about bone orientations are wrong. The remaining hints are usually enough to map some parts of the body well enough, but the fingers, if present, are often mapped completely wrong in those cases. To counter this we check the positions of left and right hip and shoulder after a mapping is completed, and derive the body orientation from those positions. If the body orientation is significantly different than the assumed one where +z is forward and +y is up, then we redo the entire mapping based on the now known actual orientation. In this second pass the bones are usually mapped with much higher rate of correctness.

自动映射算法设计为主要由数据驱动。 我想避免使用针对身体不同部位的各种硬编码规则的解决方案,因为这样的代码通常易碎且容易出错,并且不适合我可以使用的基于搜索的解决方案看到必要的以获得良好的结果。 尽管如此,最终还是需要做出一些妥协。 一种折衷方案是,搜索身体部位的操作要从手上开始,而不要包括所有手指。 手指的骨骼多于整个身体的其余部分,并且从人体映射搜索中排除所有骨骼的时间大大减少了。 而是从身体映射搜索中找到的手骨头开始自己映射手指。 以特殊方式处理的另一件事是关于身体朝向的假设。 如前所述,搜索算法从各个骨骼的方向获取提示。 但是,有时会以完全任意旋转的方式在Unity中导入模型,并且所有关于骨骼方向的假设都是错误的。 其余的提示通常足以将身体的某些部位映射得足够好,但是在这种情况下,手指(如果存在的话)通常会映射完全错误。 为了解决这个问题,我们在完成映射后检查左右臀部和肩膀的位置,并从这些位置得出身体的方向。 如果身体方向与假定的方向(+ z朝前且+ y向上)显着不同,则我们将基于现在已知的实际方向重做整个映射。 在第二遍中,通常以更高的正确率绘制骨骼。

测试框架 (Testing Framework)

While implementing the automatic setup I also created a function for automatically testing and validating the automatic setup for a model. Every time we have come across a model where the auto-setup fails, we have added it to the testing framework, provided a sensible setup is possible to do manually in the first place. (Some models don’t have a proper skeletal hierarchy at all. Those are not compatible with Mecanim humanoid animation, so obviously auto-mapping won’t work for those.) At this time we have around 30 models in the framework, which include a lots of humans with different proportions as well as some fantasy and toon characters with completely different proportions and a few robots. Among them the models have wildly varying rigs. While the auto-mapping is based on a solid algorithm, there is a lot of tweaking involved in determining which hints should contribute how much in the scoring. Having the testing framework has been essential to being able to tweak those parameters and be able to immediately test that it fixes the intended edge cases without causing regressions for other characters. If you have any characters that you CAN do a manual setup for, but which the automatic setup did not handle satisfactory, you are welcome to send the models in question in a bug report. Include the words “avatar auto-mapping” in the first line of the description. We can’t guarantee that we’ll be able to make the auto-setup handle every single model correctly, but being aware of problematic cases provides us with a better basis for attempting it.

在实现自动设置的同时,我还创建了一个用于自动测试和验证模型自动设置的功能。 每次遇到自动设置失败的模型时,我们都会将其添加到测试框架中,前提是首先可以手动进行明智的设置。 (有些模型根本没有适当的骨骼层次。这些模型与Mecanim人形动画不兼容,因此显然自动映射不适用于这些模型。)目前,框架中大约有30个模型,其中包括许多比例不同的人类,以及比例完全不同的一些幻想和卡通人物以及一些机器人。 其中的模型装备千差万别。 尽管自动映射基于可靠的算法,但在确定哪些提示应在得分中占多少方面需要进行大量调整。 拥有测试框架对于能够调整这些参数并能够立即测试其是否可以修复预期的边缘情况至关重要,而不会导致其他字符的退化。 如果您有任何可以手动设置的字符,但自动设置不能令人满意的字符,欢迎您在错误报告中发送有问题的模型。 在描述的第一行中包含“头像自动映射”一词。 我们不能保证能够使自动设置正确处理每个模型,但是了解有问题的情况为我们提供了更好的尝试基础。

结论 (Conclusion)

I’ve covered the primary functionality of the Auto-Mapping for humanoid characters in Unity. The Auto-Setup includes other functions as well, such as getting the character into T-pose, but those are outside of the scope for this post, and not quite as interesting and challenging anyway. The Auto-Mapping is an interesting feature in that it contains quite advanced functionality yet is practically invisible to the user. It’s very purpose is to be something you don’t have to think about at all. Of course it doesn’t always work out that way in all cases – for some models here and there the automatic mapping fails and then you’re suddenly painfully aware of it. But for the majority of cases, the Humanoid Animation Type is just a setting you can enable, and then not have to think about. Instead you can get on with the real fun of animating your characters.

我已经介绍了Unity中针对人形字符的自动映射的主要功能。 自动设置还包括其他功能,例如将角色放入T型姿势,但这些功能不在本文讨论范围之内,无论如何都不是那么有趣和具有挑战性。 自动映射是一个有趣的功能,因为它包含相当高级的功能,但实际上对用户是不可见的。 这是非常重要的,目的是使您完全不必考虑任何事情。 当然,并非在所有情况下都总是这样工作-对于某些模型,自动映射失败了,您突然痛苦地意识到了这一点。 但在大多数情况下,“人形动画类型”只是您可以启用的设置,而不必考虑。 取而代之的是,您可以继续享受动画角色的真正乐趣。

翻译自: https://blogs.unity3d.com/2013/02/07/automatic-setup-of-a-humanoid/

python 人形自动标注

python 人形自动标注_自动设置人形生物相关推荐

  1. 在基于图像的深度学习中如何做数据的自动标注以及自动标注的等级介绍

    作者:Tobias Schaffrath Rosario 编译:ronghuaiyang 原文:在基于图像的深度学习中如何做数据的自动标注以及自动标注的等级介绍_ronghuaiyang的博客-CSD ...

  2. 字体方向 道路标注_自动驾驶环境感知的“见闻色”——3D点云标注

    点开网约车App.线上报名.待审核通过后,用户就能在规定的测试路段免费呼叫自动驾驶车辆进行试乘--前不久,滴滴出行首次面向公众开放自动驾驶服务. 这次行业事件再次激发了公众对于自动驾驶的热切期待与探索 ...

  3. python默认编码方式_关于设置python默认编码方式的问题

    2019-8-27 07:45:36 本帖最后由 傻纸 于 2019-8-27 10:02 编辑 查了一会资料得出的结论是如果你用的是python3.x,那么就最好别去设置sys.defaultenc ...

  4. excel自动筛选_自动更改Excel筛选器标题

    excel自动筛选 There was a question about Excel Advanced Filter criteria on the Tech Republic blog recent ...

  5. python爬虫-国家企业_自动查企业工商登记信息(企业信用信息公示系统、极验Geetest与Python爬虫)...

    一.引言: 信贷作业的过程就是信息搜集和验证的过程.对于企业客户,最权威的信息渠道莫过于工商登记信息,各种第三方查询工具(天眼查.启信宝.各种各样的API等等)也来源于此. 常见的问题在于,我们不仅要 ...

  6. python仿真智能驾驶_自动驾驶仿真工程师

    禁止私自转载,转载请联系作者. 想要做一个自动驾驶仿真工程师,我们要学的还远远不够. 对自动驾驶仿真工程师这个岗位,相关介绍还是少了些.有些公司是直接把它纳入到基础架构组里,有些是单独招聘这个岗位,还 ...

  7. python 保存文件 递增_自动递增文件名Python - python

    我试图编写一个函数,该函数将路径名和文件名分配给基于文件名(而不是文件夹中存在)的变量.然后,如果文件名已经存在,则文件名将自动递增.我已经看到了一些使用while循环的帖子,但是我对此一无所知,想将 ...

  8. python图像开闭区间_自动开闭器不良故障案例分析

    问题:怎样才能每天收到这种文章? 答案:点击上方蓝色字体,再点击关注即可! 一.故障概况 某年10月26日13:00分,某站的16/18号道岔在排列进路时,从定位操纵到反位时,反位无表示. 二.监测数 ...

  9. python自动控制原理_自动控制原理(山东联盟-中国石油大学(华东))知到答案2020年MOOCPython语言程...

    自动控制原理(山东联盟-中国石油大学(华东))知到答案2020年MOOCPython语言程序设计测试答案 更多相关问题 设有一半径为a的介质圆球,置于一均匀磁场B之中,且绕通过其球心的某一固定轴,以角 ...

最新文章

  1. 基于Python, Selenium, Phantomjs无头浏览器访问页面
  2. php 线条的绘制,在非常高的图像上使用PHP绘制线条,脚本停止绘制.怎么了,怎么解决?...
  3. Android ContentResolver
  4. Spring - @CompentScan全解
  5. spcomm控件的使用
  6. php如何根据ip查找地址,根据IP地址查找IP所在地
  7. 孤立森林(iForest - Isolation Forest)
  8. spoon mysql教程_kettle 教程(一):简介及入门
  9. VB+ACCESS酒店服务管理系统
  10. 作为非计算机专业的我,是如何拿下软考软件设计师的?
  11. 视频教程-手把手教你掌握区块链技术视频教程-区块链
  12. 用javascript源码打印页面
  13. HW-RTOS 概述
  14. android 日历动态图标,android 日历图标显示星期
  15. 使用融资的心得和教训
  16. 【思维题】Bazinga
  17. 9.22生日——随笔
  18. the unfamiliar words and sentences of《The Great Gatsby》1
  19. 面试最后我一般会问面试官什么问题
  20. javascript代码操作记录

热门文章

  1. android系统智能手表 开箱,安卓智能手表不知如何选择?先看评测告诉你答案
  2. 什么是死锁?死锁的产生条件及解决办法
  3. 利用LightGBM对波士顿房价进行模拟和预测
  4. PAT 乙级 1001 害死人不偿命的(3n+1)猜想(C语言)
  5. viso转高精度矢量PDF
  6. UE4 插值FInterpEaseInOut和Ease
  7. 青岛大学超级计算机,湖南商学院成功主办2019年国家社科基金申报经验交流会...
  8. 物联网毕业设计-基于stm32的温湿度监控系统
  9. thinkphp5 调用支付宝支付电脑版
  10. 互联网学习(一):网络数据传输