日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Octree(2)

發布時間:2025/3/21 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Octree(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果是儲存面索引的方法,那么就比原來的實現有些復雜,不過原理還是一樣的。

假設所有的物體都是從3DS模型中讀入的,我們首先要把物體的基本的數據結構搞清楚。

struct tFace //面

{

???? int vertIndex[3];?????????? // 三個頂點

???? int coordIndex[3];????????? // 頂點的紋理坐標

};

struct t3DObject //物體

{

???? int? numOfVerts;??????????? // 頂點總數

???? int? numOfFaces;??????????? // 面的數目

???? int? numTexVertex;????????? // 紋理坐標的數目

???? int? materialID;??????????? // 紋理ID, 通過引用紋理數組的索引引用

???? bool bHasTexture;?????????? //

???? char strName[255];????????? // 物體的名字

???? UINT????? *pIndices;??????? // 物體的面索引,用于vertex arrays

???? CVector3? *pVerts;????????? // 頂點的指針

???? CVector3? *pNormals;??????? // 物體的法線

???? tVector2? *pTexVerts;?????? // 紋理的UV 坐標

???? tFace *pFaces;????????????? // 面

}

?

struct tFaceList

{

???? vector<bool> pFaceList;

???? int totalFaceCount;

};

和前面一樣,建立八叉樹前先要獲取世界的長寬高,然后把它作為根節點的信息傳遞給CreateNode函數。

由于我們讀入的模型中可能包括很多物體,所以我們需要改變一下,把原來用于保存頂點的vector<bool>改成 vector<tFaceList>,其實也就多了一行代碼。

vector<tFaceList> pList1(pWorld->numOfObjects);???????? // TOP_LEFT_FRONT node

???????? vector<tFaceList> pList2(pWorld->numOfObjects);???????? // TOP_LEFT_BACK node

???????? vector<tFaceList> pList3(pWorld->numOfObjects);???????? // TOP_RIGHT_BACK node????? ???? vector<tFaceList> pList4(pWorld->numOfObjects);??????? // TOP_RIGHT_FRONT node

???????? vector<tFaceList> pList5(pWorld->numOfObjects);???????? // BOTTOM_LEFT_FRONT node

???????? vector<tFaceList> pList6(pWorld->numOfObjects);???????? // BOTTOM_LEFT_BACK node

???????? vector<tFaceList> pList7(pWorld->numOfObjects);???????? // BOTTOM_RIGHT_BACK node

???? vector<tFaceList> pList8(pWorld->numOfObjects);??? ??? // BOTTOM_RIGHT_FRONT node

現在我們需要檢測每個物體的每個三角形位于哪個位置,和前面的例子,這只是換湯不換藥:

???????? for(int i = 0; i < pWorld->numOfObjects; i++) //遍歷世界的每一個物體

???????? {

????????????? t3DObject *pObject = &(pWorld->pObject[i]); //當前物體

????????????? //調整容器的容量

????????????? pList1[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList2[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList3[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList4[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList5[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList6[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList7[i].pFaceList.resize(pObject->numOfFaces);

????????????? pList8[i].pFaceList.resize(pObject->numOfFaces);

?

????????????? for(int j = 0; j < pObject->numOfFaces; j++)//遍歷該物體中所有的三角形

????????????? {

?????????????????? for(int whichVertex = 0; whichVertex < 3; whichVertex++)

?????????????????? {

?????????????????????? // 當前頂點

?????????????????????? CVector3 vPoint = pObject->pVerts[pObject->pFaces[j].vertIndex[whichVertex]];

?

?????????????????????? // 看是否在 TOP LEFT FRONT node

?????????????????????? if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) )

???? ?????????????????????? pList1[i].pFaceList[j] = true;

?

?????????????????????? //看是否在TOP LEFT BACK

?????????????????????? if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) )

??????????????????????????? pList2[i].pFaceList[j] = true;

?

?????????????????????? //看是否在TOP RIGHT BACK

?????????????????????? if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) )

??????????????????????????? pList3[i].pFaceList[j] = true;

?

?????????????????????? //看是否在TOP RIGHT FRONT

?????????????????????? if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) )

??????????????????????????? pList4[i].pFaceList[j] = true;

?

?????????????????????? //看是否在BOTTOM LEFT FRONT

?????????????????????? if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) )

