- UMA_DCS prefab 加上 UMA Dynamic Character Avatar, 选择一个race,然后设置好默认的animator controller就可以运行了。 
- base recipe –> 确定一个裸体的人物模型。 
 wardrobe recipe –> 确定人物的衣服,鞋子,饰品等;这里可以设置A物体覆盖B物体。
- Dynamic Character Avatar中的Default Recipes可以为这个人物添加默认的衣服裤子等。每个Wardrobe recipe都只能和相对应的race一起才能正常工作。Wardrobe slot是设置这个物体是放在人身上的哪个部位的。还可以设置需要覆盖哪个部位的其他物件和base物件。 
- Dynamic Character Avatar中的Character Colors可以重载recipes中的shared colors,然后在slot中可以用shared color来影响overlay的颜色。这样就可以通过设置Character Colors来方便的设置人物的整体颜色。 
- 所有的recipes和他们所用到的components都需要到UMA Global Library中去注册才能使用。制作DCS->wardrobe recipe 
- Misc->Mesh Hide Asset,可以用来隐藏某个slot上的某些三角形,已解决衣服和身体部分重叠的情况下的穿模问题。UMA内建工具可以编辑需要去掉那些三角形。在编辑的时候还可以把衣服覆盖在身体上,方便查看需要隐藏哪些三角形。 
- 通过代码来改变人物的外貌 - 得到DynamicCharacterAvatar实例:- 1 
 2
 3
 4- using UMA; 
 using UMA.CharacterSystem;
 DynamicCharacterAvatar avatar = GetComponent<DynamicCharacterAvatar>();
- 设置Dna:- 1 
 2
 3
 4
 5
 6
 7
 8- //得到所有的DnaSetter 
 Dictionary<string, DnaSetter> dna = avatar.GetDNA();
 //设置height dna
 dna["height"].Set(1f);
 //得到height dna
 dna["height"].Get();
 //重建人物
 avatar.BuildCharacter();
- 改变种族:- 1 
 2
 3
 4
 5- // 把race改成HumanMaleDCS,改变后不需要调用BuildCharacter, 
 // race改变后所对应的dnaSetter的字典也会改变。
 avatar.ChangeRace("HumanMaleDCS");
 // 得到当前种族
 avatar.activeRace;
- 监听avatar的事件:- 1 
 2
 3- // DynamicCharacterAvatar的一些时间可以通过下面类似的方法添加和删除。 
 avatar.CharacterUpdated.AddListener()
 avatar.CharacterUpdated.RemoveListener()
- 设置颜色:- 1 
 2
 3
 4- avatar.SetColor("Skin", Color.Black);// 设置名字为Skin的sharedColor的颜色为black 
 // true就是函数内部马上调用BuildCharacter,颜色马上就显示出来
 // false则把新颜色缓存者,到下次BuildCharacter才会显示在人物上。
 avatar.UpdateColors(true);
- 得到颜色:- 1 - avatar.GetColor("Skin").color; 
- 操作slot:- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- // 把名字为Hair的slot设置成MaleHair1这个配件。 
 avatar.SetSlot("Hair", "MaleHair1");
 //重建人物
 avatar.BuildCharacter();
 // 把名字为Hair的slot清空
 avatar.ClearSlot("Hair");
 //重建人物
 avatar.BuildCharacter();
 // 得到名字为Hair的slot的item的名字
 avatar.GetWardrobeItemName("Hair");- UMA 101 - Part 11 Simple Character Creator (2 of 3) 
 UMA 101 - Part 11a Simple Character Creator (2a of 3)
 
- Save/Load一个人物 - 1 
 2
 3
 4
 5
 6
 7- // 这里可以得到一个json编码的字符串,保存了所有和当前人物相关的配置信息。 
 string recipeToBeSaved = avatar.GetCurrentRecipe();
 // load之前需要清空所有的slots,不然如果load出来的人物没有相对应的slot的信息,
 // 那么之前的slot将会被laod出来的人物保留着。
 avatar.ClearSlots();
 // 从一个string的recipe中load一个人物
 avatar.LoadFromRecipeString(recipeToBeSaved);
- Utility Recipes就是类似于wardrobe recipes的东西,但是他不是给人物添加衣服的,而是给人物添加一个功能性的脚本,这个脚本可以自定义做很多事情。UMA里面内建了两个比较有用的Utility Recipes。 - ForearmTwistRecipe,用来解决手腕在绕着手臂旋转时,手腕和手臂连接处会不自然的扭曲到一起的问题。用了这Recipe后,旋转手腕会和正常人那样自然。
- ExpressionsRecipe,用来解决人物下巴往下掉的问题。因为如果动画中没有下巴的动画,那么下巴会在建模时的位置,一般都是在下面,让嘴巴张开的。加了这个Recipe,就可以调整下巴,让嘴巴比起来。当然还可以调整很多五官的位置的。
 
