电竞比分网-中国电竞赛事及体育赛事平台

分享

unity 對Animator動畫系統(tǒng)的研究

 勤奮不止 2019-07-02

unity的新動畫系統(tǒng)叫Mecanim,使用Animator來取代舊系統(tǒng)Animation,按Unity文檔的慣例:知識點主要分2部分:unity manual和unity script,讀者可以邊看文章邊查閱文檔,最好能動手測試。

文章的開始之前,先講幾個基本的知識的:

1.創(chuàng)建動畫的一個基本步驟是設(shè)置一個unity3d可理解的簡化后的骨骼到骨架中實際骨骼的映射;在Mecanim的術(shù)語中,這個映射稱為Avatar,即avatar是骨骼到骨架的映射。

  技術(shù)分享(圖片來自網(wǎng))

  Avatar主要用于類人骨骼模型,可以實現(xiàn)角色之間的Retargeting。非類人模型可以認(rèn)為骨架就是骨骼。

2.構(gòu)建模型的基本步驟:

  modelling->rigging->skinning(建模->構(gòu)建骨架->蒙皮)

  1.modelling 建模:

    1.Observe a sensible topology(遵循合理的拓撲結(jié)構(gòu)),一個合理的標(biāo)準(zhǔn)是動畫帶動的網(wǎng)格變形是漂亮的;

    2.注意網(wǎng)格的縮放比例。最好做一下各個建模軟件模型的導(dǎo)入測試,來設(shè)置好正確的縮放比例(不同建模軟件導(dǎo)入比例不一樣)

    3.安放角色使得角色的腳站在坐標(biāo)原點或者模型的“錨點”。角色通常是豎直地走在地面上,如果角色的錨點(也就是他的變換中心)在地面上會更容易控制。

    4.如果是類人模型,則盡量使用T字姿態(tài)建模(Unity為類人模型提供了許多功能和優(yōu)化)

    5.整理你的模型,去掉垃圾。只要可能的話,覆蓋孔洞,焊接頂點并且移除隱藏的面,這會對蒙皮有幫助,特別是自動蒙皮過程。

  2.Rigging 搭骨架:創(chuàng)建骨架上的關(guān)節(jié)來控制你的模型進行運動。

    非類人模型的話,可以認(rèn)為沒有骨架,只有骨骼,骨骼直接控制動畫,類人模型是骨架控制動畫。步驟1中的模型已經(jīng)有腳,手,頭,武器等骨骼,還有受擊骨骼等,這些可以用來控制模型或者懸掛額外物件。

  3.Skinning 蒙皮:給骨架附加網(wǎng)格。

    1.把網(wǎng)格中的頂點綁定到骨骼,包括硬綁定(一個頂點指定一個骨骼,不是一一對應(yīng),可能多個頂點指定的是一個骨骼)和軟綁定(一個頂點指定多個骨骼,每個骨骼有一定權(quán)重)
    2.蒙皮的實操步驟:先自動蒙皮,接著用一個測試動畫看看蒙皮效果并根據(jù)此效果慢慢改啊改。
    3.每個頂點最多綁定4個骨骼,這是U3D的上限

