Mecanim学习笔记

1、步骤

将Rig模式更换为Humanoid,在Humanoid这个模式下才能完全的发挥出Mecanim的强大优势,然后在Avatar Definition 选项里面选择Create From This Model,表示此模型的骨架结构是按照目前的角色来设置,勾选Keep Additional Bones,按下Apply,再按Configure进入骨架设置面板。

接下来是对rifle_aiming_idle动作文件进行Animations的设置,勾选Loop Pose, Root Transform Rotation > Bake into Pose, Root Transform Position(Y) > Bake into Pose与Root Transform Position(XZ) > Bake into Pose,其他的部分保存默认的设置即可,最后按下Clamp Range将动作文件的帧数分割出来,按下Apply完成动作的设置。

另外一个设置是对于动作复制的功能,也就是将swat模型现在的动作复制(Retarget)到另外一个角色上面

就我们在导入Model,设置他的Scale属性之后,要重新Configure,不然骨骼会有一些不对应,做法就是设置Rig->Generic后再重新设置Rig->Humanoid

还有就是Configure不仅可以设置骨骼,还可以设置Muscles,如可以让主角的脚分离一点,让主角的手不能穿透身体


在presslayer里,
Mask           选择创建好的Avatar Mask,意思是在本layer,Mask设置的上图的红色部分都被屏蔽了,只有绿色部分在本layer能动。
Blending     override表示该layer的动作会覆盖其他layer动作,addictive表示该layer的动作会与其他layer动作混合。

Inverse Kinematics, 反向动力学,一般来说骨骼动画都是传统的从父节点骨骼到子节点骨骼一直到根节点骨骼的带动方式。但很多情况,如行走时踩到一块石头落脚点比动画要高时,这时候就需要IK了。IK是指骨骼动画都是从根节点骨骼一直到父节点骨骼的带动方式。

下图第一步设置IK权重,第二步设置LeftHand这个根骨骼的位置


2、优缺点

做完了例子,再来说说这个Mecanim动画系统的优缺点吧。

优点:

1、不同骨骼的模型可以较简单的共享骨骼动画;

2、状态机的控制会比较有系统性。

 

缺点:

1、Unity内置的Avatar似乎只针对标准的两足类生物,比如人。当然你要做四足类的估计还是可以的,但多足类的大概就不行了。而且人物身上假如还有翅膀、飘带、裙摆等骨骼的话,就不能直接对应Avatar了。

2、Animator Controller必须手动的拖给人物模型的Animator组件上。虽然也有编辑器的方法可以批量的指定。但发布后想在运行途中用脚本修改Animator Controller是很困难的(不是绝对不行,而是需要特殊的方法)。这样就增大了对编辑器的依赖性,减低了控制的灵活性。

3、Mecainm系统动画不适用于assetBundle。也就是说,这个动画系统无法用于网络资源的动态加载。包括了整个角色带Animator Controller导出或者分开导出,再加载进来都无法使用。这是致命的伤害,只能做一些小的演示,或者全部资源都放在一起打包发布的项目。


3、Mecanim打包的问题

Avatar没问题的,我尝试三种打包方式:
1. 利用push\pop方式,把控制器和模型(含Avatar)依赖打包。然后按顺序加载,无效。
2. 分别打包模型和动画控制器,然后加载出来组装,无效。
3. 整包(模型和动画控制器)打成一个Assetbundle,然后实例化出来正常。

前两种方式加载出来,但就是不播放,在Inspector面板Animator组件上可以看到有Controller和Avatar, 但组件下方有个提示:Not initialized  . 

所以我无法确定目前版本是否支持AnimatorController单独打包成AssetBundle加载?

