linux下collada-dom编译,COLLADA DOM Tutorial
引言
COLLADA是一個開放的標準,最初用于3D軟件數(shù)據(jù)交換,由SCEA發(fā)起,現(xiàn)在則被許多著名廠家支持如Autodesk、XSI等。COLLADA不僅僅可以用于建模工具之間交換數(shù)據(jù)之用,也可以作為場景描述語言用于小規(guī)模的實時渲染。因為COLLADA DOM擁有豐富的內(nèi)容用于表現(xiàn)場景中的各種元素,從多邊形幾何體到攝像機無所不包。我們可以通過COLLADA DOM庫來進行場景文件的讀取與處理操作。
提示
COLLADA DOM的編程方式類似COM
蘇醒
從這里下載COLLADA DOM
準備好你的IDE/編譯器,Windows平臺下推薦Visual Studio 8,LINUX/UNIX平臺下看各路英豪自己的了。
推薦下載安裝包,會省掉不必要的重新編譯的工作。我向來最討厭重新編譯別人的庫,一來是時間寶貴,編譯的時候自己不可能看到任何有意義的東西,二來很多時候編寫這些庫的時候引用了特定版本的其它庫,導(dǎo)致自己還需要去下載其它的庫,非常麻煩。
安裝好后記得在VC的工程目錄加入COLLADA的頭文件和庫文件文件夾路徑,否則什么都找不到。
開始
首先在C++源文件中加入COLLADA DOM所需要的頭文件
#include#include
下面寫代碼,打開一個DAE XML文件。
intmain(intargc,char**argv)
{
DAE*collada_dom=newDAE();//創(chuàng)建一個DOM解析器daeInt?error=collada_dom->load("file:///C:/Test/colladaDocument.dae");//打開一個放在C盤Test文件夾下一個名為colladaDocument.dae的文檔error=collada_com->unload();//關(guān)閉剛才打開的文檔return0;//程序返回}
一切都是很簡單的。載入文檔,獲得一個根指針,而后一切的操作都是從這個指針開始逐級的向下遍歷、轉(zhuǎn)換。為什么load函數(shù)中不是我們所想象的"C:\\Test\\colladaDocument",而是加了個file前綴。COLLADA DOM支持在處理DAE的時候使用URI直接定位到資源,詳細的可以看附帶的文檔。
現(xiàn)在來點復(fù)雜的,讀取一個幾何體。在實際編碼前,我們需要理解一個概念,就是Shape與Instance的區(qū)別。假如場景中有10000個立方體,那么我們其實只需要儲存8個頂點、向量、三角形索引,然后我們指定這10000個立方體各自的變換、Shader參數(shù)就可以了。使用COLLADA DOM處理場景中幾何體的思路就是,先獲得Geometry(也就是我們所知道的Shape),而后獲得Instance。在對unload()的調(diào)用前增加下面一行代碼,
intgeometryElementCount=(int)(collada_dom->getDatabase()->getElementCount(NULL,"geometry",?NULL));
這個時候我們就獲得了幾何體的確切數(shù)目,然后遍歷獲得各自的數(shù)據(jù)。再添加一個循環(huán),
for(intcurrentGeometry=0;currentGeometry
{
domGeometry*thisGeometry=0;
m_dae->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL,"geometry");
domMesh*thisMesh=thisGeometry->getMesh();
}
先不要繼續(xù)添加代碼,先最好定義一種我們的程序要使用的物體格式。比如,可以這樣,
structCObject
{stringm_sName;
size_t?m_iVertexNum;
size_t?m_iNormalNum;float*m_pVertices;float*m_pNormals;
size_t?m_iTriangleNum;
};
我們就可以直接調(diào)用glDrawArrays去繪制這個物體。以后為了提高效率甚至可以把所有頂點都上傳到Vertex Buffer Object中,這樣就不需要每次繪制的時候把頂點、向量、紋理坐標都上傳一遍了。下面繼續(xù)補全代碼,
std::vectorObjectShapes;for(intcurrentGeometry=0;currentGeometry
{
CObject*pShape=newCObject;
domGeometry*thisGeometry=0;
m_dae->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL,"geometry");//逐個的找到每個Geometry?ShapedomMesh*thisMesh=thisGeometry->getMesh();//取得MeshdomListOfFloats?vertexArray=thisMesh->getSource_array()[0]->getFloat_array()->getValue();//取得儲存頂點的數(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;//每個頂點由3個數(shù)字組成pShape->m_iNormalNum=normalArray.getCount()/3;//每個向量也由3個數(shù)字組成printf("%u?%u?%u\n",?pShape->m_iTriangleNum,?pShape->m_iVertexNum,?pShape->m_iNormalNum);//再次打印一下ObjectShapes.push_back(pShape);
}
我們知道從MAYA導(dǎo)出的OBJ格式可以不是三角形,通過COLLADA插件導(dǎo)出的物體也一樣,我們可以選擇三角化或者保持原樣。假如我們不選擇三角化,那么對于一個簡單的CUBE來說,它的表示可能是這樣的,
4?4?4?4?4?4
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
這里vcount的意思是每個POLYGON由多少個頂點向量對組成,列表可以讓大家明白的更容易一些,
Polygon
Vertex Index
Normal Index
0
0 1 3 2
0 1 2 3
1
2 3 5 4
4 5 6 7
也就是說,索引數(shù)值遵照“頂點 向量 頂點 向量”這樣的順序排列,即使有了UV也一樣。
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
三角化后一切看似都變多了,其實原理依舊,
Triangle
Vertex Index
Normal Index
0
0 1 2
0 1 3
1
1 3 2
1 2 3
了解了這個之后,讓我們再次把代碼補全,將所有三角化后幾何體按照順序儲存到數(shù)組里去讓OpenGL直接渲染。
std::vectorObjectShapes;for(intcurrentGeometry=0;currentGeometry
{
CObject*pShape=newCObject;
domGeometry*thisGeometry=0;
m_dae->getDatabase()->getElement((daeElement**)&thisGeometry,currentGeometry,NULL,"geometry");//逐個的找到每個Geometry?ShapedomMesh*thisMesh=thisGeometry->getMesh();//取得MeshdomListOfFloats?vertexArray=thisMesh->getSource_array()[0]->getFloat_array()->getValue();//取得儲存頂點的數(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;//每個頂點由3個數(shù)字組成pShape->m_iNormalNum=normalArray.getCount()/3;//每個向量也由3個數(shù)字組成printf("%u?%u?%u\n",?pShape->m_iTriangleNum,?pShape->m_iVertexNum,?pShape->m_iNormalNum);//再次打印一下pShape->m_pVertices=newfloat[pShape->m_iTriangleNum*3*3];
pShape->m_pNormals=newfloat[pShape->m_iTriangleNum*3*3];
ObjectShapes.push_back(pShape);
size_t?_V[3],_N[3];for(?size_t?i=0;?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);for(inti=0;?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);
在這里可能會有疑問,為什么不使用索引的方式繪制,而是把所有的三角形全部分開,因為導(dǎo)出的場景向量與頂點的數(shù)目、位置都不統(tǒng)一,導(dǎo)致索引“顧此失彼”全然無序,雖然說可以修正,但是那樣代碼量就多了起來,而且無法應(yīng)用OOCSX的方法簡化復(fù)雜幾何體。
關(guān)于調(diào)試方法
COLLADA DOM在操作過程中幾乎都是與指針打交道,在開始不熟悉的情況下頻頻訪問違規(guī)出錯等等是很正常的,只要注意老老實實的調(diào)用getElementName()、getTypeName()、getCount()查看當前操作對象的名稱和元素數(shù)據(jù),而后逐步的找到自己需要的資源。
性能建議
COLLADA DOM的底層使用的是SAX進行XML文件的訪問操作,構(gòu)建于LibXML2庫之上,所以我推薦從DAE文件頭開始依次處理Geometry、Visual Scene等等,減少運行庫在來回搜索的損耗。默認COLLADA DOM是靜態(tài)庫,導(dǎo)致鏈接后的程序著實非常巨大,所以推薦使用動態(tài)鏈接。
總結(jié)
以上是生活随笔為你收集整理的linux下collada-dom编译,COLLADA DOM Tutorial的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux u盘内容乱码,Linux挂载
- 下一篇: linux下中文的wchar转char,