3.動畫文件導(dǎo)入unity后,我們對它的處理和設(shè)置,這些在Inspector面板:Animation Importing settings

  技術(shù)分享

  分3個頁簽:

    Model:這里的參數(shù)基本由美術(shù)來定,其他的使用默認(rèn)就好了,這里只提4個參數(shù):

      1.scale factor 模型縮放比例,不同建模軟件導(dǎo)入比例不一樣,unity的物理單位是1m,這個根據(jù)不同建模軟件設(shè)置

      2.readable/writeable和UITexture一樣,如果開了unity就必須拷一份到內(nèi)存,盡量不開。
      3.Generate Colliders一般用于生成場景的mesh collider,其他地方就不要打開了。
      4.Normals&Tangents是導(dǎo)入時對頂點和切線的處理,比如是否導(dǎo)入模型的頂點等,可限制模型精度和影響后續(xù)渲染等,比如vfshader就需要用到模型的 normal。

      技術(shù)分享

    Rig:這里Animation Type包括(Generic/Humanoid/Legacy/None)

      Generic 用于非類人模型;Humanoid用于類人模型

      Avatar Definition:可以使用現(xiàn)有的avatar,也可以create from this model,一般地,模型網(wǎng)格文件選create,這個時候,Avatar子資產(chǎn)被增加到模型資產(chǎn)的下面,即Avatar是unity根據(jù)網(wǎng)格文件生成的,對Humanoid類型,還會自動匹配骨骼到骨架,不符合會報錯;而動畫文件使用copy,使用已有資源。

    技術(shù)分享

    Animations:對一個Animation Clip動畫片段進行設(shè)置

      前面部分的設(shè)置這里就不講了,下面的clip片段我們看到Start和End參數(shù),這表示從一個fbx動畫中截取一段給clip使用,多個clip共用一個動畫資源,所以,可以一個模型的所有動作都搞到一個動畫文件中,各個動作去里面取一段即可;也可以一個模型每個動作都有一個動畫文件,分開管理。

    技術(shù)分享

    中間的參數(shù)比較煩躁,略過,先提一下Animations頁簽最下面的幾個有意思的參數(shù):curves,events,mask,這2個簡單的參數(shù)可以帶來許多有趣的功能,在后面會講到。

    技術(shù)分享

講完上面幾個基本知識點后,下面我們來分點看幾個有趣的應(yīng)用:

1.AnimationEvent

  Unity manual部分:

    這個在animations頁簽的下面,可以給clip加幀事件,即播到某幀時觸發(fā)某個事件:

    1.給clip的某些幀上加event,這個Function就是事件的名字,其他的是這個函數(shù)的參數(shù)

    2.定義一個腳本來接受這個事件,比如這個圖需要定義一個腳本,并且腳本里定義了void ani(xxx){}函數(shù)

    3.參數(shù)的處理:根據(jù)腳本的函數(shù)定義格式傳參數(shù),比如void ani(int a),則傳Int那個參數(shù),ani(Object a)則傳Object那個參數(shù),ani(float a, string b)則傳Float和String這2個參數(shù),而,ani(AnimationnEvent a)則傳整個event進去(包括所有參數(shù)和當(dāng)前event對應(yīng)的clip的信息)

    ps:添加了event的clip的animator物體必須掛上定義了該事件名Function的函數(shù)的腳本,否則會報錯

    技術(shù)分享

  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(采用哪個看函數(shù)定義式)、time(事件的觸發(fā)時間)

  實際應(yīng)用:這個event機制可以在播到某些幀執(zhí)行一些事件。那么我們可以,在某個點播某個特效,在某個點播某個聲音,在某個點進行一些畫面特效,在某個點進行對敵人“擊退”“擊飛”“擊浮空”,非常有利于實現(xiàn)各種節(jié)奏效果!還可以加入技能打斷機制:當(dāng)播到某2個幀之間可以被打斷:比如我遠撲某個玩家,結(jié)果我在空中被打斷,我就被彈回來。這種效果一定很爽吧。讀者可以在一個專門的腳本中定義各種接受事件的函數(shù),并進行相應(yīng)處理來進行使用此event機制。