IEnumerator Download(string url) { WWW www = new WWW(url); yield return www; if (www.isDone) { if (!string.IsNullOrEmpty(www.error)) { Debug.LogError(www.error); yield return true; } Object obj = [url=http://www.assetBundle.mainAsset]www.assetBundle.mainAsset[/url]; if (obj != null) { m_npc.GetComponent<Animator>().runtimeAnimatorController = (RuntimeAnimatorController)RuntimeAnimatorController.Instantiate(obj); } } }

4、其他

http://www.xuanyusong.com/archives/2222

另外Mecanim还支持多个动画的混合。目前Mecanim还有一个最大的难题,也是文章最上面我说的需要美术配合的那部分。之前我们看到的动画都是应用于人型模型,也就是说它支持人形的骨骼, 举个例子我们的项目人和武器是两个骨骼,这样在用Mecanim就悲剧了。因为不同模型武器的骨骼不一样所以公用模型的话会出现武器位置不对的情况。最后我想到的办法就是美术将以前做的武器骨骼重新导出,每个人对应一套自己武器骨骼(或者一些特殊的骨骼)最后生成武器的动画 ,比如 站立动画、攻击动画、死亡动画等。当Mecanim播放动画的时候,同时在播放该模型对应的武器动画,我想这样就可以解决这个问题吧。。

在复杂的状态机中,预览独立的状态机中的某些部分是很有用的。为了做到这些,你可以使用Mute/Solo功能。Muting表示转移会被禁止。Solo被选择时,表示其他的状态转移都源自相同的状态。你可以从状态转移检视器中选择mute和solo状态,或者从可以看到所有状态转移的状态显示器中选择(推荐)。

(注:这个段翻译的很混乱,但是根据实践结果发现:

  1. 如果选择了mute,那么被选择的状态转移一定会被禁用;
  2. 如果不选择solo,在没有变量控制(结束条件为“exit time”)的情况下,该状态优先选择动作列表中最前(或者说最上的)的状态转移;
  3. 如果选择了某个solo,那么在没有变量控制(结束条件为“exit time”)的情况下,优先选择标记solo的状态转移;
  4. 如果有多个状态转移选中了solo,那么优先选择这些已选中solo的状态转移中,在动作列表中靠前的状态转移;
  5. 暂未实验使用参数控制的转移情况。)

动画转换 (Animation Transition) 定义从一个 动画状态 (Animation State) 在任何给定时间都只能有一个转换处于活动状态。

属性: 功能:
原子 (Atomic) 此转换是否为原子转换?(无法中断)
条件 (Conditions) 在此处决定触发转换的时间时间。.

一些脚本

#pragma strict

internal var animator : Animator; // var to store the animator component
var h : float; // variable to hold user horizontal input, turns
var v : float; // variable to hold user vertical input, forward/backward
var rotSpeed : float  = 90.0; //rotation speed
var j : int; // variable to hold user jump input
var canJump : boolean = true; //flag to control the jumping
var grounded : boolean = true; // flag for in air or on ground 
internal var windedState : int; // need to coordinate with animator
internal var layers : int; // layers in the Animator


function Start () {

	animator = GetComponent(Animator); // assign the Animator component
	layers = animator.layerCount;
	if (layers >= 2) {
	    for (var i : int = 1; i < layers; i++ ) { 
	          animator.SetLayerWeight(i, 1);
	    }
	}	
	
	// assign the Winded State parameter from the animator to windedState
 	windedState = animator.GetInteger ("Winded State");
}

function Update () {

	if (windedState == 2) Input.ResetInputAxes(); // block player input
	
	// Get Input each frame and assign it to the variables
	h = Input.GetAxis("Horizontal");
	v = Input.GetAxis("Vertical");	
	j = Input.GetAxis("Jump");	
	//print (j);
	if (Input.GetAxis("Fire3")== 1) ProcessWinded();
}

function FixedUpdate () {

	var stateInfo : AnimatorStateInfo  = animator.GetCurrentAnimatorStateInfo(0);

   // Set the V Input parameter to the V axis value
   animator.SetFloat ("V Input", v);
   
if (windedState == 0) {  
	// rotate the character according to input and rotation speed
	transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed,0)); 
}

   // Set the Turning parameter to the H axis value
	animator.SetFloat ("Turning", h);  
	
	// Set the jumping parameter to the j value
	//animator.SetInteger ("Jump", j);
	if (stateInfo.IsName("Base Layer.Idle")) {  
	     // Set the jumping parameter to the j value
	     if (canJump && grounded && j ==1 ) rigidbody.AddForce (Vector3.up * 200 );
	     ProcessJump();	
	}
	
} 

  function ProcessJump () {

   // if the player pressed jump and it can jump
   if (j == 1 && canJump == true &&  grounded) {
   		// trigger the jump
   		animator.SetBool ("Jump", true); 
   		//prevent more jumps
   		grounded = false;// a jump is in progress
   		yield;
   		animator.SetBool ("Jump", false);
   		canJump = false; // a jump is in progress
   }
   else if (j == 0) {
   		yield;
   		canJump = true; // reset the jump flag
   }

} 

function OnCollisionEnter(collision : Collision) { 
      
     grounded = true; 
           
}

function ProcessWinded () {

	if (windedState != 0) return; // already being processed
	
	windedState = 1; 
	// trigger the Catch Breath state on
	animator.SetInteger ("Winded State", 1);
	// switch to the active state so it won't keep looping
	yield;// give it a frame
	animator.SetInteger ("Winded State", 2);
	// let it run a random number of seconds
	yield new WaitForSeconds(Random.Range(3.0,5.5));
	// trigger it back to idle/ ready to catch breath		
	animator.SetInteger ("Winded State", 0);
	windedState = 0; //clear winded flag
} 
 

Avatar里面的Transform Avatar可以做人体以外的部分的动画叠加,如武器,花等

Sub State Machine可以做如一个跑步的准备的动画,或经过不同的地形时人的不同的反应

Mirror可以创建动画的反效果

OnAnimatorMove


Model下Animations属性Curves可以做如动态的改变Collider的效果,须在Animator Controller下同样定义相同的参数

 OnAnimatorIK 须设置一个Animator Layer,勾选IK Pass


Generic用动画重定向功能时,如果一个角色没有Animations,若设置他的Scale属性,他会出现播放动画时Scale会变回来


如何从三维应用程序中导入对象?手册

Unity 支持从最流行的三维应用程序中导入。从下列软件中选出正在使用的一款:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值