OpenGL10-骨骼動畫原理篇(2)


接上一篇的內容,上一篇,簡單的介紹了,骨骼動畫的原理,給出來一個

簡單的例程,這一例程將給展示一個最初級的人物動畫,具備多細節內容

以人走路為例子,當人走路的從一個站立開始,到邁出一步,這個過程是

一個連續的過程,在這個一個過程中,人身體的骨頭在位置在發生變化,

骨頭發生變化以后,人的皮膚,肌肉就隨着變化,上一個例程中我們計算

(OpenGL10-骨骼動畫原理篇(1))計算了根據骨頭的位置計算皮膚的位置

只是計算量一刻的動作,走路的過程是連續的,就意味着我們要記錄下來

骨頭在運動過程中所以位置變化數據,這樣才可以根據不同時刻的骨骼的

位置計算出來皮膚的位置。

現在問題出來了,如果美術做了一個動畫有5秒鍾,每一秒播放60幀來

計算,我們要記錄非常多的骨頭的信息,小下面這樣:

假設人有100個骨頭

Bone person[100]

一秒鍾60幀 × 5秒  × 100,這個就是我們要記錄的數據量,由此可見

數據量是非常大的,實際上大可不必這樣做,想一,是否可以記錄一個

關鍵幀的,其他的數據又關鍵幀來計算呢 ?假設我們記錄了10個關鍵點

其他的數據根據時間按照一定的插值算法進行插值,那么數據量就驟然

降低非常多呢。出於這樣的想法,我們增加了一個新的概念,關鍵幀。

骨骼動畫系統的流程如下:

  下面我們使用程序的角度來描述下該問題:

1.  獲取到所有的骨骼數據(可使用矩陣存儲)

Bone   bones[n];

2.  獲取到關鍵幀數據

Bone  arKeyFrame[n][KeyNumber];

3  獲取到皮膚(頂點數據)

Vertex  verts[vNumber];

4  通過插值計算出來新的骨骼位置

Bone   timeBone[n];

5  根據計算出來骨骼來計算頂點數據

Vert  temp[vNumber];

 

一個定點的聲明如下:

struct Vertex

//! 顏色 
float r, g, b, a; 
//! 位置
float x, y, z; 
//! 影響度 
float weights[2]; 
//! 矩陣的索引 
short matrixIndices[2]; 
//! 影響整個定點的骨頭個數 
short numBones;
};

  

聲明一個類,保存骨頭的信息.類如下所示,該類保存動畫的所有骨格信息:

struct Vertex
{
    //! 顏色
    float r, g, b, a;
    //! 位置
    float x, y, z;
    //! 影響度
    float weights[2];
    //! 矩陣的索引
    short matrixIndices[2];
    //! 影響整個定點的骨頭個數
    short numBones;
};

 

  接下來,聲明一動畫類,動畫類中維護關鍵幀數據

class   Frame
{
public:
    tmat4x4<float> _bone[2];
};

 一個動畫類,用來保存所有的關鍵幀數據,提供計算骨頭插值算法,

並輸出一幀的骨骼數據,類如下所示。

class   SkinAnimation
{
public:
    //! 根據給定的時間,輸出一幀骨骼的數據
    void    calcFrame(float t,Frame& frame)
    {
       
        frame._bone[0]  =   interpolate(_keyFrame[0]._bone[0],_keyFrame[1]._bone[0],t);
        frame._bone[1]  =   interpolate(_keyFrame[0]._bone[1],_keyFrame[1]._bone[1],t);
        
    }
    //!  該動畫有兩個關鍵幀
    Frame   _keyFrame[2];
};

 

  調用方式如下:

                /**
                *   產生時間
                */
                static  float   xxx =   0;
                
                /**
                *   根據關鍵幀計算出來新的骨骼位置
                */
                _skinAnima.calcFrame(xxx,frame);
                xxx +=  0.01f;

 

  然后我們將定點數據與計算出來的骨骼數據計算,得出最后的皮膚數據:

/**
*   繪制表皮,保存臨時點數據
*   這里根據新的骨頭的(就是插值計算出來以后的骨頭來計算皮膚的位置了)
*/
Vertex  calQuadVertices[12];
memcpy(calQuadVertices,g_quadVertices,sizeof(g_quadVertices));
for (int i = 0 ;i < 12 ; ++ i )
{
    tvec3<float>    vec(0,0,0);
    tvec3<float>    vecSrc(g_quadVertices[i].x,g_quadVertices[i].y,g_quadVertices[i].z);
    for (int x = 0 ; x < calQuadVertices[i].numBones ; ++ x)
    {
        //! 計算位置
        tvec3<float>    temp    =   vecSrc* frame._bone[g_quadVertices[i].matrixIndices[x]];
        //! 計算權重位置
        vec  += temp * g_quadVertices[i].weights[x];
    }
    calQuadVertices[i].x    =   vec.x;
    calQuadVertices[i].y    =   vec.y;
    calQuadVertices[i].z    =   vec.z;
}

 

  最后將計算出來的數據給OpenGL,進行繪制了:

glColorPointer(4,GL_FLOAT,sizeof(Vertex),calQuadVertices);
glVertexPointer(3,GL_FLOAT,sizeof(Vertex),((float*)calQuadVertices) + 4);
for (int i = 0 ;i < 3 ; ++ i )
{
    glDrawArrays(GL_LINE_LOOP,i * 4,4);
}

 

  

可執行文件以及代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM