• <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>

            COLLADA DOM Tutorial

            http://www.cnblogs.com/Jedimaster/archive/2007/12/01/979256.html

            引言

              COLLADA是一個(gè)開放的標(biāo)準(zhǔn),最初用于3D軟件數(shù)據(jù)交換,由SCEA發(fā)起,現(xiàn)在則被許多著名廠家支持如Autodesk、XSI等。COLLADA不僅僅可以用于建模工具之間交換數(shù)據(jù)之用,也可以作為場景描述語言用于小規(guī)模的實(shí)時(shí)渲染。因?yàn)镃OLLADA DOM擁有豐富的內(nèi)容用于表現(xiàn)場景中的各種元素,從多邊形幾何體到攝像機(jī)無所不包。我們可以通過COLLADA DOM庫來進(jìn)行場景文件的讀取與處理操作。

            提示

              COLLADA DOM的編程方式類似COM

            蘇醒

              從這里下載COLLADA DOM

              http://sourceforge.net/projects/collada-dom/

              準(zhǔn)備好你的IDE/編譯器,Windows平臺下推薦Visual Studio 8,LINUX/UNIX平臺下看各路英豪自己的了。

              推薦下載安裝包,會省掉不必要的重新編譯的工作。我向來最討厭重新編譯別人的庫,一來是時(shí)間寶貴,編譯的時(shí)候自己不可能看到任何有意義的東西,二來很多時(shí)候編寫這些庫的時(shí)候引用了特定版本的其它庫,導(dǎo)致自己還需要去下載其它的庫,非常麻煩。

              安裝好后記得在VC的工程目錄加入COLLADA的頭文件和庫文件文件夾路徑,否則什么都找不到。

            開始

              首先在C++源文件中加入COLLADA DOM所需要的頭文件

            #include <dae.h>
            #include 
            <dom/domCOLLADA.h>
              下面寫代碼,打開一個(gè)DAE XML文件。
            int main(int argc, char** argv)
            {
                DAE 
            *collada_dom = new DAE();//創(chuàng)建一個(gè)DOM解析器
                daeInt error = collada_dom->load("file:///C:/Test/colladaDocument.dae");//打開一個(gè)放在C盤Test文件夾下一個(gè)名為colladaDocument.dae的文檔
                error = collada_com->unload();//關(guān)閉剛才打開的文檔
                return 0;//程序返回
            }
            一切都是很簡單的。載入文檔,獲得一個(gè)根指針,而后一切的操作都是從這個(gè)指針開始逐級的向下遍歷、轉(zhuǎn)換。為什么load函數(shù)中不是我們所想象的"C:\\Test\\colladaDocument",而是加了個(gè)file前綴。COLLADA DOM支持在處理DAE的時(shí)候使用URI直接定位到資源,詳細(xì)的可以看附帶的文檔。

              現(xiàn)在來點(diǎn)復(fù)雜的,讀取一個(gè)幾何體。在實(shí)際編碼前,我們需要理解一個(gè)概念,就是Shape與Instance的區(qū)別。假如場景中有10000個(gè)立方體,那么我們其實(shí)只需要儲存8個(gè)頂點(diǎn)、向量、三角形索引,然后我們指定這10000個(gè)立方體各自的變換、Shader參數(shù)就可以了。使用COLLADA DOM處理場景中幾何體的思路就是,先獲得Geometry(也就是我們所知道的Shape),而后獲得Instance。在對unload()的調(diào)用前增加下面一行代碼,

            int geometryElementCount = (int)(collada_dom->getDatabase()->getElementCount(NULL, "geometry", NULL));

              這個(gè)時(shí)候我們就獲得了幾何體的確切數(shù)目,然后遍歷獲得各自的數(shù)據(jù)。再添加一個(gè)循環(huán),

            for(int currentGeometry=0;currentGeometry<geometryElementCount;currentGeometry++)
            {
                domGeometry 
            *thisGeometry = 0;
                m_dae
            ->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL, "geometry");
                domMesh 
            *thisMesh = thisGeometry->getMesh();
            }

              先不要繼續(xù)添加代碼,先最好定義一種我們的程序要使用的物體格式。比如,可以這樣,

            struct CObject
            {
                string m_sName;
                size_t m_iVertexNum;
                size_t m_iNormalNum;
                float* m_pVertices;
                float* m_pNormals;
                size_t m_iTriangleNum;
            };

              我們就可以直接調(diào)用glDrawArrays去繪制這個(gè)物體。以后為了提高效率甚至可以把所有頂點(diǎn)都上傳到Vertex Buffer Object中,這樣就不需要每次繪制的時(shí)候把頂點(diǎn)、向量、紋理坐標(biāo)都上傳一遍了。下面繼續(xù)補(bǔ)全代碼,

            std::vector<CObject*> ObjectShapes;
            for(int currentGeometry=0;currentGeometry<geometryElementCount;currentGeometry++)
            {
                CObject
            * pShape = new CObject;
                domGeometry 
            *thisGeometry = 0;
                m_dae
            ->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL, "geometry"); //逐個(gè)的找到每個(gè)Geometry Shape
                domMesh *thisMesh = thisGeometry->getMesh();//取得Mesh
                domListOfFloats vertexArray = thisMesh->getSource_array()[0]->getFloat_array()->getValue();//取得儲存頂點(diǎn)的數(shù)組
                domListOfFloats normalArray = thisMesh->getSource_array()[1]->getFloat_array()->getValue();//取得儲存向量的數(shù)組
                domListOfUInts indexArray = thisMesh->getTriangles_array()[0]->getP()->getValue();//取得三角形索引
                pShape->m_iTriangleNum = indexArray.getCount() / 6;//看下面的解釋
                pShape->m_iVertexNum = vertexArray.getCount() / 3;//每個(gè)頂點(diǎn)由3個(gè)數(shù)字組成
                pShape->m_iNormalNum = normalArray.getCount() / 3;//每個(gè)向量也由3個(gè)數(shù)字組成
                printf("%u %u %u\n", pShape->m_iTriangleNum, pShape->m_iVertexNum, pShape->m_iNormalNum);//再次打印一下
                ObjectShapes.push_back(pShape);
            }

            Exporter

             

              我們知道從MAYA導(dǎo)出的OBJ格式可以不是三角形,通過COLLADA插件導(dǎo)出的物體也一樣,我們可以選擇三角化或者保持原樣。假如我們不選擇三角化,那么對于一個(gè)簡單的CUBE來說,它的表示可能是這樣的,

            <polylist material="initialShadingGroup" count="6">
              
            <input semantic="VERTEX" source="#pCubeShape1-vertices" offset="0"/>
              
            <input semantic="NORMAL" source="#pCubeShape1-normals" offset="1"/>
              
            <vcount>4 4 4 4 4 4</vcount>
              
            <p>0 0 1 1 3 2 2 3 2 4 3 5 5 6 4 7 4 8 5 9 7 10 6 11 6 12 7 13 1 14 0 15 1 16 7 17 5 18 3 19 6 20 0 21 2 22 4 23</p>
            </polylist>

              這里vcount的意思是每個(gè)POLYGON由多少個(gè)頂點(diǎn)向量對組成,列表可以讓大家明白的更容易一些,

            Polygon Vertex Index Normal Index
            0 0 1 3 2 0 1 2 3
            1 2 3 5 4 4 5 6 7

              也就是說,索引數(shù)值遵照“頂點(diǎn) 向量 頂點(diǎn) 向量”這樣的順序排列,即使有了UV也一樣。

            <triangles material="initialShadingGroup" count="12">
              
            <input semantic="VERTEX" source="#pCubeShape1-vertices" offset="0"/>
              
            <input semantic="NORMAL" source="#pCubeShape1-normals" offset="1"/>
              
            <p>0 0 1 1 2 3 1 1 3 2 2 3 2 4 3 5 4 7 3 5 5 6 4 7 4 8 5 9 6 11 5 9 7 10 6 11 6 12 7 13 0 15 7 13 1 14 0 15 1 16 7 17 3 19 7 17 5 18 3 19 6 20 0 21 4 23 0 21 2 22 4 23</p>
            </triangles>

             

              三角化后一切看似都變多了,其實(shí)原理依舊,

            Triangle Vertex Index Normal Index
            0 0 1 2 0 1 3
            1 1 3 2 1 2 3

              了解了這個(gè)之后,讓我們再次把代碼補(bǔ)全,將所有三角化后幾何體按照順序儲存到數(shù)組里去讓OpenGL直接渲染。

            std::vector<CObject*> ObjectShapes;

            for(int currentGeometry=0;currentGeometry<geometryElementCount;currentGeometry++)
            {
                CObject
            * pShape = new CObject;
                domGeometry 
            *thisGeometry = 0;
                m_dae
            ->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL, "geometry"); //逐個(gè)的找到每個(gè)Geometry Shape
                domMesh 
            *thisMesh = thisGeometry->getMesh();//取得Mesh
                domListOfFloats vertexArray 
            = thisMesh->getSource_array()[0]->getFloat_array()->getValue();//取得儲存頂點(diǎn)的數(shù)組
                domListOfFloats normalArray 
            = thisMesh->getSource_array()[1]->getFloat_array()->getValue();//取得儲存向量的數(shù)組
                domListOfUInts indexArray 
            = thisMesh->getTriangles_array()[0]->getP()->getValue();//取得三角形索引

                pShape
            ->m_iTriangleNum = indexArray.getCount() / 6;//看下面的解釋
                pShape->m_iVertexNum = vertexArray.getCount() / 3;//每個(gè)頂點(diǎn)由3個(gè)數(shù)字組成
                pShape->m_iNormalNum = normalArray.getCount() / 3;//每個(gè)向量也由3個(gè)數(shù)字組成
                printf("%u %u %u\n", pShape->m_iTriangleNum, pShape->m_iVertexNum, pShape->m_iNormalNum);//再次打印一下
                pShape->m_pVertices = new float[pShape->m_iTriangleNum*3*3];
                pShape
            ->m_pNormals = new float[pShape->m_iTriangleNum*3*3];

                ObjectShapes.push_back(pShape);

                size_t _V[
            3],_N[3];
               
            for( size_t i = 0; i < cube.m_iTriangleNum; i++ ){
                    size_t offset 
            = i*6;
                    _V[
            0= indexArray.get(offset+0);
                    _N[
            0= indexArray.get(offset+1);
                    _V[
            1= indexArray.get(offset+2);
                    _N[
            1= indexArray.get(offset+3);
                    _V[
            2= indexArray.get(offset+4);
                    _N[
            2= indexArray.get(offset+5);

                    offset 
            = i*3*3;
                    for( size_t j=0; j < 3; j++ ){
                        pShape
            ->m_pVertices[offset+0= vertexArray.get(_V[0]*3+0);
                        pShape
            ->m_pVertices[offset+1= vertexArray.get(_V[0]*3+1);
                        pShape
            ->m_pVertices[offset+2= vertexArray.get(_V[0]*3+2);
                        pShape
            ->m_pVertices[offset+3= vertexArray.get(_V[1]*3+0);
                        pShape
            ->m_pVertices[offset+4= vertexArray.get(_V[1]*3+1);
                        pShape
            ->m_pVertices[offset+5= vertexArray.get(_V[1]*3+2);
                        pShape
            ->m_pVertices[offset+6= vertexArray.get(_V[2]*3+0);
                        pShape
            ->m_pVertices[offset+7= vertexArray.get(_V[2]*3+1);
                        pShape
            ->m_pVertices[offset+8= vertexArray.get(_V[2]*3+2);
                        pShape
            ->m_pNormals[offset+0= normalArray.get(_N[0]*3+0);
                        pShape
            ->m_pNormals[offset+1= normalArray.get(_N[0]*3+1);
                        pShape
            ->m_pNormals[offset+2= normalArray.get(_N[0]*3+2);
                        pShape
            ->m_pNormals[offset+3= normalArray.get(_N[1]*3+0);
                        pShape
            ->m_pNormals[offset+4= normalArray.get(_N[1]*3+1);
                        pShape
            ->m_pNormals[offset+5= normalArray.get(_N[1]*3+2);
                        pShape
            ->m_pNormals[offset+6= normalArray.get(_N[2]*3+0);
                        pShape
            ->m_pNormals[offset+7= normalArray.get(_N[2]*3+1);
                        pShape
            ->m_pNormals[offset+8= normalArray.get(_N[2]*3+2);
                    }
                }
            }

              這樣,我們就可以使用OpenGL渲染了,

            glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_NORMAL_ARRAY);
            forint i=0; i<ObjectShapes.size(); i++ ){
                glVertexPointer(
            3,GL_FLOAT,0,ObjectShapes[i]->m_pVertices);
                glNormalPointer(GL_FLOAT,
            0,ObjectShapes[i]->m_pNormals);
                glDrawArrays(GL_TRIANGLES,
            0,ObjectShapes[i]->m_iTriangleNum*3);
            }
            glDisableClientState(GL_VERTEX_ARRAY);
            glDisableClientState(GL_NORMAL_ARRAY);

              在這里可能會有疑問,為什么不使用索引的方式繪制,而是把所有的三角形全部分開,因?yàn)閷?dǎo)出的場景向量與頂點(diǎn)的數(shù)目、位置都不統(tǒng)一,導(dǎo)致索引“顧此失彼”全然無序,雖然說可以修正,但是那樣代碼量就多了起來,而且無法應(yīng)用OOCSX的方法簡化復(fù)雜幾何體。

            關(guān)于調(diào)試方法

              COLLADA DOM在操作過程中幾乎都是與指針打交道,在開始不熟悉的情況下頻頻訪問違規(guī)出錯(cuò)等等是很正常的,只要注意老老實(shí)實(shí)的調(diào)用getElementName()、getTypeName()、getCount()查看當(dāng)前操作對象的名稱和元素?cái)?shù)據(jù),而后逐步的找到自己需要的資源。

            性能建議

              COLLADA DOM的底層使用的是SAX進(jìn)行XML文件的訪問操作,構(gòu)建于LibXML2庫之上,所以我推薦從DAE文件頭開始依次處理Geometry、Visual Scene等等,減少運(yùn)行庫在來回搜索的損耗。默認(rèn)COLLADA DOM是靜態(tài)庫,導(dǎo)致鏈接后的程序著實(shí)非常巨大,所以推薦使用動(dòng)態(tài)鏈接。

            posted on 2008-08-28 13:39 zmj 閱讀(1092) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            人妻无码久久一区二区三区免费| 人妻无码久久一区二区三区免费| 精品999久久久久久中文字幕| 精品久久久久久中文字幕人妻最新| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 久久丫精品国产亚洲av不卡| 久久久久久九九99精品| 国内精品久久九九国产精品| 狠狠久久综合伊人不卡| 久久国内免费视频| 久久一日本道色综合久久| 91精品日韩人妻无码久久不卡| 久久免费观看视频| 一本色道久久88精品综合| 久久精品无码一区二区三区| 久久91精品国产91| 久久九九亚洲精品| 久久久久久久久久免免费精品| 很黄很污的网站久久mimi色 | 亚洲精品乱码久久久久久自慰| 久久91精品国产91久久小草| 中文字幕久久亚洲一区| 51久久夜色精品国产| 色诱久久久久综合网ywww| 久久久91人妻无码精品蜜桃HD| 色婷婷综合久久久久中文| 亚洲色欲久久久久综合网| 久久免费精品视频| 久久久久高潮毛片免费全部播放| 久久人人爽人爽人人爽av| 国产激情久久久久影院| 99久久精品午夜一区二区| 婷婷综合久久中文字幕蜜桃三电影 | 99久久香蕉国产线看观香| 久久精品国产色蜜蜜麻豆| 婷婷久久精品国产| 99久久久久| 日批日出水久久亚洲精品tv| 久久久久久亚洲精品无码| 久久久91人妻无码精品蜜桃HD| 久久夜色精品国产亚洲av|