??????????????????????????? pList5[i].pFaceList[j] = true;

?

?????????????????????? //看是否在BOTTOM LEFT BACK

?????????????????????? if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) )

??????????????????????????? pList6[i].pFaceList[j] = true;

?

?????????????????????? //看是否在BOTTOM RIGHT BACK

?????????????????????? if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) )

??????????????????????????? pList7[i].pFaceList[j] = true;

?

?????????????????????? //看是否在BOTTOM RIGHT FRONT

?????????????????????? if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) )

??????????????????????????? pList8[i].pFaceList[j] = true;

?????????????????? }

????????????? }???

?

????????????? // 接下來我們要把每個小區域內部的三角形的數目數出來

?????????????

????????????? pList1[i].totalFaceCount = 0;??????? pList2[i].totalFaceCount = 0;

????????????? pList3[i].totalFaceCount = 0;??????? pList4[i].totalFaceCount = 0;

????????????? pList5[i].totalFaceCount = 0;??????? pList6[i].totalFaceCount = 0;

????????????? pList7[i].totalFaceCount = 0;??????? pList8[i].totalFaceCount = 0;

???????? }

知道了三角形的數目我們就可以調用CreateNewNode了:

???????? for(i = 0; i < pWorld->numOfObjects; i++)

???????? {

????????????? //便利所有物體的三角形

????????????? for(int j = 0; j < pWorld->pObject[i].numOfFaces; j++)

????????????? {

????????????? ???? if(pList1[i].pFaceList[j])? { pList1[i].totalFaceCount++; triCount1++; }

?????????????????? if(pList2[i].pFaceList[j])? { pList2[i].totalFaceCount++; triCount2++; }

?????????????????? if(pList3[i].pFaceList[j])? { pList3[i].totalFaceCount++; triCount3++; }

?????????????????? if(pList4[i].pFaceList[j])? { pList4[i].totalFaceCount++; triCount4++; }

?????????????????? if(pList5[i].pFaceList[j])? { pList5[i].totalFaceCount++; triCount5++; }

?????????????????? if(pList6[i].pFaceList[j])? { pList6[i].totalFaceCount++; triCount6++; }

?????????????????? if(pList7[i].pFaceList[j])? { pList7[i].totalFaceCount++; triCount7++; }

?????????????????? if(pList8[i].pFaceList[j])? { pList8[i].totalFaceCount++; triCount8++; }

????????????? }

???????? }

?

???????? CreateNewNode(pWorld, pList1, triCount1, vCenter, width, TOP_LEFT_FRONT);

???????? CreateNewNode(pWorld, pList2, triCount2, vCenter, width, TOP_LEFT_BACK);

???????? CreateNewNode(pWorld, pList3, triCount3, vCenter, width, TOP_RIGHT_BACK);

???????? CreateNewNode(pWorld, pList4, triCount4, vCenter, width, TOP_RIGHT_FRONT);

???????? CreateNewNode(pWorld, pList5, triCount5, vCenter, width, BOTTOM_LEFT_FRONT);

???????? CreateNewNode(pWorld, pList6, triCount6, vCenter, width, BOTTOM_LEFT_BACK);

???????? CreateNewNode(pWorld, pList7, triCount7, vCenter, width, BOTTOM_RIGHT_BACK);

???? CreateNewNode(pWorld, pList8, triCount8, vCenter, width, BOTTOM_RIGHT_FRONT);

現在CreateNewNode有了較大的改變,參數還是一樣,在調用CreateNode之前,我們需要做一些工作,這些工作是要確定面列表,到最后把它傳給顯示列表:

?

void COctree::CreateNewNode(t3DModel *pWorld, vector<tFaceList> pList, int triangleCount,

?????????????????????? ? ?? ????CVector3 vCenter, float width,???????????? ?? int nodeID)

