Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7993
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-16 18:31
文章分类

全部博文(1)

文章存档

2015年(1)

我的朋友
最近访客

分类: C#/.net

2015-04-16 18:35:15


点击(此处)折叠或打开

  1. /*
  2. 全身BipedIK
  3.     Final IK 為採用biped骨骼的角色提供了一個極端靈活、強大且高效的全身IK解算器。FBBIK先把Biped角色映射到一個低解析度的多反應器角色IK綁定,解算它,然後重新把結果映射角色。這個過程在LateUpdate進行,在Mecanim/Legacy動畫完成之後,所以它跟animator系統完全分離。
  4.  
  5. 鏈:
  6.     內部,每個肢體和軀幹都是FBIKChain類的實例。軀幹是根鏈,只包含一個node,軀幹是它的子鏈。這種設置形成一個圍繞根鏈的多反應器IK樹。
  7.  
  8. 節點:
  9.     node是鏈的組成部分。比如,手臂鏈包括3個節點-上臂、前臂、手。每個節點維護一個到骨骼的引用(node.transform)。當解算器運行或者結束后,解算出的骨骼位置會保存在node.solverPosition。
  10.  
  11. 反應器:
  12.     FBBIK有3種反應器-【末端反應器】(手、腳),【中間反應器】(肩膀、大腿)和【多反應器】(軀幹)。當旋轉【中間反應器】和【多反應器】無效的時候可以轉動【末端反應器】。旋轉【末端反應器】同樣會改變軀幹的彎曲方向(除非你用彎曲目標覆蓋它)。軀幹反應器是一個【多反應器】,意味著它拖動2個大腿反應器(簡化軀幹定位)。反應器有positionOffset屬性可以非常簡單的操控下層動畫。反應器會在每次解算結束之後將postionOffset重置為Vector3.zero。
  13.   
  14. 拉和伸:
  15.     每個鏈都有pull屬性。當pull=1,pull權重跟肢體一樣。這意味著你觸到所有反應器是沒有保障的,太遠的會接觸不到。可以通過修改reach參數,或增加解算迭代次數,或這每幀多次解算,來調整或者改進這個結果。但是,如果你把左臂鏈的pull權重設置到1然後其他都為0,那麼你可以拉角色的左手到無限遠而不丟失聯繫。
  16.  
  17. 映射:
  18.     IKSolverFullBodyBiped解算一個非常低分辨率的快速軀殼。雖然你的角色有多得多的脊椎骨,他可能有兩倍的骨骼在手臂和肩膀或者臀部骨骼等等。因此,在解算之前,解算器需要映射高分辨率的骨架到低分辨率的解算骨架,在解算完成之後再逆向操作。有3種映射器,1.IKMappingSpine用來映射盆骨和脊柱;2.IKMappingLimb映射軀幹;3.IKMappingBone映射頭部;你可以通過IKSolverFullBody.spineMappingIKSolverFullBody.limbMappings和IKSolverFullBody.boneMappings訪問他們。
  19.      
  20. 限制:
  21.     1.FullBodyBipedIK沒有頭部反應器。因為頭部只有一個骨頭,你可以再FullBodyIK結束之後隨意轉動,而且,只有極少的情況你需要抓住頭部拉動角色。即使如此,它可以通過拉動肩膀來很好的模擬。這是一個讓程序更快、更穩定的優化措施。
  22.     2.FullBodyBipedIK沒有手指和腳趾反應器。解算手指IK似乎有點過分使用IK了,因為極少有遊戲對手指做綁定。使用104段CCD或者FABRIK鏈控制手指,可能這樣浪費寶貴的毫秒數並不是你想要的。你可以參考DrivingRigdemo了解如何快速擺手指到物體上。
  23.     3.FullBodyBipedIK採樣角色的初始pose(在Start()函數,當每次你重新初始化解算器的時候)找到以什麼方式彎曲肢體。從此,限制-角色的肢體需要被彎曲到自然的方向。有些角色可能是處於T-Pose,他們的肢體是伸直的。有些角色的肢體可能還輕微的往反向彎曲(有些Mixamo綁定的角色)。FullBodyBipedIK會警告你這些問題可能發生。你需要手動在SceneView稍微旋轉骨骼到正確的彎曲方向。因為,這些旋轉會在播放的時候被動畫覆蓋,所以你不用擔心搞壞你的角色。
  24.     4.FullBodyBipedIK 沒有肘部、膝部反應器。這功能在將來如果確實需要的話可能增加。仍然支持通過彎曲目標改變肘部、膝蓋的位置。
  25.     5.Optimize Game Objects 需要關閉,或者至少所有解算器需要的骨骼要引入(FullBodyBipedIK.references)。
  26.     6.支持只有扭曲動畫的額外骨骼。如果額外骨骼有擺動動畫,比如翅膀擺動。那麼FBBIK將不能正確解算。
  27.     7.FullBodyBipedIK 需要角色開啟animatePhysics。這是Mecanim系統的一個bug,它不允許運行時改變animatePhysics,那麼FullBodyBipedIK需要根據初始animatePhysics進行刷新。
  28.     8.FullBodyBipedIK不會在拉動手的時候旋轉肩膀。這樣可以維護胸部動畫的。大多數情況,這沒有問題,但有時候,特別是抓取或者有東西高於頭部的時候,讓肩膀跟著旋轉會更真實。這種情況,你不僅需要一個底層的抬起動畫,還需要肩膀骨骼在IK解算器讀取pose之前,能用腳本旋轉它。這裡同樣有一個腳本包括這個demo,它叫ShoulderRotator。
  29.     9.當你移動【末端反應器】並且反應器權重=0,FBBIK將在動畫的時候嘗試修復肢體的彎曲方向,當肢體旋轉接近180度的時候你將體驗到肢體的轟響,就是說,解算器無法知道在這個奇點上如何旋轉。比如,你有一個行走動畫,手下垂,而你想要夠到頭頂正上方的某個物體,這時候無論你做反應器旋轉動畫或者使用彎曲目標,要在接近180度生硬旋轉中確保手臂不翻轉都會很麻煩。這並不是一個bug,如果我們想要保持默認動畫彎曲方向,這在邏輯上是必然會發生的。
  30.     10.FullBodyBipedIK認定手肘和膝蓋關節是鉸鏈關節,就是說前臂不能相對上臂扭動。在最常見的綁定,像3dsMaxbiped上這沒問題,因為這些綁定阻止這類動畫出現。然而如果綁定允許這種扭曲。這不會導致FBBIK解算器失效,相反,FBBIK解算器會強制手肘和膝蓋約束到鉸鏈關節,即使它沒有反應器。這不會改變肢體末端,它會輕微的改變肢體彎曲方向,和骨骼的扭曲。
  31. 開始教程:
  32.     1.添加FullBodyBipedIK組件到角色根節點(與Animator/Animation組件相同)
  33.     2.確認自動檢測到的biped references正確。
  34.     3.確認跟節點正確檢測到。它應該是脊柱下端的骨骼。
  35.     4.看下SceneView,確認FBBIK骨架在角色上顯示。
  36.     5.按Play,操控解算器。
  37. */
  38. //訪問反應器:
  39.     public FullBodyBipedIK ik;
  40.     void LateUpdate () {
  41.         ik.solver.leftHandEffector.position = something; // 設置左手反應器位置(世界坐標)。如果把權重設置到0,反應器會沒有效果。
  42.         ik.solver.leftHandEffector.rotation = something; // 設置左手反應器旋轉(世界坐標)。如果把權重設置到0,反應器會沒有效果。
  43.         ik.solver.leftHandEffector.positionWeight = 1f; // 反應器位置權重,這裡設為1,左手位置會被固定到ik.solver.leftHandEffector.position.
  44.         // 反應器旋轉權重,這裡設為1,左手和手臂旋轉會被固定到ik.solver.leftHandEffector.rotation.
  45.         // 注意:如果你想要旋轉手,同時不改變手臂綁定
  46.         // 最好在FBBIK更新結束之後,再直接旋轉手(使用委託事件OnPostUpdate)
  47.         ik.solver.leftHandEffector.rotationWeight = 1f;
  48.         // 使手便宜它的動畫位置,如果反應器的positionWeight為1, 它沒有作用。
  49.         // 注意:在反應器每幀更新完之後他會重置positionOffset 到 Vector3.zero所以你必須另外設置它.
  50.         // This enables you to easily edit the value by more than one script.
  51.         ik.solver.leftHandEffector.positionOffset += something;
  52.         // 反應器模式用來改變肢體行為方式,當沒有參與的時候。The effector mode is for changing the way the limb behaves when not weighed in.
  53.         // Free 表示node完全有solver決定。Free means the node is completely at the mercy of the solver.
  54.         // 如果你碰到動作平滑問題,你可以試試把手的模式改為MaintainAnimatedPosition 或 MaintainRelativePosition
  55.         // MaintainAnimatedPosition在每次迭代解算的時候,重置node到骨骼動畫位置
  56.         // 這對腳非常有用,因為一般你需要他們在動畫位置上。
  57.         // MaintainRelativePositionWeight 維護相關部位的相對位置,胸部相對手臂,臀部相對腿。maintains the limb's position relative to the chest for the arms and hips for the legs.
  58.         // 所以,如果你從左手拉動角色,右手臂會隨著胸部運動。
  59.         // 一般你不需要把這個行為應用到腿部。
  60.         ik.solver.leftHandEffector.maintainRelativePositionWeight = 1f;
  61.         // 軀體反應器是一個【多反應器】,表示在解算器裡它跟其他node一起操控,明確的說是左右大腿。
  62.         // 所以,你可以帶著大腿骨骼移動軀體反應器。如果我們設置effectChildNodes 為 false,大腿node就不會被軀體反應器改變。
  63.         ik.solver.body.effectChildNodes = false;
  64.         // 其他反應器:rightHandEffector, leftFootEffector, rightFootEffector, leftShoulderEffector, rightShoulderEffector,leftThighEffector, rightThighEffector, bodyEffector
  65.         // 你也可以通過下面的方法找到反應器:
  66.         ik.solver.GetEffector(FullBodyBipedEffector effectorType);
  67.         ik.solver.GetEffector(FullBodyBipedChain chainType);
  68.         ik.solver.GetEndEffector(FullBodyBipedChain chainType); // 值返回手或腳反應器
  69.     }
  70.       
  71.       
  72.     // 訪問鏈:
  73.     public FullBodyBipedIK ik;
  74.     void LateUpdate () {
  75.         ik.solver.leftArmChain.pull = 1f; // 改變左臂pull值
  76.         ik.solver.leftArmChain.reach = 0f; // 改變左臂Reach值
  77.         // 其他鏈:rightArmChain, leftLegChain, rightLegChain, chain (根鏈)
  78.         // 你可以用下面的方法找到鏈:
  79.         ik.solver.GetChain(FullBodyBipedChain chainType);
  80.         ik.solver.GetChain(FullBodyBipedEffector effectorType);
  81.     }
  82.   
  83.       
  84.     //訪問映射:
  85.     public FullBodyBipedIK ik;
  86.     void LateUpdate () {
  87.         ik.solver.spineMapping.iterations = 2; // 改變脊柱映射迭代次數
  88.         ik.solver.leftArmMapping.maintainRotationWeight = 1f; // 使左手處理旋轉與動畫保持一致。Make the left hand maintain it's rotation as animated.
  89.         ik.solver.headMapping.maintainRotationWeight = 1f; // 使頭部旋轉處理與動畫一致。Make the head maintain it's rotation as animated.
  90.     }
  91.       
  92.       
  93.     //運行時添加 FullBodyBipedIK (UMA):
  94.     using RootMotion; // 需要先包含RootMotion 命名空間,因為BipedReferences類
  95.     FullBodyBipedIK ik;
  96.     // 任何時候可以調用下面的方法
  97.     // 注意,FBBIK初始化的時候要採樣角色pose,所以再調用這個方法的時候肢體需要被彎曲到自然方向
  98.     void AddFBBIK (GameObject go, BipedReferences references = null) {
  99.         if (references == null) { // 還沒有定義biped的時候,自動檢測它
  100.             BipedReferences.AutoDetectReferences(ref references, go.transform, BipedReferences.AutoDetectParams.Default);
  101.         }
  102.         ik = go.AddComponent<FullBodyBipedIK>(); // 添加組件
  103.         // 設置FBBIK到references. 第二個參數可以為空(root node) 如果你信任FBBIK自動檢測到根節點在正確的脊柱骨骼上
  104.         ik.SetReferences(references, null);
  105.     }
  106.       
  107.       
  108.     //優化FullBodyBipedIK:
  109.     //如果角色沒有顯示,可以使用renderer.isVisible來顯示
  110.     //大部分時間你不需要這麼的solver迭代和脊椎映射迭代。注意: 如果只有一次迭代,角色的肩膀和大腿拉動手和腳的時候可能想脫臼
  111.     //如果不需要“Reach”值,請保持它為0。它默認=0.05f來提高精度。
  112.     //保持Spine Twist 權重=0。如果你不需要他。
  113.     //同樣設置"Spine Stiffness", "Pull Body Vertical" and/or "Pull Body Horizontal" =0 可以提高性能。
  114.       
  115.       
  116.     //肢體:
  117.     // LimbIK 繼承 TrigonometricIK 來定義3段 類似手臂和腿的肢體。
  118.     // LimbIK由以下幾個修Bend改器組成:
  119.     // Animation: 嘗試按動畫控制彎曲方向
  120.     // Target: 根據目標IKRotation旋轉彎曲方向
  121.     // Parent: 根據父物體旋轉彎曲方向(盆骨或鎖骨)
  122.     // Arm: 保持在生物統計學的鬆弛位置彎曲手臂(相對上面的,它的消耗更大)
  123.     // 如果所有的bend修改器都不適合你的要求,那麼你可以添加彎曲目標,簡單如下;
  124.     using RootMotion.FinalIK;
  125.     public LimbIK limbIK;
  126.     void LateUpdate () {
  127.         limbIK.solver.SetBendGoalPosition(transform.position);
  128.     }
  129.     // 這會使limb彎曲到 從第一個bone指向goal位置的方向
  130.     // IKSolverLimb.maintainRotationWeight 屬性允許操控最後一個骨骼,使它保持在肢體解算器前的世界左邊旋轉值
  131.     // 當你需要復位腳的時候這非常有用,但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.
  132.     // 開始:
  133.     // 添加LimbIK 組件到角色跟物體(角色需要朝前)
  134.     // 添加骨骼到LimbIK組件 bone1, bone2 and bone3
  135.     // 按play
  136.     // 用腳本實現:
  137.     public LimbIK limbIK;
  138.     void LateUpdate () {
  139.         // 改變目標位置、旋轉、權重
  140.         limbIK.solver.IKPosition = something;
  141.         limbIK.solver.IKRotation = something;
  142.         limbIK.solver.IKPositionWeight = something;
  143.         limbIK.solver.IKRotationWeight = something;
  144.         // 改變自動bend修改器
  145.         limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Animation; // 按動畫控制彎曲方向
  146.         limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Target; // 按目標旋轉控制彎曲
  147.         limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Parent; // 根據父骨骼控制彎曲方向(盆骨、肩膀)
  148.         // 嘗試按生物學鬆弛狀態控制手臂彎曲方向
  149.         // 腿部不會受這個影響
  150.         limbIK.solver.bendModifier = IKSolverLimb.BendModifier.Arm;
  151.     }
  152.     //運行時添加LimbIK:
  153.     //通過腳本添加
  154.     LimbIK.solver.SetChain()
  155.       
  156.       
  157.     //旋轉限制:
  158.     //所有旋轉約束和其他FinalIK組件都是基於Quaternion(四元數)和Axis-Angle(軸角)以確保一致性,連續性和最小化奇異問題。FinalIK沒有包含簡單歐拉角選項。
  159.     //所有旋轉約束基於local rotation 並且像Physics 關節一樣使用初始local rotation 作為引用。這使它軸獨立,并容易設置。
  160.     //所有旋轉約束可以在SceneView 可以undo
  161.     //所有旋轉約束支持與IK解算器聯合工作
  162.       
  163.       
  164.     //角度mode
  165.     //簡單的角度擺動和扭動限制
  166.       
  167.     //鉸鏈mode
  168.     //鉸鏈旋轉限制限制限制關節只繞某個軸旋轉一定角度。它旋轉值可以超過360度。
  169.       
  170.       
  171.       
  172.       
  173.     //多邊形mode
  174.     // 使用一個球面多邊形來限制旋轉範圍,這是普遍存在的球窩使關節。 A reach cone is specified as a spherical polygon on the surface of a a reach sphere that defines all
  175.     // positions the longitudinal segment axis beyond the joint can take.
  176.     // twist limit 參數定義了圍繞主軸最大扭轉角度
  177.     // 這個類基於論文:
  178.     // "Fast and Easy Reach-Cone Joint Limits"
  179.     // Jane Wilhelms and Allen Van Gelder. Computer Science Dept., University of California, Santa Cruz, CA 95064. August 2, 2001
  180.     // 多邊形角度限制模式提供方便快速編輯SceneView工具,來編輯、克隆和修改reachcone點
  181.       
  182.     //樣條線mode
  183.     // 使用樣條線限制普遍的球窩關節的旋轉範圍
  184.     // 通過AnimationCurve正交投影到球面獲得光滑、快速的限制範圍。
  185.     // twist limit 參數定義了圍繞主軸最大扭轉角度
  186.     // 樣條線角度限制模式提供方便快速編輯SceneView工具,來編輯、克隆和修改reachcone點
  187.       
  188.       
  189.       
  190.     //擴展Final IK
  191.     // FinalIK的IK解算器和旋轉限制架構基於可擴展思想搭建。
  192.     // FinalIK的一些組件比如BipedIK, 本質上僅僅是IK解算器的收集器
  193.     // 自定義IK組件:
  194.     // 在你發掘出FinalIK全部能力之前,了解一些它的架構非常重要。
  195.     // IK組件和IK解算器之間的區別:
  196.     // 架構上,IK解算器類包括反向關節功能,而IK組件只是擁有、初始化、更新他的解算器然後提供SceneView操作手柄和自定義inspector。
  197.     // 因此,IK解算器完全獨立於他的組件,並且可以完全脫離直接引用來使用:
  198.     using RootMotion.FinalIK;
  199.     public IKSolverCCD spine = new IKSolverCCD();
  200.     public IKSolverLimb limb = new IKSolverLimb();
  201.     void Start() {
  202.         // 基於多種原因,根transform引用在IK解算器初始化的時候引用。
  203.         // 啟發式解算器(CCD) IKSolverCCD, IKSolverFABRIK and IKSolverAim 只需要用它作為警告log的上下文。
  204.         // 角色解算器 IKSolverLimb, IKSolverLookAt, BipedIK and IKSolverFullBodyBiped 用它來定義相對與角色的方向。
  205.         // IKSolverFABRIKRoot 使用它作為所有FABRIK鏈的根
  206.         spine.Initiate(transform);
  207.         limb.Initiate(transform);
  208.     }
  209.     void LateUpdate() {
  210.         // 按順序更新IK解算器
  211.         // 在多IK解算器擁有骨骼層次,先初始化的它的父物體比較好。
  212.         spine.Update();
  213.         limb.Update();
  214.     }
  215.     // 你現在有了一個自己的IK組件
  216.     // 如果你想把自己的功能全部放在單個組件里,像 BipedIK,所以你不會管理很多不同的IK組件在你的場景裡
  217.       
  218.     // 寫自定義旋轉限制:
  219.     // 所有旋轉限制都繼承抽象類RotationLimit 構建自己的類同樣需要繼承這個基類,并覆蓋抽象方法。
  220.     protected abstract Quaternion LimitRotation(Quaternion rotation);
  221.     // 這個方法里你需要應用約束,并返回輸入Quaternion
  222.     // 注意:比較重要,Quaternion已經轉換為物體的默認的local rotation空間,意味著如果你返回Quaternion.identity,物體會總是會被修正到他的初始local rotation
  223.     // 下面的代碼是一個創建自定義旋轉限制的模板:
  224.     using RootMotion.FinalIK;
  225.     // 聲明類并繼承RotationLimit.cs
  226.     public class RotationLimitCustom: RotationLimit {
  227.         // 在實例Transform的local空間限制旋轉
  228.         protected override Quaternion LimitRotation(Quaternion rotation) {
  229.             return MyLimitFunction(rotation);
  230.         }
  231.     }
  232.     // 新旋轉限制由所有可約束的IK解算器認可并自動應用。
  233.     // 組合IK組件:
  234.     // 當創建更複雜的IK系統時,你可能需要完全控制解算器的更新順序。要這麼做,你只要禁用他們的組件,并用外部腳本管理他們的解算器
  235.     // 所有IK組件繼承類IK,而所有IK解算器繼承抽象類IKSolver。這讓你很容易的掌控和替代解算器,而不需要知道特別的解算器類型
  236.     // 控制多重IK組件的更新順序
  237.     using RootMotion.FinalIK;
  238.     // IK組件數組,你可以從inspector賦值
  239.     // IK是抽象類,所以你不用使用的是考慮那個特別的IK組件類型 is abstract, so it does not matter which specific IK component types are used.
  240.     public IK[] components;
  241.     void Start() {
  242.         // 禁用所有其他IK組件,這樣他們不會更新解算器。使用 Disable() 代替=false 後者不能保證初始化。
  243.         foreach (IK component in components) component.Disable();
  244.     }
  245.     void LateUpdate() {
  246.         // 按順序更新IK解算器
  247.         foreach (IK component in components) component.GetIKSolver().Update();
  248.     }


阅读(1850) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~