青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

永遠也不完美的程序

不斷學習,不斷實踐,不斷的重構……

常用鏈接

統計

積分與排名

好友鏈接

最新評論

人物動畫系統(轉)

我最近在學習人物動畫的方面,做個總結,由于剛剛接觸這個方面,所以有什么問題請大家指出。

在這篇日志里面,你可以獲得這些信息:

1 人物動畫的框架
2 骨骼動畫及蒙皮技術
3 doom 3和quake 4中模型和動畫格式md5及原理
4 可能的擴展


先來看一下人物動畫的幾種方法:

一、簡單關鍵禎的動畫

  像quake3中就是用的這樣的方法。這種方法最簡單,缺點就是空間上的浪費。由于每個關鍵禎中都要儲存整個網格的幾何信息,所以用這種方法生成的動畫文件相當的龐大,在游戲進行中也會占用大量的內存。現在的游戲,一般都不用了。

二、簡單的骨骼動畫及蒙皮技術

  現在的很多游戲,都是用的這種方法,具體的原理后面再解釋。這種方法可以節省大量的空間,對于美工來說,工作量也相對較小(可以利用動作捕捉的數據),真實性方面,簡單的應用中也表現得比較好。

三、改進的蒙皮方法和基于物理的骨骼動畫

  改進的蒙皮方法可以避免簡單的蒙皮中產生的“糖紙失真現象”;

  基于物理的骨骼動畫,已經有很多的游戲、物理引擎支持這一特性了,但是還有很多的技術問題需要處理。這是次時代游戲引擎必須很好實現技術之一。



基本的蒙皮原理

拿md5格式為例,來簡單的解釋一下蒙皮的原理。在doom3和quake4中md5mesh文件,用來記錄一個人物的靜態模型。有這樣幾個結構:

Joint: 用來記錄骨骼的關節的信息;
Weight: 用來記錄頂點相對于關節的權值;
Vertex: 頂點信息,和一般的頂點不同,這里的頂點不直接的包含幾何坐標信息,而是記錄了對應的Weight;

現在就來解釋一下這三者之間的關系:

  Joint(關節)是會動的,而皮膚上的頂點是會隨著頂點做相應的運動。我們保持皮膚上面的各個頂點和它相對應的關節的“位置關系”,就可以通過旋轉關節,使得真個皮膚跟著旋轉。這個“位置關系”,就是Weight。在運動的過程中,我們獲得當前的骨骼的幾何信息,也就是每個關節的幾何位置,然后在根據每個頂點對于這些關節的權值,分別計算每個頂點的實際幾何位置,這樣,整個人物網格就計算出來了。

  很顯然,這其中有一個預處理過程和兩個關鍵的步驟。預處理就是需要由靜態的模型(美工做出的人物模型)和骨骼來計算得到一組Weight;兩個關鍵的步驟是,1、獲得的整個骨骼的幾何信息(有可能從關鍵禎混合得到);2、由頂點對應的Weight來計算出每個頂點的實際幾何信息。

  了解這些基本的概念,下面就來介紹人物動畫系統的框架。


骨骼蒙皮基本框架

基本的類型:

關節信息:

typedef struct _CharJoint
{
    Vector3 pos;
    Vector4 startPoint;
    int parentID;
    char name[32];
} CharJoint;

其中,parentID為父關節,pos為對應父關節的偏移值,startPoint為旋轉角度;

權值信息:

typedef struct _CharWeight
{
    Vector3 pos;
    int jointID;
    float bias;
} CharWeight;

其中,pos為偏移量,jiontID為對應的joint,bias偏向值;


頂點信息:

typedef struct _CharVert
{
    float u, v;
    int startWeight;
    int weightCount;
} CharVert;

  其中,startWeight為該頂點對應的Weight在Weight列表中的偏移地址,weightCount記錄該頂點對應多少個權值;對于簡單的頂點,比如頭頂上的某個點,動畫的時候涉及到的變化并不多,所以,對應的權值數也就少,可以只有一個;對于動畫中涉及變化比較復雜的點,比如手肘區域的頂點,可能由較多的權值(4個或更多),這樣才能夠很好的表示運動中對于多個關節的相對位置。


大概還涉及到這樣一些類:

CharSkeleton: 記錄整個骨骼的信息,包含了關節的鏈表;
CharMesh: 記錄整個人物模型的靜態信息,包括頂點,權值,關節等;
CharBlender: 基類,根據CharMesh和CharSkeleton來計算出實際的網格,基本成員函數為Blender,用CPU來計算蒙皮,可以被子類Blend覆蓋(比如可以寫一個用Vertex Shader實現的Blender);
CharAnimation: 每個CharAnimation實例對應一個動作序列,比如“人物蹲下動作”;動作序列保存的是人物骨骼動畫的關鍵禎,也就是在某一禎時,骨骼中各個關節的幾何信息;注意這里的禎的概念并不是平常說的渲染的禎,在動畫中,為了進一步節省空間,一般設定了一個動作為幾個格,就像動漫制作過程中的“故事板”,只是整個過程中的幾個縮略圖,在后期制作過程中,在“填滿”中間缺省的圖片;這里的骨骼動畫關鍵禎也是如此,文件中只保存了間斷的幾個狀態,在渲染的時候,還是要實時的生成中間的某個狀態,來把整個動作序列“填滿”;
CharAnimCtrl: 這個類的作用就是完成上面所說的,將動作序列“填滿”的功能,輸入是CharAnimation和時間,輸出是一個基本的骨架,也就是CharSkeleton(當然這是靠傳引用參數進行輸出);


解決關鍵問題

  剛才提到了,整個系統中由三個關鍵的問題:一個預處理過程,關鍵禎混合以及從權值計算出實際頂點。預處理過程,基本上是編寫一個建模工具導出插件的工作,這里就不討論了。

關鍵禎混合:

  簡單的辦法,就是直接用線性的方法混合,比如現在的動畫時間標識為40,而我只有標識為20和50的兩個關鍵禎,于是:40-20 = 20,50-40 = 10;而20:10 = 2:1;所以,我們現在的狀態離關鍵禎20的差異,以及離關鍵禎50的差異,這兩個差異的比,就是2:1;好了,所以現在很自然地,我們取倒數,1:2;于是,我們做混合的時候,用“1份”關鍵禎20的骨骼,和“2份”50關鍵禎的骨骼,然后相加兩者的結果(也就是“混合”過程)最后,除以3,得到最終的“1份”關鍵禎為40的骨骼。恩,就這么簡單。(不過注意不要把這個比值的含義搞反了);

  際應用中還有其他的混合形式,后面再來介紹。


計算實際頂點:

我們看一下軟件的(用CPU做蒙皮)Blend過程:

void CharBlender::Blend( Mesh &outputMesh, PE::CharMesh &inputMesh, PE::CharSkeleton &inputSk )
{
    if ( outputMesh.GetNumVertices() < inputMesh.GetNumVerts() )
        return;

    CharOutVert *pOutVerts = ( CharOutVert* )outputMesh.LockVertexBuffer();
    int numVerts = inputMesh.GetNumVerts();
    int numTris = inputMesh.GetNumTris();

    for ( int i = 0; i < numVerts; i++ )
    {
        const CharVert *pVert = inputMesh.GetVertAt( i );
        pOutVerts->x = pOutVerts->y = pOutVerts->z = 0.0f;

        /* u v initial */
        pOutVerts->u0 = pOutVerts->u1 = pOutVerts->u2 = pVert->u;
        pOutVerts->v0 = pOutVerts->v1 = pOutVerts->v2 = pVert->v;

        for ( int j = 0; j < pVert->weightCount; j++ )
        {
            const CharWeight *pWeight = inputMesh.GetWeightAt( pVert->startWeight + j );
            int index = pWeight->jointID;
            const CharJoint *pJoint = & ( inputSk.GetJointAt( pWeight->jointID ) );
            vec3_t wv;
            Quat_rotatePoint( &pJoint->startPoint.x, &pWeight->pos.x, wv );
            pOutVerts->x += ( pJoint->pos[0] + wv[0] ) * pWeight->bias;
            pOutVerts->y += ( pJoint->pos[1] + wv[1] ) * pWeight->bias;
            pOutVerts->z += ( pJoint->pos[2] + wv[2] ) * pWeight->bias;
        }
    }

    outputMesh.UnlockVertexBuffer();

    CharTri *pOutTri = ( CharTri* )outputMesh.LockIndexBuffer();

    for ( int i = 0; i < numTris; i++ )
    {
        const CharTri *pTri = inputMesh.GetTriAt( i );
        pOutTri->index[0] = pTri->index[0];
        pOutTri->index[1] = pTri->index[1];
        pOutTri->index[2] = pTri->index[2];
    }

    outputMesh.UnlockIndexBuffer();
}

