unity的新動(dòng)畫系統(tǒng)叫Mecanim,使用Animator來(lái)取代舊系統(tǒng)Animation,按Unity文檔的慣例:知識(shí)點(diǎn)主要分2部分:unity manual和unity script,讀者可以邊看文章邊查閱文檔,最好能動(dòng)手測(cè)試。 文章的開(kāi)始之前,先講幾個(gè)基本的知識(shí)的: 1.創(chuàng)建動(dòng)畫的一個(gè)基本步驟是設(shè)置一個(gè)unity3d可理解的簡(jiǎn)化后的骨骼到骨架中實(shí)際骨骼的映射;在Mecanim的術(shù)語(yǔ)中,這個(gè)映射稱為Avatar,即avatar是骨骼到骨架的映射。 Avatar主要用于類人骨骼模型,可以實(shí)現(xiàn)角色之間的Retargeting。非類人模型可以認(rèn)為骨架就是骨骼。 2.構(gòu)建模型的基本步驟: modelling->rigging->skinning(建模->構(gòu)建骨架->蒙皮) 1.modelling 建模: 1.Observe a sensible topology(遵循合理的拓?fù)浣Y(jié)構(gòu)),一個(gè)合理的標(biāo)準(zhǔn)是動(dòng)畫帶動(dòng)的網(wǎng)格變形是漂亮的; 2.注意網(wǎng)格的縮放比例。最好做一下各個(gè)建模軟件模型的導(dǎo)入測(cè)試,來(lái)設(shè)置好正確的縮放比例(不同建模軟件導(dǎo)入比例不一樣) 3.安放角色使得角色的腳站在坐標(biāo)原點(diǎn)或者模型的“錨點(diǎn)”。角色通常是豎直地走在地面上,如果角色的錨點(diǎn)(也就是他的變換中心)在地面上會(huì)更容易控制。 4.如果是類人模型,則盡量使用T字姿態(tài)建模(Unity為類人模型提供了許多功能和優(yōu)化) 5.整理你的模型,去掉垃圾。只要可能的話,覆蓋孔洞,焊接頂點(diǎn)并且移除隱藏的面,這會(huì)對(duì)蒙皮有幫助,特別是自動(dòng)蒙皮過(guò)程。 2.Rigging 搭骨架:創(chuàng)建骨架上的關(guān)節(jié)來(lái)控制你的模型進(jìn)行運(yùn)動(dòng)。 非類人模型的話,可以認(rèn)為沒(méi)有骨架,只有骨骼,骨骼直接控制動(dòng)畫,類人模型是骨架控制動(dòng)畫。步驟1中的模型已經(jīng)有腳,手,頭,武器等骨骼,還有受擊骨骼等,這些可以用來(lái)控制模型或者懸掛額外物件。 3.Skinning 蒙皮:給骨架附加網(wǎng)格。 1.把網(wǎng)格中的頂點(diǎn)綁定到骨骼,包括硬綁定(一個(gè)頂點(diǎn)指定一個(gè)骨骼,不是一一對(duì)應(yīng),可能多個(gè)頂點(diǎn)指定的是一個(gè)骨骼)和軟綁定(一個(gè)頂點(diǎn)指定多個(gè)骨骼,每個(gè)骨骼有一定權(quán)重) 3.動(dòng)畫文件導(dǎo)入unity后,我們對(duì)它的處理和設(shè)置,這些在Inspector面板:Animation Importing settings 分3個(gè)頁(yè)簽: Model:這里的參數(shù)基本由美術(shù)來(lái)定,其他的使用默認(rèn)就好了,這里只提4個(gè)參數(shù): 1.scale factor 模型縮放比例,不同建模軟件導(dǎo)入比例不一樣,unity的物理單位是1m,這個(gè)根據(jù)不同建模軟件設(shè)置 2.readable/writeable和UITexture一樣,如果開(kāi)了unity就必須拷一份到內(nèi)存,盡量不開(kāi)。 Rig:這里Animation Type包括(Generic/Humanoid/Legacy/None) Generic 用于非類人模型;Humanoid用于類人模型 Avatar Definition:可以使用現(xiàn)有的avatar,也可以create from this model,一般地,模型網(wǎng)格文件選create,這個(gè)時(shí)候,Avatar子資產(chǎn)被增加到模型資產(chǎn)的下面,即Avatar是unity根據(jù)網(wǎng)格文件生成的,對(duì)Humanoid類型,還會(huì)自動(dòng)匹配骨骼到骨架,不符合會(huì)報(bào)錯(cuò);而動(dòng)畫文件使用copy,使用已有資源。 Animations:對(duì)一個(gè)Animation Clip動(dòng)畫片段進(jìn)行設(shè)置 前面部分的設(shè)置這里就不講了,下面的clip片段我們看到Start和End參數(shù),這表示從一個(gè)fbx動(dòng)畫中截取一段給clip使用,多個(gè)clip共用一個(gè)動(dòng)畫資源,所以,可以一個(gè)模型的所有動(dòng)作都搞到一個(gè)動(dòng)畫文件中,各個(gè)動(dòng)作去里面取一段即可;也可以一個(gè)模型每個(gè)動(dòng)作都有一個(gè)動(dòng)畫文件,分開(kāi)管理。 中間的參數(shù)比較煩躁,略過(guò),先提一下Animations頁(yè)簽最下面的幾個(gè)有意思的參數(shù):curves,events,mask,這2個(gè)簡(jiǎn)單的參數(shù)可以帶來(lái)許多有趣的功能,在后面會(huì)講到。 講完上面幾個(gè)基本知識(shí)點(diǎn)后,下面我們來(lái)分點(diǎn)看幾個(gè)有趣的應(yīng)用: 1.AnimationEvent Unity manual部分: 這個(gè)在animations頁(yè)簽的下面,可以給clip加幀事件,即播到某幀時(shí)觸發(fā)某個(gè)事件: 1.給clip的某些幀上加event,這個(gè)Function就是事件的名字,其他的是這個(gè)函數(shù)的參數(shù) 2.定義一個(gè)腳本來(lái)接受這個(gè)事件,比如這個(gè)圖需要定義一個(gè)腳本,并且腳本里定義了void ani(xxx){}函數(shù) 3.參數(shù)的處理:根據(jù)腳本的函數(shù)定義格式傳參數(shù),比如void ani(int a),則傳Int那個(gè)參數(shù),ani(Object a)則傳Object那個(gè)參數(shù),ani(float a, string b)則傳Float和String這2個(gè)參數(shù),而,ani(AnimationnEvent a)則傳整個(gè)event進(jìn)去(包括所有參數(shù)和當(dāng)前event對(duì)應(yīng)的clip的信息) ps:添加了event的clip的animator物體必須掛上定義了該事件名Function的函數(shù)的腳本,否則會(huì)報(bào)錯(cuò) Unity Script部分:可查看class AnimationEvent,主要是獲得該event所在clip的一些信息:與此event相關(guān)的stateinfo,clipinfo,和該event本身的信息:event調(diào)用的函數(shù)名functionName、函數(shù)調(diào)用的參數(shù):float/int/string/Object(采用哪個(gè)看函數(shù)定義式)、time(事件的觸發(fā)時(shí)間) 實(shí)際應(yīng)用:這個(gè)event機(jī)制可以在播到某些幀執(zhí)行一些事件。那么我們可以,在某個(gè)點(diǎn)播某個(gè)特效,在某個(gè)點(diǎn)播某個(gè)聲音,在某個(gè)點(diǎn)進(jìn)行一些畫面特效,在某個(gè)點(diǎn)進(jìn)行對(duì)敵人“擊退”“擊飛”“擊浮空”,非常有利于實(shí)現(xiàn)各種節(jié)奏效果!還可以加入技能打斷機(jī)制:當(dāng)播到某2個(gè)幀之間可以被打斷:比如我遠(yuǎn)撲某個(gè)玩家,結(jié)果我在空中被打斷,我就被彈回來(lái)。這種效果一定很爽吧。讀者可以在一個(gè)專門的腳本中定義各種接受事件的函數(shù),并進(jìn)行相應(yīng)處理來(lái)進(jìn)行使用此event機(jī)制。 2.AnimationCurve: Unity manual部分: 添加curve,這個(gè)curve和event有點(diǎn)像但又不同,event是幾幀,curves 則是每幀,curves可以配合OnAnimatorMove使用,比如每幀不同速度前進(jìn): void OnAnimatorMove() { Animator animator = GetComponent<Animator>(); Vector3 newPosition = transform.position; newPosition.z += animator.GetFloat("Runspeed") * Time.deltaTime; //RunSpeed是Curves的曲線變量,控制移動(dòng), transform.position = newPosition; //由此類似方法可以讓角色一個(gè)動(dòng)畫各種移動(dòng)。 } 官方文檔給出一個(gè)例子是: 比如人在冰冷環(huán)境呼吸時(shí),呼氣的水霧由粒子系統(tǒng)控制,那么就可以在播呼吸動(dòng)畫或者站立動(dòng)畫時(shí),通過(guò)Animator.Get參數(shù)(一個(gè)Curve的name)獲得當(dāng)前數(shù)值,控制水霧大小。 Unity Script部分: 屬性:keys(關(guān)鍵幀key集合),length(the num of keys),postWrapMode(最后一幀循環(huán)類型),preWrapMode(第一幀循環(huán)類型),this[int]獲取關(guān)鍵幀 接口:Evaluate(time):計(jì)算某個(gè)time時(shí)曲線的value 總結(jié):curves感覺(jué)就是:邊播動(dòng)畫邊干點(diǎn)其他事情,event則像播到一些幀就干點(diǎn)事情。2者配合使用能讓你的動(dòng)畫系統(tǒng)變得豐富起來(lái),好好使用這兩個(gè)小小的利器吧。 3.Animation Layers和遮罩 實(shí)現(xiàn):邊走邊吃蘋果 1.給吃蘋果動(dòng)畫加遮罩:在animation tab中的Mask中加遮罩,只勾選吃蘋果的那部分骨骼,3種情況添加: A.加現(xiàn)有的遮罩文件,可以通過(guò)Assets->Create->Avatar Mast創(chuàng)建一個(gè)遮罩 2.創(chuàng)建新Layer:EatApple Layer, 把第1步的遮罩拖到這里的Mask參數(shù)中,設(shè)置該layer設(shè)置比走路動(dòng)畫Layer高,并設(shè)置該Layer的Blending為override,這樣,播走路動(dòng)畫和播吃蘋果動(dòng)畫就可以同時(shí)進(jìn)行并且播蘋果動(dòng)畫override了走路動(dòng)畫的上半身動(dòng)畫。 4.Animator Override Controller: 顧名思義,它就是Override “Animator Controller”的,先簡(jiǎn)單說(shuō)一下Animations Controller: Animation Controller可以認(rèn)為它就是動(dòng)畫狀態(tài)機(jī), Animator動(dòng)畫系統(tǒng)是通過(guò)Animator Controller來(lái)控制動(dòng)畫播放的,里面存著指向各個(gè)動(dòng)畫片段Animation Clip的引用,和播放動(dòng)畫的邏輯,比如狀態(tài)轉(zhuǎn)移等. 而Animator Override Controller則用于拓展一個(gè)已存在的Animtor Controller,它只是在后者基礎(chǔ)上在某些狀態(tài)播新的動(dòng)畫Clip而已,保持后者的狀態(tài)機(jī)邏輯,結(jié)構(gòu)等等:retaining the original’s structure, parameters and logic. 所以在應(yīng)用方面,Animator Override Controller能做到一個(gè)狀態(tài)機(jī)(Animator Controller)實(shí)現(xiàn)多套動(dòng)作,非常利于維護(hù)。按官方說(shuō)法就是: 如果一類模型可以共用動(dòng)畫狀態(tài)機(jī),則可以弄一個(gè)基礎(chǔ)Animtor Controller,里面是基本的動(dòng)畫狀態(tài)邏輯,然后給某個(gè)模型使用就弄一個(gè)Animtor Override Controller,然后把其中不同的動(dòng)畫Clip換成自己的,這樣就只需維護(hù)一份動(dòng)畫狀態(tài)機(jī)了,省心省力。比如NPC系統(tǒng)的各個(gè)NPC。許多怪物也可以共用,主角更不用說(shuō)。 5.1種換裝系統(tǒng) (復(fù)習(xí)一個(gè)知識(shí)點(diǎn):Skinning 蒙皮:給骨架附加網(wǎng)格,把網(wǎng)格中的頂點(diǎn)綁定到骨骼) 先加載2個(gè)模型出來(lái),第1個(gè)模型是基礎(chǔ)模型,skinmesh/動(dòng)畫/Animator等都有,第2個(gè)模型則是一個(gè)帶skinmesh的幾乎空的模型,第一個(gè)是源模型,第二個(gè)是目標(biāo)模型,我們現(xiàn)在要做的就是用第2個(gè)模型的skinmesh替換掉第1個(gè)模型的skinmesh,做法如下: a.獲得第一個(gè)模型的skinmesh old_meshrender,獲得第2個(gè)模型的skinmesh dst_meshrender,獲得第一個(gè)模型的所有骨骼 Transform[] bones. b.目的是獲得dst_meshrender中各個(gè)頂點(diǎn)映射到bones的各個(gè)骨骼列表,即為dst_meshrender網(wǎng)格中各個(gè)頂點(diǎn)找到第1個(gè)模型中對(duì)應(yīng)的骨骼,即為“新皮”重新指定骨骼,然后把old_meshrender的網(wǎng)格sharemesh換成dst_meshrender的sharemesh,把old_meshrender的骨骼bones換成新的骨骼列表(當(dāng)然還是第1個(gè)模型的),簡(jiǎn)而言之,就是:為第1個(gè)模型重新指定網(wǎng)格(第二個(gè)模型的),因?yàn)榫W(wǎng)格是新的,所以需要重新映射網(wǎng)格頂點(diǎn)到骨骼,看代碼可能更容易理解: SkinnedMeshRender dst_meshR = newModel.GetComponent<SkinnedMeshRender>(); SkinnedMeshRender old_meshR = oldModel.GetComponent<SkinnedMeshRender>(); Transform[] bones = old_meshR.bones; Transform[] newBones = new Transform[dst_meshR.bones.Length]; for (int i = 0; i < dst_meshR.bones.Length;++i) { for (int j = 0; j < old_meshR.bones.Length; ++j) { if (old_meshR.bones[j].name == dst_meshR.bones[i].name) { newBones[i] = old_meshR.bones[j]; break; } } } old_meshR.sharedMesh = dst_meshR.sharedMesh; old_meshR.bones = newBones; old_meshR.sharedMaterials = dst_meshR.sharedMaterials; 這種換皮技術(shù)原理清晰、簡(jiǎn)單,也方便使用,并且只換皮(網(wǎng)格)不換模型骨架,所以對(duì)動(dòng)畫系統(tǒng)等非常方便,只需把那些東西綁定到原始模型即可。 但需要注意的是,各個(gè)換裝模型的骨骼要規(guī)范,盡量骨架同原始模型一致,至少需要做到骨骼“可以多不可以少”。 6.混合樹(shù) 狀態(tài)轉(zhuǎn)移和混合樹(shù),雖然兩者都是用來(lái)制作平滑動(dòng)畫,但區(qū)別是大大的(讀者可只看前3點(diǎn)即可): 8.之前一直不知道怎么移動(dòng)瀏覽Animator 窗口的各自狀態(tài):Alt+鼠標(biāo)左鍵! 9.animator的TargetMatching技術(shù) 假如你有一個(gè)跳躍的動(dòng)畫,要實(shí)現(xiàn)跳躍到某個(gè)物體上的效果,可以考慮用animator的TargetMatching技術(shù): get到模型的Animator ani,然后 animator.MatchTarget(jumpTarget.position, jumpTarget.rotation, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 1f), 0.141f, 0.78f); 10.IK控制骨骼 步驟: 11.根運(yùn)動(dòng) 根運(yùn)動(dòng)是動(dòng)畫本身自帶的,比如行走動(dòng)畫,如果不apply root motion則“原地踏步”(in-place),如果應(yīng)用則向前行走。 實(shí)際項(xiàng)目中一般,不apply root motion,而通過(guò)代碼來(lái)設(shè)置transform postion,總結(jié)而言: 1.不apply root motion并且該animator組件所在obj上的控制腳本不實(shí)現(xiàn)OnAnimatorMove,且所有腳本也不控制該模型position,=>模型原地踏步; PS1:上述只提了位置,根運(yùn)動(dòng)也包括rotation,且控制邏輯也是同樣的。 官方說(shuō)明:Root motion is the effect where an object‘s entire mesh moves away from its starting point but that motion is created by the animation itself rather than by changing the Transform position. Note that applyRootMotion has no effect when the script implements a MonoBehaviour.OnAnimatorMove function.Changing the value of applyRootMotion at runtime will re-initialize the animator. 11.一些優(yōu)化建議 1.The Animator doesn’t spend time processing when a Controller is not set to it 12.Animator Component Unity Manual:參考這篇:http://www.cnblogs.com/Tearix/p/6941156.html Unity Script:屬性和接口太多了,看官方文檔吧,有個(gè)翻譯可以參考一下,但那個(gè)只是作者自己的理解,不保證準(zhǔn)確: http://www.cnblogs.com/hont/p/5100472.html?utm_source=tuicool&utm_medium=referral 13.一個(gè)坑 Play(A);Play(B);則最終Play了A;以前好像遇到過(guò)有概率不播某個(gè)動(dòng)畫的情況,沒(méi)查明是否是因此造成的。解決方法是: Play(A);Update(x);Play(B);則最終Play了B,用Update更新一下就可以覆蓋了。如果是CrossFade,情況又復(fù)雜一些了,這個(gè)問(wèn)題我專門和一位網(wǎng)友討論過(guò),這里不提。 unity 對(duì)Animator動(dòng)畫系統(tǒng)的研究 標(biāo)簽:amp 錨點(diǎn) end skin ble 動(dòng)作 actor bre 函數(shù)定義 原文地址:http://www.cnblogs.com/Tearix/p/6939948.html |
|
來(lái)自: 勤奮不止 > 《游戲引擎unity》