{

???? if(!triangleCount) return;

???? //臨時變量,并初始化,保存葉結點中所有的物體

???? t3DModel *pTempWorld = new t3DModel;

???? memset(pTempWorld, 0, sizeof(t3DModel));

???? pTempWorld->numOfObjects = pWorld->numOfObjects;

????

???? // 遍歷由參數傳遞進來的分區的所有物體

???? for(int i = 0; i < pWorld->numOfObjects; i++)

???? {

???????? t3DObject *pObject = &(pWorld->pObject[i]);

???????? // Create a new object, initialize it, then add it to our temp partition

???????? t3DObject newObject;

???????? memset(&newObject, 0, sizeof(t3DObject));

???????? pTempWorld->pObject.push_back(newObject);

?

???????? // Assign the new node's face count, material ID, texture boolean and

???????? // vertices to the new object.? Notice that it's not that pObject's face

???????? // count, but the pList's.? Also, we are just assigning the pointer to the

???????? // vertices, not copying them.

???????? pTempWorld->pObject[i].numOfFaces? = pList[i].totalFaceCount;

???????? pTempWorld->pObject[i].materialID? = pObject->materialID;

???????? pTempWorld->pObject[i].bHasTexture = pObject->bHasTexture;

???????? pTempWorld->pObject[i].pVerts????? = pObject->pVerts;

?

???????? pTempWorld->pObject[i].pFaces = new tFace [pTempWorld->pObject[i].numOfFaces];//建立空的面列表

???????? int index = 0;

???????? // 遍歷所有的面,如果在節點內,就保存面到面列表

???????? for(int j = 0; j < pObject->numOfFaces; j++)

???????? {

????????????? if(pList[i].pFaceList[j])??

????????????? {

?????????????????? pTempWorld->pObject[i].pFaces[index] = pObject->pFaces[j];

?????????????????? index++;

????????????? }

???????? }

???? }

這里我們做的所有的工作都是為了這個pTempWorld,這是一個臨時變量,保存了當前分區的所有物體,接下來要做的就是為新的節點分配內存

?

?

m_pOctreeNodes[nodeID] = new COctree;

???? CVector3 vNodeCenter = GetNewNodeCenter(vCenter, width, nodeID);

???? g_CurrentSubdivision++;

???? m_pOctreeNodes[nodeID]->CreateNode(pTempWorld, triangleCount, vNodeCenter, width / 2);

g_CurrentSubdivision--;

最后一步釋放臨時變量:

// 遍歷臨時變量的所有物體,釋放前面創建的面列表

???? for(i = 0; i < pWorld->numOfObjects; i++)

???? {

???????? if(pTempWorld->pObject[i].pFaces)

????????????? delete [] pTempWorld->pObject[i].pFaces;

???? }

???? delete pTempWorld;

?

到現在為止我們還沒有把面索引的信息拷貝給葉結點,這個工作的思想是,對葉結點的分區的每一個物體遍歷,把物體的每一個面(三角形)的三個頂點按順序儲存在一個數組里面,每一個物體都持有這樣的一個數組

AssignTrianglesToNode(t3DModel *pWorld, int numberOfTriangles)

{

???? //我們把pWorld分區的信息傳遞給面列表,它保存了我們渲染需要的面索引,由于我們使用頂點數組的緣故我們不能使用tFace結構作為索引的值,我們需要建立這樣一個數組,他連續的保存了面索引。這就是pIndices數組,他的型別是無符號整數,必須是無符號整數。

???? m_bSubDivided = false;

???? m_TriangleCount = numberOfTriangles;

???? m_pWorld = new t3DModel;

???? memset(m_pWorld, 0, sizeof(t3DModel));

?

???? // Assign the number of objects to our face index list

???? m_pWorld->numOfObjects = pWorld->numOfObjects;

???? // Go through all of the objects in the partition that was passed in

???? for(int i = 0; i < m_pWorld->numOfObjects; i++)

???? {

???????? // Create a pointer to the current object

???????? t3DObject *pObject = &(pWorld->pObject[i]);

?

???????? // Create and init a new object to hold the face index information

???????? t3DObject newObject;

???????? memset(&newObject, 0, sizeof(t3DObject));

?

???????? // If this object has face information, add it's index to our object index list

???????? if(pObject->numOfFaces)

????????????? AddObjectIndexToList(i); //為每個物體建立索引

?

???????? // Add our new object to our face index list

???????? m_pWorld->pObject.push_back(newObject);

???????? int numOfFaces = pObject->numOfFaces;

???????? m_pWorld->pObject[i].numOfFaces = numOfFaces;

?

???????? // 為面索引分配空間? pIndices將傳遞給頂點數組.?

???????? m_pWorld->pObject[i].pFaces = new tFace [numOfFaces];

???????? m_pWorld->pObject[i].pIndices = new UINT [numOfFaces * 3];

?

???????? // 初始化

???????? memset(m_pWorld->pObject[i].pIndices, 0, sizeof(UINT) * numOfFaces * 3);

???????? // 拷貝面信息

???????? memcpy(m_pWorld->pObject[i].pFaces, pObject->pFaces, sizeof(tFace) * numOfFaces);

?

???????? // 由于使用頂點數組,我們需要一個儲存了所有的面信息的數組,這將作為參數傳遞給

???????? // glDrawElements().?

???????? // Go through all the faces and assign them in a row to our pIndices array

???????? for(int j = 0; j < numOfFaces * 3; j += 3)

???????? {

???? m_pWorld->pObject[i].pIndices[j]???? = m_pWorld->pObject[i].pFaces[j / 3].vertIndex[0];

???? m_pWorld->pObject[i].pIndices[j + 1] = m_pWorld->pObject[i].pFaces[j / 3].vertIndex[1];

???? m_pWorld->pObject[i].pIndices[j + 2] = m_pWorld->pObject[i].pFaces[j / 3].vertIndex[2];

???????? }

?

???????? // 我們只需要使用pIndcies,所以釋放不需要的變量

???????? delete [] m_pWorld->pObject[i].pFaces;

???????? m_pWorld->pObject[i].pFaces = NULL;

???? }

???? m_DisplayListID = g_EndNodeCount;

???? g_EndNodeCount++;

}

到此,每個物體的面索引就都儲存在每個物體內部的pIndices數組內,這個數組最終將作為頂點數組渲染的對象。

為了使程序看上去完整,順帶把顯示列表也提一下,我們將為每個葉結點分配一個顯示列表的ID,每個葉結點中的物體保存了pIndices數組,在構造顯示列表的時候用頂點數組來實現立即繪制:

CreateDisplayList(COctree *pNode, t3DModel *pRootWorld, int displayListOffset)

{

???? if(!pNode) return;

???? // 檢查是不是葉結點,如果不是就深入

???? if(pNode->IsSubDivided())

???? {

???????? // Recurse down to each one of the children until we reach the end nodes

CreateDisplayList(pNode->m_pOctreeNodes[TOP_LEFT_FRONT],???? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[TOP_LEFT_BACK],????? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[TOP_RIGHT_BACK],???? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[TOP_RIGHT_FRONT],??? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[BOTTOM_LEFT_FRONT],? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[BOTTOM_LEFT_BACK],?? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[BOTTOM_RIGHT_BACK],? pRootWorld, displayListOffset);

CreateDisplayList(pNode->m_pOctreeNodes[BOTTOM_RIGHT_FRONT],pRootWorld, displayListOffset);

???? }

???? else

???? {

???????? if(!pNode->m_pWorld) return;

???????? // 顯示列表的ID偏移量

???????? pNode->m_DisplayListID += displayListOffset;

//********************************建立顯示列表開始*****************************************

???????? // Start the display list and assign it to the end nodes ID

???????? glNewList(pNode->m_DisplayListID,GL_COMPILE);

???????? // 儲存物體數量

???????? int counter = 0;

???????? // Store the object count and material count in some local variables for optimization

???????? int objectCount = pNode->m_pObjectList.size(); //物體數量

???????? int materialCount = pRootWorld->pMaterials.size(); //材質數量

?

???????? // 遍歷所有物體

???????? while(counter < objectCount)

???????? {

????????????? // Get the first object index into our root world

????????????? // 取得整個世界中第一個物體的索引

????????????? int i = pNode->m_pObjectList[counter];

?

????????????? // Store pointers to the current face list and the root object

????????????? // that holds all the data (verts, texture coordinates, normals, etc..)

????????????? // 保存指向現在的面列表的指針和整個世界的指針,他們包含了所有的數據

????????????? t3DObject *pObject???? = &pNode->m_pWorld->pObject[i];

????????????? t3DObject *pRootObject = &pRootWorld->pObject[i];

?

????????????? // Check to see if this object has a texture map, if so, bind the texture to it.

????????????? // 檢查當前物體是否包括貼圖,如果有,邦定貼圖

????????????? if(pRootObject->bHasTexture)

????????????? {

?????????????????? // Turn on texture mapping and turn off color

?????????????????? glEnable(GL_TEXTURE_2D);

?????????????????? // Reset the color to normal again

?????????????????? glColor3ub(255, 255, 255);

?????????????????? glBindTexture(GL_TEXTURE_2D, g_Texture[pRootObject->materialID]);

????????????? }

????????????? else

????????????? {

?????????????????? glDisable(GL_TEXTURE_2D);

?????????????????? glColor3ub(255, 255, 255);

????????????? }

?

????????????? // Check to see if there is a valid material assigned to this object

????????????? // 檢查材質

????????????? if(materialCount && pRootObject->materialID >= 0)

????????????? {

?????????????????? // Get and set the color that the object is, since it must not have a texture

?????????????????? BYTE *pColor = pRootWorld->pMaterials[pRootObject->materialID].color;

?

?????????????????? // Assign the current color to this model

?????????????????? glColor3ub(pColor[0], pColor[1], pColor[2]);

????????????? }

????????????? // Make sure we have texture coordinates to render

????????????? // 是否有紋理坐標,如果有,需要啟用紋理坐標數組

????????????? if(pRootObject->pTexVerts)

????????????? {

?????????????????? // Turn on the texture coordinate state

?????????????????? glEnableClientState(GL_TEXTURE_COORD_ARRAY);

?????????????????? glTexCoordPointer(2, GL_FLOAT, 0, pRootObject->pTexVerts);

????????????? }

?

????????????? // Make sure we have vertices to render

????????????? // 確定是否有頂點等待渲染,如果有建立頂點數組

????????????? if(pRootObject->pVerts)

????????????? {

?????????????????? glEnableClientState(GL_VERTEX_ARRAY);

?????????????????? glVertexPointer(3, GL_FLOAT, 0, pRootObject->pVerts);? // pRootObject->pVerts指向頂點數組

????????????? }

?

????????????? // Make sure we have normals to render

????????????? // 確定是否有法線需要渲染,如果有建立法線數組

????????????? if(pRootObject->pNormals)

????????????? {

?????????????????? // Turn on the normals state

?????????????????? glEnableClientState(GL_NORMAL_ARRAY);

?????????????????? glNormalPointer(GL_FLOAT, 0, pRootObject->pNormals);

????????????? }

????????????? // 注意,這里的pObject是? &pNode->m_pWorld->pObject[i];

????????????? glDrawElements(GL_TRIANGLES,??? pObject->numOfFaces * 3,

??????????????????????????? ?? GL_UNSIGNED_INT, pObject->pIndices);

????????????? counter++;

???????? }

?

???????? // End the display list for this ID

???????? glEndList();

//********************************建立顯示列表結束****************************************

?

???? }

}

最后一步,把八叉樹畫出來,思想也很簡單,首先深入到葉結點,然后執行顯示列表,當然,在最開始還是要判斷以下視景體所在的位置:

DrawOctree(COctree *pNode, t3DModel *pRootWorld)

{

???? if(!pNode) return;

???? if(!g_Frustum.CubeInFrustum(pNode->m_vCenter.x, pNode->m_vCenter.y,

???????????????????????????????????? pNode->m_vCenter.z, pNode->m_Width / 2) )

???? {

???????? return;

???? }

???? if(pNode->IsSubDivided())

???? {

???????? // Recurse to the bottom of these nodes and draw the end node's vertices

???????? // Like creating the octree, we need to recurse through each of the 8 nodes.

???????? DrawOctree(pNode->m_pOctreeNodes[TOP_LEFT_FRONT],?????? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[TOP_LEFT_BACK],??????? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[TOP_RIGHT_BACK],?????? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[TOP_RIGHT_FRONT],????? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[BOTTOM_LEFT_FRONT],??? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[BOTTOM_LEFT_BACK],???? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[BOTTOM_RIGHT_BACK],??? pRootWorld);

???????? DrawOctree(pNode->m_pOctreeNodes[BOTTOM_RIGHT_FRONT],?? pRootWorld);

???? }

???? else

???? {

???????? // Increase the amount of nodes in our viewing frustum (camera's view)

???????? g_TotalNodesDrawn++;

???????? // Make sure we have valid data assigned to this node

???????? if(!pNode->m_pWorld) return;

???????? // Call the list with our end node's display list ID

???????? glCallList(pNode->m_DisplayListID);

?

???? }

}

轉載于:https://www.cnblogs.com/sssa2000/archive/2005/09/16/238306.html

總結

以上是生活随笔為你收集整理的Octree(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。