其中黑體的部分,就是關鍵的代碼,應該很容易看懂。其中,Quat_rotatePoint函數的作用就是將點進行旋轉,得到新的坐標。


關于md5anim文件

  Doom3和Quake4中的動畫文件都是用md5anim文件保存的。md5anim文件只含有該動作所涉及到的骨骼關節的動畫信息。也就是所,文件中關鍵禎的關節列表,是它所對應的md5mesh文件中基本關節列表的一個子集;這樣做當然是有道理的,因為,有些動作,可能只涉及到身體的一個部分,比如眨眼,換彈夾等等,那么,把一個完整的骨骼框架放在mesh文件中,把若干不同的局部或者整體的關節序列放在不同的動畫文件中,這樣,可以最大限度的節省空間。


可能的擴展

一、復雜動作的混合

  有時候,我們需要將兩個動作混合,比如,一個人物同時的在做兩種動作,一邊向左平移,一邊向右方開槍;不可能為每種可能的混合動作做大量的美工工作,而且空間上,我們也不允許這樣做;可行的辦法是,混合兩個不同的動作序列,比如上半身動作和下半身動作的混合,這當然是最簡單的方式。還有很多比較麻煩的混合方式,比如,人物在行走時中了槍,需要混合“行走”和“中槍”兩個動作,而簡單的線性混合是無法真實模擬的。

二、基于物理的動畫

  這不再僅是圖形方面的問題了,這其中涉及到了大量的物理模型,這個,我也不懂。。。可以從第三方的物理引擎獲得幫助,ODE好像就支持了;

三、基于GPU的蒙皮

  原理和CPU蒙皮的原理一致,只是用了Shader,會比CPU蒙皮的效率快很多。在前面的代碼中,只需實現CharBlender的子類就可以了。

四、非常流行的“換裝”系統

  這在RPG游戲里面簡直就是不可少的一條。就現在的框架來說,還不能達到隨意“換裝”的要求。修改CharMesh以及Character的底層,需要能夠添加和刪除基本的骨架,支持多層皮膚(衣服)(多個Mesh的開關)。還可以更換不同的武器(底層實現還是通過添加骨架完成)。。。