2.AnimationCurve:

  Unity manual部分:

  添加curve,這個curve和event有點像但又不同,event是幾幀,curves 則是每幀,curves可以配合OnAnimatorMove使用,比如每幀不同速度前進:

      void OnAnimatorMove()
         {
             Animator animator = GetComponent<Animator>();          
             Vector3 newPosition = transform.position;
            newPosition.z += animator.GetFloat("Runspeed") * Time.deltaTime; //RunSpeed是Curves的曲線變量,控制移動,     transform.position = newPosition;    //由此類似方法可以讓角色一個動畫各種移動。 }

  官方文檔給出一個例子是:

  比如人在冰冷環(huán)境呼吸時,呼氣的水霧由粒子系統(tǒng)控制,那么就可以在播呼吸動畫或者站立動畫時,通過Animator.Get參數(shù)(一個Curve的name)獲得當(dāng)前數(shù)值,控制水霧大小。

  技術(shù)分享

  Unity Script部分:

    屬性:keys(關(guān)鍵幀key集合),length(the num of keys),postWrapMode(最后一幀循環(huán)類型),preWrapMode(第一幀循環(huán)類型),this[int]獲取關(guān)鍵幀

    接口:Evaluate(time):計算某個time時曲線的value

  總結(jié):curves感覺就是:邊播動畫邊干點其他事情,event則像播到一些幀就干點事情。2者配合使用能讓你的動畫系統(tǒng)變得豐富起來,好好使用這兩個小小的利器吧。

3.Animation Layers和遮罩 實現(xiàn):邊走邊吃蘋果

  1.給吃蘋果動畫加遮罩:在animation tab中的Mask中加遮罩,只勾選吃蘋果的那部分骨骼,3種情況添加:     

      A.加現(xiàn)有的遮罩文件,可以通過Assets->Create->Avatar Mast創(chuàng)建一個遮罩
      B.如果是給類人模型的動畫,使用點擊部位加遮罩
      C.如果是通用模型的動畫,勾選關(guān)節(jié)加遮罩

  技術(shù)分享

  2.創(chuàng)建新Layer:EatApple Layer, 把第1步的遮罩拖到這里的Mask參數(shù)中,設(shè)置該layer設(shè)置比走路動畫Layer高,并設(shè)置該Layer的Blending為override,這樣,播走路動畫和播吃蘋果動畫就可以同時進行并且播蘋果動畫override了走路動畫的上半身動畫。

  技術(shù)分享

4.Animator Override Controller:

  顧名思義,它就是Override “Animator Controller”的,先簡單說一下Animations Controller:

    Animation Controller可以認(rèn)為它就是動畫狀態(tài)機, Animator動畫系統(tǒng)是通過Animator Controller來控制動畫播放的,里面存著指向各個動畫片段Animation Clip的引用,和播放動畫的邏輯,比如狀態(tài)轉(zhuǎn)移等.

  而Animator Override Controller則用于拓展一個已存在的Animtor Controller,它只是在后者基礎(chǔ)上在某些狀態(tài)播新的動畫Clip而已,保持后者的狀態(tài)機邏輯,結(jié)構(gòu)等等:retaining the original’s structure, parameters and logic.

  所以在應(yīng)用方面,Animator Override Controller能做到一個狀態(tài)機(Animator Controller)實現(xiàn)多套動作,非常利于維護。按官方說法就是:

    如果一類模型可以共用動畫狀態(tài)機,則可以弄一個基礎(chǔ)Animtor Controller,里面是基本的動畫狀態(tài)邏輯,然后給某個模型使用就弄一個Animtor Override Controller,然后把其中不同的動畫Clip換成自己的,這樣就只需維護一份動畫狀態(tài)機了,省心省力。比如NPC系統(tǒng)的各個NPC。許多怪物也可以共用,主角更不用說。

5.1種換裝系統(tǒng)

   ?。◤?fù)習(xí)一個知識點:Skinning 蒙皮:給骨架附加網(wǎng)格,把網(wǎng)格中的頂點綁定到骨骼)

    先加載2個模型出來,第1個模型是基礎(chǔ)模型,skinmesh/動畫/Animator等都有,第2個模型則是一個帶skinmesh的幾乎空的模型,第一個是源模型,第二個是目標(biāo)模型,我們現(xiàn)在要做的就是用第2個模型的skinmesh替換掉第1個模型的skinmesh,做法如下:

    a.獲得第一個模型的skinmesh old_meshrender,獲得第2個模型的skinmesh dst_meshrender,獲得第一個模型的所有骨骼 Transform[] bones.

    b.目的是獲得dst_meshrender中各個頂點映射到bones的各個骨骼列表,即為dst_meshrender網(wǎng)格中各個頂點找到第1個模型中對應(yīng)的骨骼,即為“新皮”重新指定骨骼,然后把old_meshrender的網(wǎng)格sharemesh換成dst_meshrender的sharemesh,把old_meshrender的骨骼bones換成新的骨骼列表(當(dāng)然還是第1個模型的),簡而言之,就是:為第1個模型重新指定網(wǎng)格(第二個模型的),因為網(wǎng)格是新的,所以需要重新映射網(wǎng)格頂點到骨骼,看代碼可能更容易理解:

    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ù)原理清晰、簡單,也方便使用,并且只換皮(網(wǎng)格)不換模型骨架,所以對動畫系統(tǒng)等非常方便,只需把那些東西綁定到原始模型即可。

    但需要注意的是,各個換裝模型的骨骼要規(guī)范,盡量骨架同原始模型一致,至少需要做到骨骼“可以多不可以少”。

