您的位置:首页 > 移动开发 > Unity3D

Unity插件FinalIK部分说明书翻译

2015-04-16 17:54 871 查看
/*
全身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.
// 如果你碰到動作平滑問題,你可以試試把手的模式改為MaintainAnimat
4000
edPosition 或 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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c# unity3d finalik