Unity插件FinalIK部分说明书翻译

来源:互联网 发布:网络电视盒子刷机软件 编辑:程序博客网 时间:2024/04/30 00:18
/*全身BipedIK    Final IK 為採用biped骨骼的角色提供了一個極端靈活、強大且高效的全身IK解算器。FBBIK先把Biped角色映射到一個低解析度的多反應器角色IK綁定,解算它,然後重新把結果映射角色。這個過程在LateUpdate進行,在Mecanim/Legacy動畫完成之後,所以它跟animator系統完全分離。鏈:    內部,每個肢體和軀幹都是FBIKChain類的實例。軀幹是根鏈,只包含一個node,軀幹是它的子鏈。這種設置形成一個圍繞根鏈的多反應器IK樹。節點:    node是鏈的組成部分。比如,手臂鏈包括3個節點-上臂、前臂、手。每個節點維護一個到骨骼的引用(node.transform)。當解算器運行或者結束后,解算出的骨骼位置會保存在node.solverPosition。反應器:    FBBIK有3種反應器-【末端反應器】(手、腳),【中間反應器】(肩膀、大腿)和【多反應器】(軀幹)。當旋轉【中間反應器】和【多反應器】無效的時候可以轉動【末端反應器】。旋轉【末端反應器】同樣會改變軀幹的彎曲方向(除非你用彎曲目標覆蓋它)。軀幹反應器是一個【多反應器】,意味著它拖動2個大腿反應器(簡化軀幹定位)。反應器有positionOffset屬性可以非常簡單的操控下層動畫。反應器會在每次解算結束之後將postionOffset重置為Vector3.zero。 拉和伸:    每個鏈都有pull屬性。當pull=1,pull權重跟肢體一樣。這意味著你觸到所有反應器是沒有保障的,太遠的會接觸不到。可以通過修改reach參數,或增加解算迭代次數,或這每幀多次解算,來調整或者改進這個結果。但是,如果你把左臂鏈的pull權重設置到1然後其他都為0,那麼你可以拉角色的左手到無限遠而不丟失聯繫。映射:    IKSolverFullBodyBiped解算一個非常低分辨率的快速軀殼。雖然你的角色有多得多的脊椎骨,他可能有兩倍的骨骼在手臂和肩膀或者臀部骨骼等等。因此,在解算之前,解算器需要映射高分辨率的骨架到低分辨率的解算骨架,在解算完成之後再逆向操作。有3種映射器,1.IKMappingSpine用來映射盆骨和脊柱;2.IKMappingLimb映射軀幹;3.IKMappingBone映射頭部;你可以通過IKSolverFullBody.spineMappingIKSolverFullBody.limbMappings和IKSolverFullBody.boneMappings訪問他們。    限制:    1.FullBodyBipedIK沒有頭部反應器。因為頭部只有一個骨頭,你可以再FullBodyIK結束之後隨意轉動,而且,只有極少的情況你需要抓住頭部拉動角色。即使如此,它可以通過拉動肩膀來很好的模擬。這是一個讓程序更快、更穩定的優化措施。    2.FullBodyBipedIK沒有手指和腳趾反應器。解算手指IK似乎有點過分使用IK了,因為極少有遊戲對手指做綁定。使用104段CCD或者FABRIK鏈控制手指,可能這樣浪費寶貴的毫秒數並不是你想要的。你可以參考DrivingRigdemo了解如何快速擺手指到物體上。    3.FullBodyBipedIK採樣角色的初始pose(在Start()函數,當每次你重新初始化解算器的時候)找到以什麼方式彎曲肢體。從此,限制-角色的肢體需要被彎曲到自然的方向。有些角色可能是處於T-Pose,他們的肢體是伸直的。有些角色的肢體可能還輕微的往反向彎曲(有些Mixamo綁定的角色)。FullBodyBipedIK會警告你這些問題可能發生。你需要手動在SceneView稍微旋轉骨骼到正確的彎曲方向。因為,這些旋轉會在播放的時候被動畫覆蓋,所以你不用擔心搞壞你的角色。    4.FullBodyBipedIK 沒有肘部、膝部反應器。這功能在將來如果確實需要的話可能增加。仍然支持通過彎曲目標改變肘部、膝蓋的位置。    5.Optimize Game Objects 需要關閉,或者至少所有解算器需要的骨骼要引入(FullBodyBipedIK.references)。    6.支持只有扭曲動畫的額外骨骼。如果額外骨骼有擺動動畫,比如翅膀擺動。那麼FBBIK將不能正確解算。    7.FullBodyBipedIK 需要角色開啟animatePhysics。這是Mecanim系統的一個bug,它不允許運行時改變animatePhysics,那麼FullBodyBipedIK需要根據初始animatePhysics進行刷新。    8.FullBodyBipedIK不會在拉動手的時候旋轉肩膀。這樣可以維護胸部動畫的。大多數情況,這沒有問題,但有時候,特別是抓取或者有東西高於頭部的時候,讓肩膀跟著旋轉會更真實。這種情況,你不僅需要一個底層的抬起動畫,還需要肩膀骨骼在IK解算器讀取pose之前,能用腳本旋轉它。這裡同樣有一個腳本包括這個demo,它叫ShoulderRotator。    9.當你移動【末端反應器】並且反應器權重=0,FBBIK將在動畫的時候嘗試修復肢體的彎曲方向,當肢體旋轉接近180度的時候你將體驗到肢體的轟響,就是說,解算器無法知道在這個奇點上如何旋轉。比如,你有一個行走動畫,手下垂,而你想要夠到頭頂正上方的某個物體,這時候無論你做反應器旋轉動畫或者使用彎曲目標,要在接近180度生硬旋轉中確保手臂不翻轉都會很麻煩。這並不是一個bug,如果我們想要保持默認動畫彎曲方向,這在邏輯上是必然會發生的。    10.FullBodyBipedIK認定手肘和膝蓋關節是鉸鏈關節,就是說前臂不能相對上臂扭動。在最常見的綁定,像3dsMaxbiped上這沒問題,因為這些綁定阻止這類動畫出現。然而如果綁定允許這種扭曲。這不會導致FBBIK解算器失效,相反,FBBIK解算器會強制手肘和膝蓋約束到鉸鏈關節,即使它沒有反應器。這不會改變肢體末端,它會輕微的改變肢體彎曲方向,和骨骼的扭曲。開始教程:    1.添加FullBodyBipedIK組件到角色根節點(與Animator/Animation組件相同)    2.確認自動檢測到的biped references正確。    3.確認跟節點正確檢測到。它應該是脊柱下端的骨骼。    4.看下SceneView,確認FBBIK骨架在角色上顯示。    5.按Play,操控解算器。*///訪問反應器:    public FullBodyBipedIK ik;    void LateUpdate () {        ik.solver.leftHandEffector.position = something; // 設置左手反應器位置(世界坐標)。如果把權重設置到0,反應器會沒有效果。        ik.solver.leftHandEffector.rotation = something; // 設置左手反應器旋轉(世界坐標)。如果把權重設置到0,反應器會沒有效果。        ik.solver.leftHandEffector.positionWeight = 1f;  // 反應器位置權重,這裡設為1,左手位置會被固定到ik.solver.leftHandEffector.position.        // 反應器旋轉權重,這裡設為1,左手和手臂旋轉會被固定到ik.solver.leftHandEffector.rotation.        // 注意:如果你想要旋轉手,同時不改變手臂綁定        // 最好在FBBIK更新結束之後,再直接旋轉手(使用委託事件OnPostUpdate)        ik.solver.leftHandEffector.rotationWeight = 1f;        // 使手便宜它的動畫位置,如果反應器的positionWeight為1, 它沒有作用。        // 注意:在反應器每幀更新完之後他會重置positionOffset 到 Vector3.zero所以你必須另外設置它.        // This enables you to easily edit the value by more than one script.        ik.solver.leftHandEffector.positionOffset += something;        // 反應器模式用來改變肢體行為方式,當沒有參與的時候。The effector mode is for changing the way the limb behaves when not weighed in.        // Free 表示node完全有solver決定。Free means the node is completely at the mercy of the solver.        // 如果你碰到動作平滑問題,你可以試試把手的模式改為MaintainAnimatedPosition 或 MaintainRelativePosition        // MaintainAnimatedPosition在每次迭代解算的時候,重置node到骨骼動畫位置        // 這對腳非常有用,因為一般你需要他們在動畫位置上。        // MaintainRelativePositionWeight 維護相關部位的相對位置,胸部相對手臂,臀部相對腿。maintains the limb's position relative to the chest for the arms and hips for the legs.        // 所以,如果你從左手拉動角色,右手臂會隨著胸部運動。        // 一般你不需要把這個行為應用到腿部。        ik.solver.leftHandEffector.maintainRelativePositionWeight = 1f;        // 軀體反應器是一個【多反應器】,表示在解算器裡它跟其他node一起操控,明確的說是左右大腿。        // 所以,你可以帶著大腿骨骼移動軀體反應器。如果我們設置effectChildNodes 為 false,大腿node就不會被軀體反應器改變。        ik.solver.body.effectChildNodes = false;        // 其他反應器:rightHandEffector, leftFootEffector, rightFootEffector, leftShoulderEffector, rightShoulderEffector,leftThighEffector, rightThighEffector, bodyEffector        // 你也可以通過下面的方法找到反應器:        ik.solver.GetEffector(FullBodyBipedEffector effectorType);        ik.solver.GetEffector(FullBodyBipedChain chainType);        ik.solver.GetEndEffector(FullBodyBipedChain chainType); // 值返回手或腳反應器    }            // 訪問鏈:    public FullBodyBipedIK ik;    void LateUpdate () {        ik.solver.leftArmChain.pull = 1f; // 改變左臂pull值        ik.solver.leftArmChain.reach = 0f; // 改變左臂Reach值        // 其他鏈:rightArmChain, leftLegChain, rightLegChain, chain (根鏈)        // 你可以用下面的方法找到鏈:        ik.solver.GetChain(FullBodyBipedChain chainType);        ik.solver.GetChain(FullBodyBipedEffector effectorType);    }        //訪問映射:    public FullBodyBipedIK ik;    void LateUpdate () {        ik.solver.spineMapping.iterations = 2; // 改變脊柱映射迭代次數        ik.solver.leftArmMapping.maintainRotationWeight = 1f; // 使左手處理旋轉與動畫保持一致。Make the left hand maintain it's rotation as animated.        ik.solver.headMapping.maintainRotationWeight = 1f; // 使頭部旋轉處理與動畫一致。Make the head maintain it's rotation as animated.    }            //運行時添加 FullBodyBipedIK (UMA):    using RootMotion; // 需要先包含RootMotion 命名空間,因為BipedReferences類    FullBodyBipedIK ik;    // 任何時候可以調用下面的方法    // 注意,FBBIK初始化的時候要採樣角色pose,所以再調用這個方法的時候肢體需要被彎曲到自然方向    void AddFBBIK (GameObject go, BipedReferences references = null) {        if (references == null) { // 還沒有定義biped的時候,自動檢測它            BipedReferences.AutoDetectReferences(ref references, go.transform, BipedReferences.AutoDetectParams.Default);        }        ik = go.AddComponent<FullBodyBipedIK>(); // 添加組件        // 設置FBBIK到references. 第二個參數可以為空(root node) 如果你信任FBBIK自動檢測到根節點在正確的脊柱骨骼上        ik.SetReferences(references, null);    }            //優化FullBodyBipedIK:    //如果角色沒有顯示,可以使用renderer.isVisible來顯示    //大部分時間你不需要這麼的solver迭代和脊椎映射迭代。注意: 如果只有一次迭代,角色的肩膀和大腿拉動手和腳的時候可能想脫臼    //如果不需要“Reach”值,請保持它為0。它默認=0.05f來提高精度。    //保持Spine Twist 權重=0。如果你不需要他。    //同樣設置"Spine Stiffness", "Pull Body Vertical" and/or "Pull Body Horizontal" =0 可以提高性能。            //肢體:    // LimbIK 繼承 TrigonometricIK 來定義3段 類似手臂和腿的肢體。    // LimbIK由以下幾個修Bend改器組成:    // Animation: 嘗試按動畫控制彎曲方向    // Target: 根據目標IKRotation旋轉彎曲方向    // Parent: 根據父物體旋轉彎曲方向(盆骨或鎖骨)    // Arm: 保持在生物統計學的鬆弛位置彎曲手臂(相對上面的,它的消耗更大)    // 如果所有的bend修改器都不適合你的要求,那麼你可以添加彎曲目標,簡單如下;    using RootMotion.FinalIK;    public LimbIK limbIK;    void LateUpdate () {        limbIK.solver.SetBendGoalPosition(transform.position);    }    // 這會使limb彎曲到 從第一個bone指向goal位置的方向    // IKSolverLimb.maintainRotationWeight 屬性允許操控最後一個骨骼,使它保持在肢體解算器前的世界左邊旋轉值    // 當你需要復位腳的時候這非常有用,但This is most useful when we need to reposition a foot, but maintain it's rotation as it was animated to ensure proper alignment with the ground surface.    // 開始:    // 添加LimbIK 組件到角色跟物體(角色需要朝前)    // 添加骨骼到LimbIK組件 bone1, bone2 and bone3    // 按play    // 用腳本實現:    public LimbIK limbIK;    void LateUpdate () {        // 改變目標位置、旋轉、權重        limbIK.solver.IKPosition = something;        limbIK.solver.IKRotation = something;        limbIK.solver.IKPositionWeight = something;        limbIK.solver.IKRotationWeight = something;        // 改變自動bend修改器        limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Animation; // 按動畫控制彎曲方向        limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Target; // 按目標旋轉控制彎曲        limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Parent; // 根據父骨骼控制彎曲方向(盆骨、肩膀)        // 嘗試按生物學鬆弛狀態控制手臂彎曲方向        // 腿部不會受這個影響        limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Arm;    }    //運行時添加LimbIK:    //通過腳本添加    LimbIK.solver.SetChain()            //旋轉限制:    //所有旋轉約束和其他FinalIK組件都是基於Quaternion(四元數)和Axis-Angle(軸角)以確保一致性,連續性和最小化奇異問題。FinalIK沒有包含簡單歐拉角選項。    //所有旋轉約束基於local rotation 並且像Physics 關節一樣使用初始local rotation 作為引用。這使它軸獨立,并容易設置。    //所有旋轉約束可以在SceneView 可以undo    //所有旋轉約束支持與IK解算器聯合工作            //角度mode    //簡單的角度擺動和扭動限制        //鉸鏈mode    //鉸鏈旋轉限制限制限制關節只繞某個軸旋轉一定角度。它旋轉值可以超過360度。                    //多邊形mode    // 使用一個球面多邊形來限制旋轉範圍,這是普遍存在的球窩使關節。 A reach cone is specified as a spherical polygon on the surface of a a reach sphere that defines all    // positions the longitudinal segment axis beyond the joint can take.    // twist limit 參數定義了圍繞主軸最大扭轉角度    // 這個類基於論文:    // "Fast and Easy Reach-Cone Joint Limits"    // Jane Wilhelms and Allen Van Gelder. Computer Science Dept., University of California, Santa Cruz, CA 95064. August 2, 2001    // 多邊形角度限制模式提供方便快速編輯SceneView工具,來編輯、克隆和修改reachcone點        //樣條線mode    // 使用樣條線限制普遍的球窩關節的旋轉範圍    // 通過AnimationCurve正交投影到球面獲得光滑、快速的限制範圍。    // twist limit 參數定義了圍繞主軸最大扭轉角度    // 樣條線角度限制模式提供方便快速編輯SceneView工具,來編輯、克隆和修改reachcone點                //擴展Final IK    // FinalIK的IK解算器和旋轉限制架構基於可擴展思想搭建。    // FinalIK的一些組件比如BipedIK, 本質上僅僅是IK解算器的收集器    // 自定義IK組件:    // 在你發掘出FinalIK全部能力之前,了解一些它的架構非常重要。    // IK組件和IK解算器之間的區別:    // 架構上,IK解算器類包括反向關節功能,而IK組件只是擁有、初始化、更新他的解算器然後提供SceneView操作手柄和自定義inspector。    // 因此,IK解算器完全獨立於他的組件,並且可以完全脫離直接引用來使用:    using RootMotion.FinalIK;    public IKSolverCCD spine = new IKSolverCCD();    public IKSolverLimb limb = new IKSolverLimb();    void Start() {        // 基於多種原因,根transform引用在IK解算器初始化的時候引用。        // 啟發式解算器(CCD) IKSolverCCD, IKSolverFABRIK and IKSolverAim 只需要用它作為警告log的上下文。        // 角色解算器 IKSolverLimb, IKSolverLookAt, BipedIK and IKSolverFullBodyBiped 用它來定義相對與角色的方向。        // IKSolverFABRIKRoot 使用它作為所有FABRIK鏈的根        spine.Initiate(transform);        limb.Initiate(transform);    }    void LateUpdate() {        // 按順序更新IK解算器        // 在多IK解算器擁有骨骼層次,先初始化的它的父物體比較好。        spine.Update();        limb.Update();    }    // 你現在有了一個自己的IK組件    // 如果你想把自己的功能全部放在單個組件里,像 BipedIK,所以你不會管理很多不同的IK組件在你的場景裡        // 寫自定義旋轉限制:    // 所有旋轉限制都繼承抽象類RotationLimit 構建自己的類同樣需要繼承這個基類,并覆蓋抽象方法。    protected abstract Quaternion LimitRotation(Quaternion rotation);    // 這個方法里你需要應用約束,并返回輸入Quaternion    // 注意:比較重要,Quaternion已經轉換為物體的默認的local rotation空間,意味著如果你返回Quaternion.identity,物體會總是會被修正到他的初始local rotation    // 下面的代碼是一個創建自定義旋轉限制的模板:    using RootMotion.FinalIK;    // 聲明類并繼承RotationLimit.cs    public class RotationLimitCustom: RotationLimit {        // 在實例Transform的local空間限制旋轉        protected override Quaternion LimitRotation(Quaternion rotation) {            return MyLimitFunction(rotation);        }    }    // 新旋轉限制由所有可約束的IK解算器認可并自動應用。    // 組合IK組件:    // 當創建更複雜的IK系統時,你可能需要完全控制解算器的更新順序。要這麼做,你只要禁用他們的組件,并用外部腳本管理他們的解算器    // 所有IK組件繼承類IK,而所有IK解算器繼承抽象類IKSolver。這讓你很容易的掌控和替代解算器,而不需要知道特別的解算器類型    // 控制多重IK組件的更新順序    using RootMotion.FinalIK;    // IK組件數組,你可以從inspector賦值    // IK是抽象類,所以你不用使用的是考慮那個特別的IK組件類型 is abstract, so it does not matter which specific IK component types are used.    public IK[] components;    void Start() {        // 禁用所有其他IK組件,這樣他們不會更新解算器。使用 Disable() 代替=false 後者不能保證初始化。        foreach (IK component in components) component.Disable();    }    void LateUpdate() {        // 按順序更新IK解算器        foreach (IK component in components) component.GetIKSolver().Update();    }                                      


0 0
原创粉丝点击