6.混合樹

  狀態(tài)轉(zhuǎn)移和混合樹,雖然兩者都是用來制作平滑動畫,但區(qū)別是大大的(讀者可只看前3點即可):
    1.狀態(tài)轉(zhuǎn)移是從一個動畫狀態(tài)平滑轉(zhuǎn)移到另外一個動畫狀態(tài),2個狀態(tài)的動畫可以區(qū)別很大也表現(xiàn)得漂亮,不能維持中間狀態(tài),即不能產(chǎn)生新的動畫讓你播;是動畫狀態(tài)機的一部分,是一個過程。
    2.動畫混合樹是把多個動畫混合起來:
      blend multiple animations smoothly by incorporating parts of them all to varying degrees
      將角色不同的部分混合,對一個部分而言,是混合所有動畫中該部分的角度,形成該部分的新角度,是混合動畫。
      有參數(shù)控制各個動畫的混合權(quán)重,以達到目的(比如左轉(zhuǎn):一開始是向前的權(quán)重大,向左的權(quán)重小,然后。。。)
      要使混合效果好,各個動畫需要造型類似,這個和轉(zhuǎn)移不同;動畫混合樹作為一種特殊的狀態(tài)存在在動畫狀態(tài)機中,是一個狀態(tài),新的狀態(tài)。
    3.鑒于上述描寫,制作混合樹的子動畫需要注意:
      Examples of similar motions could be various walk and run animations. In order for the blend to work well, the movements in the clips must take place at the same points in normalized time. For example, walking and running animations can be aligned so that the moments of contact of foot to the floor take place at the same points in normalized time (e.g. the left foot hits at 0.0 and the right foot at 0.5). Since normalized time is used, it doesn’t matter if the clips are of different length.
      我的理解是,走路動畫和奔跑動畫都在0.7的時候右腳觸地,不然0.7的時刻融合后,右腳在半空,也就是說動作在一些關(guān)鍵點比如離地和觸地。在時間線上的百分比應(yīng)該相近的,在此基礎(chǔ)上,各個動作的Length不用考慮,比如run就比walk短,這無所謂的。
    4.混合樹的創(chuàng)建,選一個State->create blend tree,雙擊blend tree進入混合樹編輯頁面,右邊Inspector中就是控制這個混合樹混合的anim clips和參數(shù)。
    5.一些參數(shù):有一個Compute Thresholds的參數(shù),可以幫忙指定各種閾值控制混合。比如X方向的速度等。
    6.給混合樹添加已創(chuàng)建的參數(shù):在Parameter選擇欄里手動鍵入,回車!這個同給動畫狀態(tài)機加參數(shù)是一樣的
    7.上面的4是針對一維混合,二維混合一般用不到,不討論,多維混合蠻有趣的,可以用于控制臉部表情,多維混合的做法(那控制臉部表情做例子):給出多個表情動畫,每個動畫對應(yīng)一個參數(shù)控制混合的權(quán)重,這樣通過控制各個參數(shù)可以“生產(chǎn)”出很多有意思的表情動畫了。

8.之前一直不知道怎么移動瀏覽Animator 窗口的各自狀態(tài):Alt+鼠標(biāo)左鍵!

9.animator的TargetMatching技術(shù)

  假如你有一個跳躍的動畫,要實現(xiàn)跳躍到某個物體上的效果,可以考慮用animator的TargetMatching技術(shù):

  get到模型的Animator ani,然后

  animator.MatchTarget(jumpTarget.position, jumpTarget.rotation, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 1f), 0.141f, 0.78f);
  0.14,和0.78是起跳和跳完所在時間百分比
  注:我測試沒成功,沒看到跳到某個物體的效果,=。=,或許哪步出錯了。

