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

永遠也不完美的程序

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

常用鏈接

統計

積分與排名

好友鏈接

最新評論

人物動畫系統(轉)

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

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

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久久久久久宅男| 欧美sm极限捆绑bd| 欧美亚洲一区二区三区| 欧美www视频| 亚洲欧美日韩直播| 欧美一区二区三区在线观看| 欧美午夜精品一区二区三区| 亚洲乱码日产精品bd| 欧美xxx在线观看| 久久久综合网站| 影音先锋一区| 免费人成精品欧美精品| 欧美在线一区二区| 精品91在线| 另类国产ts人妖高潮视频| 欧美一区三区三区高中清蜜桃 | 欧美怡红院视频一区二区三区| 亚洲欧美视频在线观看| 欧美 日韩 国产在线 | 欧美激情精品久久久久久| 亚洲人成人一区二区在线观看| 午夜精品av| 欧美午夜无遮挡| 一本色道久久综合亚洲精品小说 | 亚洲人成人一区二区三区| 久久精品一区二区三区四区| 欧美国产日韩一区| 亚洲三级视频在线观看| 久久国产精品免费一区| 欧美精品九九| 99成人精品| 亚洲国产专区| 欧美日本中文字幕| 99国内精品| 一区二区av| 国产精品久久久久久av下载红粉 | 夜夜嗨av一区二区三区网站四季av| 久久九九热免费视频| 久久久久久一区| 亚洲福利av| 日韩一二在线观看| 国产精品区免费视频| 久久久五月婷婷| 老司机精品久久| 亚洲一级高清| 性欧美video另类hd性玩具| 欧美日韩日韩| 午夜精品999| 久久精品国产亚洲5555| 影音先锋中文字幕一区| 亚洲精品资源美女情侣酒店| 欧美手机在线视频| 麻豆成人在线观看| 欧美国产精品人人做人人爱| 国语自产精品视频在线看一大j8| 久久综合久色欧美综合狠狠| 欧美jjzz| 亚洲区在线播放| 久久蜜臀精品av| 久久国产日韩欧美| 亚洲国产你懂的| 亚洲综合欧美| 亚洲欧美日韩国产中文| 久久手机精品视频| 99精品热视频| 午夜亚洲精品| 欧美日韩一区二区三区高清| 亚洲欧美成人网| 久久精品在线播放| 亚洲欧美在线x视频| 亚洲一区国产一区| 亚洲人www| 日韩视频永久免费| 中日韩美女免费视频网址在线观看| 亚洲激情电影在线| 亚洲免费在线视频一区 二区| 99re6这里只有精品| 欧美午夜精品久久久久久人妖| 一区二区欧美在线观看| 国产在线一区二区三区四区| 亚洲黄色精品| 亚洲精品黄色| 国产精品福利久久久| 久久嫩草精品久久久精品一| 久久久久久9999| 欧美久久电影| 久久伊人一区二区| 另类国产ts人妖高潮视频| 久久久久久9| 久久国产综合精品| 在线视频亚洲| 国产精品外国| 久久精品欧美| 亚洲日本欧美在线| 欧美α欧美αv大片| 亚洲精品乱码久久久久久按摩观| 久久久久99| 亚洲桃花岛网站| 一区二区三区欧美视频| 最新精品在线| 久久久久久久久久久久久久一区 | 久久综合九九| 久久久精品久久久久| 日韩视频免费大全中文字幕| 亚洲美洲欧洲综合国产一区| 国内精品伊人久久久久av影院| 亚洲欧美成aⅴ人在线观看| 欧美肥婆bbw| 欧美成人情趣视频| 亚洲第一精品福利| 久久久久免费视频| 久久久久久久激情视频| 黄色亚洲免费| 欧美自拍偷拍午夜视频| 美日韩免费视频| 黄色工厂这里只有精品| 午夜精品电影| 亚洲永久免费精品| 在线视频亚洲一区| 国产精品私拍pans大尺度在线| 久久久久久午夜| 亚洲第一久久影院| 亚洲精品无人区| 欧美日韩直播| 亚洲视频一二| 性欧美暴力猛交69hd| 国产伦精品一区二区三区免费| 一二三区精品| 日韩亚洲综合在线| 免费在线成人av| 国产欧美日韩不卡| 欧美精品七区| 国产精品国产自产拍高清av| 国产精品捆绑调教| 国产欧美精品| 国产一区二区三区四区| 国产精品日韩一区二区三区| 亚洲精品乱码久久久久久蜜桃91 | 国产精品一二三四区| 亚洲五月六月| 欧美成人中文字幕| 艳妇臀荡乳欲伦亚洲一区| 欧美一区二区黄| 亚洲精品视频在线| 中文有码久久| 国产精品视频专区| 亚洲另类一区二区| 蜜桃精品久久久久久久免费影院| 亚洲激情视频在线观看| 亚洲一区综合| 欧美日韩一本到| 久久蜜臀精品av| 精品99视频| 亚洲一区二区精品视频| 久久国产精品电影| 欧美国产日韩一区二区三区| 一本色道久久加勒比88综合| 国产精品久久久久一区二区三区 | 欧美一区二区三区视频在线观看| 国产一区二区三区久久久| 毛片基地黄久久久久久天堂 | 午夜精品亚洲| 日韩视频在线观看国产| 欧美精品v国产精品v日韩精品| 久久天天躁狠狠躁夜夜爽蜜月 | 久久国产精品黑丝| 亚洲大胆人体视频| 欧美aa在线视频| 亚洲高清视频中文字幕| 日韩亚洲国产欧美| 老司机凹凸av亚洲导航| 午夜国产欧美理论在线播放| 欧美日韩激情网| 红杏aⅴ成人免费视频| 老鸭窝91久久精品色噜噜导演| 国产精品mv在线观看| 老司机精品视频网站| 亚洲欧美日韩成人| 亚洲精品日韩久久| 欧美1区2区| 久久久中精品2020中文| 亚洲欧美中文在线视频| 亚洲精品久久视频| 欧美在线|欧美| 日韩视频免费在线| 亚洲欧美精品中文字幕在线| 亚洲精品国产视频| 99国产精品久久久久久久久久| 国产欧美日韩一区| 久久亚裔精品欧美| 欧美日韩国产区一| 久久午夜国产精品| 老司机凹凸av亚洲导航| 亚洲欧美在线aaa| 欧美成人免费网| 美日韩精品免费| 国产日韩欧美精品一区| 日韩性生活视频| 亚洲一区综合|