1. 程式人生 > >基於FBX SDK的FBX模型解析與載入 -(三)

基於FBX SDK的FBX模型解析與載入 -(三)

6. 載入Camera和Light

在FBX模型中除了幾何資料外較為常用的資訊可能就是Camera和Light,雖然在遊戲中一般不直接從模型中得到這兩部分資訊,而是由引擎來提供,但是FBX中提供了對這些資訊儲存的支援。其實單純載入這兩部分的資訊很簡單,就像之前介紹的在整個Scene Graph中對每個Node遍歷過程中,判斷得到當前結點是Camera或Light時呼叫相應的ProcessCamera或ProcessLight來完成相關的處理操作即可。

如果對於當前結點判斷得到其是一個Camera結點,那麼可以直接呼叫GetCamera來得到一個KFbxCamera型別的指標,之後就可以通過該指標來完成Camera屬性的獲取。

  1. void ProcessCamera(KFbxNode* pNode)  
  2. {  
  3.     KFbxCamera* pCamera = pNode->GetCamera();  
  4.     // 呼叫相應的介面獲取Camera的屬性即可
  5. }  

對於Light結點的處理與Camera類似。至於Camera與Light結點所具有的屬性可以直接在SDK中看kfbxcamera與kfbxlight的型別定義即可。

  1. void ProcessLight(KFbxNode* pNode)  
  2. {  
  3.     KFbxLight* pLight = pNode->GetLight();  
  4.     // 呼叫相應的介面獲取Light的屬性即可
  5. }  

7. 載入動畫

動畫資訊是模型資料中非常重要的一部分,也是一個渲染或遊戲引擎最基本的需求之一。FBX對Animation的良好支援也成為其與.obj等靜態模型最主要區別之一,而且最新的SDK中也提供了對Animation很豐富與簡便的操作介面,包括自定義寫入與讀出等。接下來介紹一下如何使用FBX SDK來載入FBX中儲存的動畫資訊。

7.1 動畫資料讀取

在FBX中實現對於動畫資料的儲存主要通過以下三個物件層來實現:Animaiton Stack、 Animation Layer、Animation Node,其層次關係為

Animation Stack -> Animation Layer -> Animation Node,圖示化結構為(圖片來自於FBX SDKRef):

其中的Animation Stack為FBX動畫管理的最高層,其中包含著與之相關聯的Animation Layer等;每個Animation Stack對應著一套動作過程。每個Stack中包含一個或多個Animation Layer(當用來做blend時就需要多個Layer,但一般是一個)。在每個Layer中又通過一個KFbxAnimCurveNode的結點使Layer與具體的動畫資料發生關係。一般情況下可以根據自己的需要情況或引擎的動畫實現方式來讀取FBX中的動畫資料,例如本人在實現時從FBX中讀取資料的方法就可以抽像化為如下圖所示的結構:

其中對每個Node判斷其是否有對應的動畫資料,若有則讀取其Curve中的資料並存儲以供渲染更新使用,程式碼如下所述:

  1. void LoadNodeCurve(KFbxAnimLayer* pAnimationLayer , KFbxNode* pNode , StackTimeSpan& timeSpan)  
  2. {  
  3.     KTime       keyTimer;  
  4.     unsigned long millseconds;  
  5.     for(UINT i = 0 ; i < timeSpan.mKeyNums ; ++i)  
  6.     {  
  7.         millseconds = timeSpan.mStart + (float)i * timeSpan.mStep;  
  8.         keyTimer.SetMilliSeconds(millseconds);  
  9.         // 計算得到當前結點在當前時刻下所對應的空間區域性和全域性矩陣                
  10.         // 區域性矩陣對於Skeleton是必需的,因需要使用它來計算父子Skeleton之間的空間關係
  11.         KFbxXMatrix curveKeyLocalMatrix  = pNode->EvaluateLocalTransform(keyTimer);  
  12.         KFbxXMatrix curveKeyGlobalMatrix = pNode->EvaluateGlobalTransform(keyTimer);  
  13.     }  
  14. }  

程式碼中的timeSpan是一個自定義的結構,其中包含了整個FBX物件動畫資訊的相關資料,比如幀數、起始時間、幀間時差等;在讀取時需將其中的資訊轉換為一個KTime型別的物件(keyTimer)以供FBX SDK的API使用。上述操作載入了動畫資料中直接相關的空間Matrix資訊,這是普通模型物件的基本動畫資訊。但是對於Camera或Light等物件而言,動畫不僅包含著位置或空間資訊的變化而且還包含著一些其它的屬性變化如Camera的FOV,Light的Direction,Color等,這些資訊也匯出FBX時被儲存到了FBX中。而這些資訊的獲取就是通過KFbxCurveNode來實現,其關聯具體的Curve到相應的Property上,進而從中獲得對應的動畫資訊。比如我們熟悉的Camera實現中有一個常用的屬性PixelAspectRatio,用來描述視口Width與Height之間的比值,對於某些動畫效果這個Ratio可能是時變的,因而在建模時就會將該資訊同樣以動畫的資訊進行儲存,現在我們想要得到這一部分動畫資料。通過檢視kfbxcamera.h可以發現在KFbxCamera的定義中含有

KFbxTypedProperty<fbxDouble1> PixelAspectRatio

的一個成員變數,這即是PixelAspcetRatio動畫資料所儲存的位置;而在ProcessCamera時已經由當前Node的指標得到了Camera對應的指標,之後該部分讀取程式碼基本上如下所述:

  1. void LoadCameraCurve(KFbxAnimLayer* pAnimationLayer , KFbxCamera* pCamera , StackTimeSpan& timeSpan)  
  2. {  
  3.     if(pCamera == NULL)  
  4.     {  
  5.         return;  
  6.     }  
  7.     // 通過FBX的屬性物件而獲取其所對應的Animation Curve
  8.     KFbxAnimCurve* pCameraAttriAnimCurve = pCamera->PixelAspectRatio.GetCurve<KFbxAnimCurve>(pAnimationLayer);  
  9.     // 判斷當前的屬性是否含有可變的Animation值
  10.     if(pCameraAttriAnimCurve)  
  11.     {  
  12.         KTime         keyTimer;  
  13.         unsigned long millseconds;  
  14.         for(UINT i = 0 ; i < timeSpan.mKeyNums ; ++i)  
  15.         {  
  16.             millseconds = timeSpan.mStart + (float)i * timeSpan.mStep;  
  17.             keyTimer.SetMilliSeconds(millseconds);  
  18.             // 計算Camera的某屬性在當前時刻所對應的值
  19.             pCameraAttriAnimCurve->Evaluate(keyTimer);  
  20.         }  
  21.     }  
  22. }  

上述程式碼通過PixelAspectRatio的屬性物件載入了其不同時刻下的動畫值,其它的屬性的動畫讀取也可以用類似的操作實現。

7.2 動畫驅動

載入了上述的動畫資料以後,即可以使用其來驅動模型中的直接動畫相關部分,如Camera、Light、Skeleton等。由之前的程式碼可知,在載入動畫資料時我們使用了當前Node的指標,因而就可以用它在載入動畫時儲存其它的一些額外資訊使這些動畫資料與對應的Camera、Light、Skeleton等部件進行關聯(比如Node的指標,或是Node的Name等),從而可以從動畫管理器中隨時查得到某結點在指定時刻位置上的動畫資料。該部分可以根據具體的實現採取適宜的操作即可完成。

最後,帶有動畫驅動的Skeleton渲染效果如下列圖所示(Camera,Light的動畫效果木有繪出):