posted on 2008-11-12 11:39 狂爛球 閱讀(646) 評論(0)  編輯 收藏 引用 所屬分類: 圖形編程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美亚洲| 亚洲国产欧美一区| 看片网站欧美日韩| 亚洲欧美日韩在线综合| 欧美日韩国产麻豆| 亚洲国产欧美日韩精品| 亚洲精品日韩精品| 欧美精品成人在线| 亚洲国产日韩美| 亚洲欧洲综合另类| 久热成人在线视频| 亚洲国产精品成人久久综合一区| 在线观看国产精品淫| 久久久久久久久久久久久女国产乱 | 亚洲日本欧美日韩高观看| 99这里只有精品| 欧美精品一区二区久久婷婷| 亚洲第一页中文字幕| 亚洲精品你懂的| 在线一区二区三区四区五区| 久热精品视频在线免费观看| 欧美岛国在线观看| 欧美日韩国产色综合一二三四| 91久久精品国产91久久性色| 母乳一区在线观看| 亚洲精品美女91| 在线亚洲美日韩| 国产精品一区在线播放| 香蕉久久夜色精品国产| 久久一区二区三区av| 亚洲国产精品高清久久久| 欧美国产日本韩| 一本久久知道综合久久| 欧美在线观看网站| 亚洲成人在线视频网站| 欧美精品电影在线| 亚洲小视频在线| 麻豆成人在线| 亚洲免费av片| 国产女主播在线一区二区| 久久午夜羞羞影院免费观看| 亚洲精品视频二区| 久久gogo国模裸体人体| 91久久极品少妇xxxxⅹ软件| 国产精品qvod| 麻豆精品视频| 亚洲午夜激情在线| 欧美福利视频在线| 欧美一区二区黄| 亚洲人成网站影音先锋播放| 国产精品久久久久三级| 久久综合给合久久狠狠狠97色69| 亚洲精品国精品久久99热| 午夜一区不卡| 91久久久久久| 国产色综合久久| 欧美国产视频在线| 午夜日韩激情| 亚洲精品久久嫩草网站秘色| 久久av资源网| 亚洲午夜国产成人av电影男同| 伊人成综合网伊人222| 欧美视频在线不卡| 欧美不卡视频一区发布| 性色av一区二区怡红| 亚洲精品一品区二品区三品区| 久久成人18免费网站| 中文在线资源观看网站视频免费不卡| 国产性猛交xxxx免费看久久| 欧美视频官网| 免费观看成人| 亚洲欧美大片| 99热免费精品在线观看| 欧美激情在线| 六十路精品视频| 久久久国产精品一区二区中文 | 牛牛国产精品| 欧美在线视频观看免费网站| 亚洲天堂av图片| 91久久中文| 欧美好吊妞视频| 久久综合久色欧美综合狠狠| 欧美中在线观看| 亚洲一级免费视频| 乱中年女人伦av一区二区| 欧美一区二区在线观看| 一区二区三区四区蜜桃| 亚洲精品乱码久久久久久日本蜜臀| 国产在线欧美日韩| 国产精品久久久久久久7电影| 欧美精品久久久久久久久久| 久久久久久欧美| 久久精品一区| 欧美自拍偷拍午夜视频| 欧美一区二区三区视频| 亚洲淫性视频| 亚洲曰本av电影| 亚洲欧美国产毛片在线| 亚洲欧美日韩精品综合在线观看| 中文亚洲欧美| 一区二区欧美激情| 亚洲永久在线观看| 亚洲欧美日韩在线播放| 午夜精品美女自拍福到在线| 亚洲男女自偷自拍| 亚洲欧美一区二区在线观看| 性欧美8khd高清极品| 欧美一级久久久| 久久精品亚洲热| 免费成人在线观看视频| 免费看亚洲片| 欧美激情中文不卡| 欧美片第1页综合| 欧美午夜电影在线| 国产日韩欧美三级| 极品尤物av久久免费看| 伊人成年综合电影网| 亚洲国产成人精品女人久久久 | 欧美激情成人在线| 亚洲二区在线视频| 99精品欧美一区二区三区| 日韩视频免费观看| 亚洲一区二区三区乱码aⅴ| 欧美一级午夜免费电影| 欧美一区日本一区韩国一区| 久久这里有精品视频 | 亚洲欧美一区二区激情| 欧美一区2区三区4区公司二百| 久久gogo国模啪啪人体图| 蜜臀av国产精品久久久久| 欧美日产国产成人免费图片| 欧美体内she精视频在线观看| 国产精品久久亚洲7777| 国产亚洲综合在线| 亚洲精品麻豆| 先锋影音久久久| 男人的天堂成人在线| 日韩写真视频在线观看| 性感少妇一区| 老司机午夜精品视频| 欧美午夜欧美| 一区二区在线视频观看| 一区二区三区视频在线| 久久精品盗摄| 亚洲欧洲另类| 午夜精品理论片| 蜜臀av在线播放一区二区三区| 欧美日韩美女| 一区在线电影| 亚洲欧美精品在线观看| 欧美福利视频在线| 亚洲视频专区在线| 蜜桃伊人久久| 国产欧美日韩在线观看| 亚洲人成在线观看网站高清| 亚洲愉拍自拍另类高清精品| 欧美1级日本1级| 亚洲一区一卡| 欧美成人蜜桃| 亚洲美女精品一区| 亚洲国产经典视频| 亚洲欧美日韩直播| 欧美日韩亚洲国产精品| 在线电影国产精品| 亚洲综合色噜噜狠狠| 欧美福利影院| 亚洲欧美日韩国产中文| 欧美日韩视频一区二区三区| 怡红院精品视频| 亚洲欧美精品在线| 亚洲国产天堂久久国产91| 久久精精品视频| 国产精品一区久久久久| 日韩一级精品| 欧美激情日韩| 久久一二三区| 亚洲第一在线综合在线| 欧美国产日本在线| 久久中文久久字幕| 亚洲网站在线看| 久久国产精品电影| 亚洲麻豆av| 蜜桃久久av| 一区二区三区在线视频免费观看| 午夜精品999| 99re视频这里只有精品| 欧美国产日韩精品| 亚洲国产精品一区在线观看不卡| 久久久久久一区| 亚洲女与黑人做爰| 国产欧美日韩视频一区二区| 亚洲伊人久久综合| 亚洲精品综合在线| 欧美日韩精品一区二区| 一区二区三区www| 亚洲伦理在线| 欧美日韩性生活视频| 中文有码久久| 亚洲一区二区精品视频| 欧美性生交xxxxx久久久|