- Expression Player可以控制人物的面部表情。内建的Enable Blinking可以让人物随机间隔的眨眼,Enable Saccades可以让眼球像真人那样转动。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98- using UMA; 
 using UMA.CharacterSystem;
 using UMA.PoseTools; // for Expression Player
 private ExpressionPlayer expression;
 // OnUMACreated
 expression = GetComponent<ExpressionPlayer>();
 expression.enableBlinking = true; // 激活眨眼
 expression.enableSaccades = true; // 激活眼球运动
 // void Update,实现各种表情
 float delta = 10 * Time.deltaTime;
 switch(mood)
 {
 case 0: // Normal
 expression.leftMouthSmile_Frown = Mathf.Lerp(expression.leftMouthSmile_Frown,0,delta);
 expression.rightMouthSmile_Frown = Mathf.Lerp(expression.rightMouthSmile_Frown,0,delta);
 expression.midBrowUp_Down = Mathf.Lerp(expression.midBrowUp_Down,0,delta);
 expression.leftBrowUp_Down = Mathf.Lerp(expression.leftBrowUp_Down,0,delta);
 expression.rightBrowUp_Down = Mathf.Lerp(expression.rightBrowUp_Down,0,delta);
 expression.rightUpperLipUp_Down = Mathf.Lerp(expression.rightUpperLipUp_Down,0,delta);
 expression.leftUpperLipUp_Down = Mathf.Lerp(expression.leftUpperLipUp_Down,0,delta);
 expression.rightLowerLipUp_Down = Mathf.Lerp(expression.rightLowerLipUp_Down,0,delta);
 expression.leftLowerLipUp_Down = Mathf.Lerp(expression.leftLowerLipUp_Down,0,delta);
 expression.mouthNarrow_Pucker = Mathf.Lerp(expression.mouthNarrow_Pucker,0,delta);
 expression.jawOpen_Close = Mathf.Lerp(expression.jawOpen_Close,0,delta);
 expression.noseSneer = Mathf.Lerp(expression.noseSneer,0,delta);
 expression.leftEyeOpen_Close = Mathf.Lerp(expression.leftEyeOpen_Close,0,delta);
 expression.rightEyeOpen_Close = Mathf.Lerp(expression.rightEyeOpen_Close,0,delta);
 break;
 case 1: // Happy
 expression.leftMouthSmile_Frown = Mathf.Lerp(expression.leftMouthSmile_Frown,0.7f,delta);
 expression.rightMouthSmile_Frown = Mathf.Lerp(expression.rightMouthSmile_Frown,0.7f,delta);
 expression.midBrowUp_Down = Mathf.Lerp(expression.midBrowUp_Down,-0.7f,delta);
 expression.leftBrowUp_Down = Mathf.Lerp(expression.leftBrowUp_Down,0f,delta);
 expression.rightBrowUp_Down = Mathf.Lerp(expression.rightBrowUp_Down,0f,delta);
 expression.rightUpperLipUp_Down = Mathf.Lerp(expression.rightUpperLipUp_Down,0f,delta);
 expression.leftUpperLipUp_Down = Mathf.Lerp(expression.leftUpperLipUp_Down,0f,delta);
 expression.rightLowerLipUp_Down = Mathf.Lerp(expression.rightLowerLipUp_Down,-0f,delta);
 expression.leftLowerLipUp_Down = Mathf.Lerp(expression.leftLowerLipUp_Down,-0f,delta);
 expression.mouthNarrow_Pucker = Mathf.Lerp(expression.mouthNarrow_Pucker,0f,delta);
 expression.jawOpen_Close = Mathf.Lerp(expression.jawOpen_Close,0f,delta);
 expression.noseSneer = Mathf.Lerp(expression.noseSneer,0.1f,delta);
 expression.leftEyeOpen_Close = Mathf.Lerp(expression.leftEyeOpen_Close,-0.2f,delta);
 expression.rightEyeOpen_Close = Mathf.Lerp(expression.rightEyeOpen_Close,-0.2f,delta);
 break;
 case 2: // Sad
 expression.leftMouthSmile_Frown = Mathf.Lerp(expression.leftMouthSmile_Frown,-0.8f,delta);
 expression.rightMouthSmile_Frown = Mathf.Lerp(expression.rightMouthSmile_Frown,-0.8f,delta);
 expression.midBrowUp_Down = Mathf.Lerp(expression.midBrowUp_Down,0.7f,delta);
 expression.leftBrowUp_Down = Mathf.Lerp(expression.leftBrowUp_Down,-0.3f,delta);
 expression.rightBrowUp_Down = Mathf.Lerp(expression.rightBrowUp_Down,-0.3f,delta);
 expression.rightUpperLipUp_Down = Mathf.Lerp(expression.rightUpperLipUp_Down,0f,delta);
 expression.leftUpperLipUp_Down = Mathf.Lerp(expression.leftUpperLipUp_Down,0,delta);
 expression.rightLowerLipUp_Down = Mathf.Lerp(expression.rightLowerLipUp_Down,0f,delta);
 expression.leftLowerLipUp_Down = Mathf.Lerp(expression.leftLowerLipUp_Down,0f,delta);
 expression.mouthNarrow_Pucker = Mathf.Lerp(expression.mouthNarrow_Pucker,-0.7f,delta);
 expression.jawOpen_Close = Mathf.Lerp(expression.jawOpen_Close,0f,delta);
 expression.noseSneer = Mathf.Lerp(expression.noseSneer,-0.1f,delta);
 expression.leftEyeOpen_Close = Mathf.Lerp(expression.leftEyeOpen_Close,0.5f,delta);
 expression.rightEyeOpen_Close = Mathf.Lerp(expression.rightEyeOpen_Close,0.5f,delta);
 break;
 case 3: // Angry
 expression.leftMouthSmile_Frown = Mathf.Lerp(expression.leftMouthSmile_Frown,-0.3f,delta);
 expression.rightMouthSmile_Frown = Mathf.Lerp(expression.rightMouthSmile_Frown,-0.3f,delta);
 expression.midBrowUp_Down = Mathf.Lerp(expression.midBrowUp_Down,-1f,delta);
 expression.leftBrowUp_Down = Mathf.Lerp(expression.leftBrowUp_Down,1f,delta);
 expression.rightBrowUp_Down = Mathf.Lerp(expression.rightBrowUp_Down,1f,delta);
 expression.rightUpperLipUp_Down = Mathf.Lerp(expression.rightUpperLipUp_Down,0.7f,delta);
 expression.leftUpperLipUp_Down = Mathf.Lerp(expression.leftUpperLipUp_Down,0.7f,delta);
 expression.rightLowerLipUp_Down = Mathf.Lerp(expression.rightLowerLipUp_Down,-0.7f,delta);
 expression.leftLowerLipUp_Down = Mathf.Lerp(expression.leftLowerLipUp_Down,-0.7f,delta);
 expression.mouthNarrow_Pucker = Mathf.Lerp(expression.mouthNarrow_Pucker,0.7f,delta);
 expression.jawOpen_Close = Mathf.Lerp(expression.jawOpen_Close,-0.3f,delta);
 expression.noseSneer = Mathf.Lerp(expression.noseSneer,0.3f,delta);
 expression.leftEyeOpen_Close = Mathf.Lerp(expression.leftEyeOpen_Close,-0.2f,delta);
 expression.rightEyeOpen_Close = Mathf.Lerp(expression.rightEyeOpen_Close,-0.2f,delta);
 break;
 case 4: // Surprised
 expression.leftMouthSmile_Frown = Mathf.Lerp(expression.leftMouthSmile_Frown,0f,delta);
 expression.rightMouthSmile_Frown = Mathf.Lerp(expression.rightMouthSmile_Frown,0f,delta);
 expression.midBrowUp_Down = Mathf.Lerp(expression.midBrowUp_Down,1f,delta);
 expression.leftBrowUp_Down = Mathf.Lerp(expression.leftBrowUp_Down,1f,delta);
 expression.rightBrowUp_Down = Mathf.Lerp(expression.rightBrowUp_Down,1f,delta);
 expression.rightUpperLipUp_Down = Mathf.Lerp(expression.rightUpperLipUp_Down,0f,delta);
 expression.leftUpperLipUp_Down = Mathf.Lerp(expression.leftUpperLipUp_Down,0f,delta);
 expression.rightLowerLipUp_Down = Mathf.Lerp(expression.rightLowerLipUp_Down,-0f,delta);
 expression.leftLowerLipUp_Down = Mathf.Lerp(expression.leftLowerLipUp_Down,-0f,delta);
 expression.mouthNarrow_Pucker = Mathf.Lerp(expression.mouthNarrow_Pucker,-1f,delta);
 expression.jawOpen_Close = Mathf.Lerp(expression.jawOpen_Close,0.8f,delta);
 expression.noseSneer = Mathf.Lerp(expression.noseSneer,-0.3f,delta);
 expression.leftEyeOpen_Close = Mathf.Lerp(expression.leftEyeOpen_Close,1f,delta);
 expression.rightEyeOpen_Close = Mathf.Lerp(expression.rightEyeOpen_Close,1f,delta);
 break;
 default:
 break;
 }- 在AssetStore上有个插件LipSync Pro可以更好利用ExpressionPlayer来控制表情 
- UMA和其他插件的整合 - 许多插件要求人物上必须有Animator组件,但是UMA的Aniamtor组件是运行时动态生成的,这就会有问题。但是其实可以先在人物上放置一个空的Animator组件,UMA运行后会找个这个Animator并正确初始化它。
 - 许多插件要求人物上必须有骨骼结构,但是UMA的骨骼结构同样是运行时才生成的,这又是个问题。但是现在可以通过UMA->Bone Builder菜单,预先生成静态的骨骼结构在人物上,然后运行时UMA会找到这个静态骨骼结构,并和UMA关联起来,而不会重新生成一个新的骨骼结构。
- 有个小问题,这个预先生成的骨架是从UMA的原始FBX文件中得到的,和预览用的dummy人物不相符。UMA Bone Visualizer可以在没有运行的时候在scene中显示骨架。
- 可以在这个预先生成的骨架上绑定新的骨头,用来绑定武器等附件,但是需要注意在骨架结构中不能出现相同名字的骨头,哪怕在不同的层次下。