10.IK控制骨骼

  步驟:
    1.模型的Rig的Animation Type選Humanoid,動畫狀態(tài)機controller的Layer勾上IK Pass;
    2.寫個腳本掛到模型預(yù)制上,打開void OnAnimatorIK()函數(shù),在這個函數(shù)里控制IK:
  具體看Manual的InverseKinematics.html:控制模型轉(zhuǎn)向和各個部位的Rotation和Position
  注:已測試,效果還有趣,可能在一些有意思的地方用到,或許項目想做一系列可控的動畫會用到吧,否則,直接制作動畫就解決了。

11.根運動

  根運動是動畫本身自帶的,比如行走動畫,如果不apply root motion則“原地踏步”(in-place),如果應(yīng)用則向前行走。

  實際項目中一般,不apply root motion,而通過代碼來設(shè)置transform postion,總結(jié)而言:

    1.不apply root motion并且該animator組件所在obj上的控制腳本不實現(xiàn)OnAnimatorMove,且所有腳本也不控制該模型position,=>模型原地踏步;
    2.不apply root motion并且該animator組件所在obj上的控制腳本不實現(xiàn)OnAnimatorMove,但其他腳本控制該模型position,=>模型不原地踏步;
    3.animator組件所在obj上的控制腳本實現(xiàn)OnAnimatorMove(這個時候apply root motion變不可選了),且所有腳本也不控制該模型position,=>模型不原地踏步,又OnAnimatorMove控制;
    4.animator組件所在obj上的控制腳本實現(xiàn)OnAnimatorMove(這個時候apply root motion變不可選了),且其他腳本控制該模型position,=>模型不原地踏步,即受其他腳本控制又受OnAnimatorMove控制;
    5.apply root motion(由4可知不能掛帶OnAnimatorMove的腳本了),且所有腳本也不控制該模型position,=>模型不原地踏步,按動畫里根動作移動;
    6.apply root motion(由4可知不能掛帶OnAnimatorMove的腳本了),且其他腳本控制該模型position,=>模型不原地踏步,按動畫里根動作移動的同時也受其他腳本控制;

  PS1:上述只提了位置,根運動也包括rotation,且控制邏輯也是同樣的。

    官方說明: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
  2.少用縮放動畫曲線
  3.When importing Humanoid animation use a BodyMask to remove IK Goals or fingers animation if they are not needed.
   如果是類人動畫,用身體遮罩剔除IK Goals和不需要的細節(jié)動畫(如手指動畫)
  4.When you use Generic, using root motion is more expensive than not using it. If your animations don’t use root motion, make sure that you have no root bone selected.
  如果選通用模式,不要使用root motion,不要選擇root bone
  5.Use hashes instead of strings to query the Animator.用Hashid而不用string來獲取動畫狀態(tài)或參數(shù),動畫的Play函數(shù)重載了hash和string,可以考慮做一個映射,string->hash,使用hash獲取參數(shù)(播動畫),來代替string.
  6.使用curves來實現(xiàn)一些額外表現(xiàn):在播動畫的時候同時搞事情。
  7.Rig頁簽的optimize gameobjects(選create from this model才可用)

12.Animator Component

  Unity Manual:參考這篇:http://www.cnblogs.com/Tearix/p/6941156.html

  Unity Script:屬性和接口太多了,看官方文檔吧,有個翻譯可以參考一下,但那個只是作者自己的理解,不保證準(zhǔn)確:

    http://www.cnblogs.com/hont/p/5100472.html?utm_source=tuicool&utm_medium=referral

13.一個坑

  Play(A);Play(B);則最終Play了A;以前好像遇到過有概率不播某個動畫的情況,沒查明是否是因此造成的。解決方法是:

  Play(A);Update(x);Play(B);則最終Play了B,用Update更新一下就可以覆蓋了。如果是CrossFade,情況又復(fù)雜一些了,這個問題我專門和一位網(wǎng)友討論過,這里不提。

unity 對Animator動畫系統(tǒng)的研究

標(biāo)簽:amp   錨點   end   skin   ble   動作   actor   bre   函數(shù)定義   

原文地址:http://www.cnblogs.com/Tearix/p/6939948.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多