void COctree::CreateNode(CVector3 *pVertices, int numberOfVerts, CVector3 vCenter, float width) { // This is our main function that creates the octree. We will recurse through // this function until we finish subdividing. Either this will be because we // subdivided too many levels or we divided all of the triangles up. // Create a variable to hold the number of triangles int numberOfTriangles = numberOfVerts / 3; // Initialize this node's center point. Now we know the center of this node. m_vCenter = vCenter; // Initialize this nodes cube width. Now we know the width of this current node. m_Width = width; // Add the current node to our debug rectangle list so we can visualize it. // We can now see this node visually as a cube when we render the rectangles. // Since it's a cube we pass in the width for width, height and depth. g_Debug.AddDebugRectangle(vCenter, width, width, width); // Check if we have too many triangles in this node and we haven't subdivided // above our max subdivisions. If so, then we need to break this node into // 8 more nodes (hence the word OCTree). Both must be true to divide this node. if( (numberOfTriangles > g_MaxTriangles) && (g_CurrentSubdivision < g_MaxSubdivisions) ) { // Since we need to subdivide more we set the divided flag to true. // This let's us know that this node does NOT have any vertices assigned to it, // but nodes that perhaps have vertices stored in them (Or their nodes, etc....) // We will querey this variable when we are drawing the octree. m_bSubDivided = true; // Create a list for each new node to store if a triangle should be stored in it's // triangle list. For each index it will be a true or false to tell us if that triangle // is in the cube of that node. Below we check every point to see where it's // position is from the center (I.E. if it's above the center, to the left and // back it's the TOP_LEFT_BACK node). Depending on the node we set the pList // index to true. This will tell us later which triangles go to which node. // You might catch that this way will produce doubles in some nodes. Some // triangles will intersect more than 1 node right? We won't split the triangles // in this tutorial just to keep it simple, but the next tutorial we will. // Create the list of booleans for each triangle index vector<bool> pList1(numberOfTriangles); // TOP_LEFT_FRONT node list vector<bool> pList2(numberOfTriangles); // TOP_LEFT_BACK node list vector<bool> pList3(numberOfTriangles); // TOP_RIGHT_BACK node list vector<bool> pList4(numberOfTriangles); // TOP_RIGHT_FRONT node list vector<bool> pList5(numberOfTriangles); // BOTTOM_LEFT_FRONT node list vector<bool> pList6(numberOfTriangles); // BOTTOM_LEFT_BACK node list vector<bool> pList7(numberOfTriangles); // BOTTOM_RIGHT_BACK node list vector<bool> pList8(numberOfTriangles); // BOTTOM_RIGHT_FRONT node list // Create this variable to cut down the thickness of the code below (easier to read) CVector3 vCtr = vCenter; // Go through all of the vertices and check which node they belong too. The way // we do this is use the center of our current node and check where the point // lies in relationship to the center. For instance, if the point is // above, left and back from the center point it's the TOP_LEFT_BACK node. // You'll see we divide by 3 because there are 3 points in a triangle. // If the vertex index 0 and 1 are in a node, 0 / 3 and 1 / 3 is 0 so it will // just set the 0'th index to TRUE twice, which doesn't hurt anything. When // we get to the 3rd vertex index of pVertices[] it will then be checking the // 1st index of the pList*[] array. We do this because we want a list of the // triangles in the node, not the vertices. for(int i = 0; i < numberOfVerts; i++) { // Create some variables to cut down the thickness of the code (easier to read) CVector3 vPoint = pVertices[i]; // Check if the point lines within the TOP LEFT FRONT node if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) ) pList1[i / 3] = true; // Check if the point lines within the TOP LEFT BACK node if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) ) pList2[i / 3] = true; // Check if the point lines within the TOP RIGHT BACK node if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) ) pList3[i / 3] = true; // Check if the point lines within the TOP RIGHT FRONT node if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) ) pList4[i / 3] = true; // Check if the point lines within the BOTTOM LEFT FRONT node if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) ) pList5[i / 3] = true; // Check if the point lines within the BOTTOM LEFT BACK node if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) ) pList6[i / 3] = true; // Check if the point lines within the BOTTOM RIGHT BACK node if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) ) pList7[i / 3] = true; // Check if the point lines within the BOTTOM RIGHT FRONT node if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) ) pList8[i / 3] = true; } // Here we create a variable for each list that holds how many triangles // were found for each of the 8 subdivided nodes. int triCount1 = 0; int triCount2 = 0; int triCount3 = 0; int triCount4 = 0; int triCount5 = 0; int triCount6 = 0; int triCount7 = 0; int triCount8 = 0; // Go through each of the lists and increase the triangle count for each node. for(int i = 0; i < numberOfTriangles; i++) { // Increase the triangle count for each node that has a "true" for the index i. if(pList1[i]) triCount1++; if(pList2[i]) triCount2++; if(pList3[i]) triCount3++; if(pList4[i]) triCount4++; if(pList5[i]) triCount5++; if(pList6[i]) triCount6++; if(pList7[i]) triCount7++; if(pList8[i]) triCount8++; } // Next we do the dirty work. We need to set up the new nodes with the triangles // that are assigned to each node, along with the new center point of the node. // Through recursion we subdivide this node into 8 more nodes. // Create the subdivided nodes if necessary and then recurse through them. // The information passed into CreateNewNode() are essential for creating the // new nodes. We pass the 8 ID's in so it knows how to calculate it's new center. CreateNewNode(pVertices, pList1, numberOfVerts, vCenter, width, triCount1, TOP_LEFT_FRONT); CreateNewNode(pVertices, pList2, numberOfVerts, vCenter, width, triCount2, TOP_LEFT_BACK); CreateNewNode(pVertices, pList3, numberOfVerts, vCenter, width, triCount3, TOP_RIGHT_BACK); CreateNewNode(pVertices, pList4, numberOfVerts, vCenter, width, triCount4, TOP_RIGHT_FRONT); CreateNewNode(pVertices, pList5, numberOfVerts, vCenter, width, triCount5, BOTTOM_LEFT_FRONT); CreateNewNode(pVertices, pList6, numberOfVerts, vCenter, width, triCount6, BOTTOM_LEFT_BACK); CreateNewNode(pVertices, pList7, numberOfVerts, vCenter, width, triCount7, BOTTOM_RIGHT_BACK); CreateNewNode(pVertices, pList8, numberOfVerts, vCenter, width, triCount8, BOTTOM_RIGHT_FRONT); } else { // If we get here we must either be subdivided past our max level, or our triangle // count went below the minimum amount of triangles so we need to store them. // Assign the vertices to this node since we reached the end node. // This will be the end node that actually gets called to be drawn. // We just pass in the vertices and vertex count to be assigned to this node. AssignVerticesToNode(pVertices, numberOfVerts); } }
void COctree::CreateNode(t3DModel *pWorld, int numberOfTriangles, CVector3 vCenter, float width) { // Initialize this node's center point. Now we know the center of this node. m_vCenter = vCenter; // Initialize this nodes cube width. Now we know the width of this current node. m_Width = width; // Add the current node to our debug rectangle list so we can visualize it. g_Debug.AddDebugRectangle(vCenter, width, width, width); // Check if we have too many triangles in this node and we haven't subdivided // above our max subdivisions. If so, then we need to break this node into // 8 more nodes (hence the word OCTree). Both must be true to divide this node. if( (numberOfTriangles > g_MaxTriangles) && (g_CurrentSubdivision < g_MaxSubdivisions) ) { // Since we need to subdivide more we set the divided flag to true. m_bSubDivided = true; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // This function pretty much stays the same, except a small twist because // we are dealing with multiple objects for the scene, not just an array of vertices. // In the previous tutorials, we used a vector<> of booleans, but now we use our // tFaceList to store a vector of booleans for each object. // Create the list of tFaceLists for each child node vector<tFaceList> pList1(pWorld->numOfObjects); // TOP_LEFT_FRONT node list vector<tFaceList> pList2(pWorld->numOfObjects); // TOP_LEFT_BACK node list vector<tFaceList> pList3(pWorld->numOfObjects); // TOP_RIGHT_BACK node list vector<tFaceList> pList4(pWorld->numOfObjects); // TOP_RIGHT_FRONT node list vector<tFaceList> pList5(pWorld->numOfObjects); // BOTTOM_LEFT_FRONT node list vector<tFaceList> pList6(pWorld->numOfObjects); // BOTTOM_LEFT_BACK node list vector<tFaceList> pList7(pWorld->numOfObjects); // BOTTOM_RIGHT_BACK node list vector<tFaceList> pList8(pWorld->numOfObjects); // BOTTOM_RIGHT_FRONT node list // Create this variable to cut down the thickness of the code below (easier to read) CVector3 vCtr = vCenter; // Go through every object in the current partition of the world for(int i = 0; i < pWorld->numOfObjects; i++) { // Store a point to the current object t3DObject *pObject = &(pWorld->pObject[i]); // Now, we have a face list for each object, for every child node. // We need to then check every triangle in this current object // to see if it's in any of the child nodes dimensions. We store a "true" in // the face list index to tell us if that's the case. This is then used // in CreateNewNode() to create a new partition of the world for that child node. // Resize the current face list to be the size of this object's face count 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); // Go through all the triangles for this object for(int j = 0; j < pObject->numOfFaces; j++) { // Check every vertice in the current triangle to see if it's inside a child node for(int whichVertex = 0; whichVertex < 3; whichVertex++) { // Store the current vertex to be checked against all the child nodes CVector3 vPoint = pObject->pVerts[pObject->pFaces[j].vertIndex[whichVertex]]; // Check if the point lies within the TOP LEFT FRONT node if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) ) pList1[i].pFaceList[j] = true; // Check if the point lies within the TOP LEFT BACK node if( (vPoint.x <= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) ) pList2[i].pFaceList[j] = true; // Check if the point lies within the TOP RIGHT BACK node if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z <= vCtr.z) ) pList3[i].pFaceList[j] = true; // Check if the point lies within the TOP RIGHT FRONT node if( (vPoint.x >= vCtr.x) && (vPoint.y >= vCtr.y) && (vPoint.z >= vCtr.z) ) pList4[i].pFaceList[j] = true; // Check if the point lies within the BOTTOM LEFT FRONT node if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) ) pList5[i].pFaceList[j] = true; // Check if the point lies within the BOTTOM LEFT BACK node if( (vPoint.x <= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) ) pList6[i].pFaceList[j] = true; // Check if the point lies within the BOTTOM RIGHT BACK node if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z <= vCtr.z) ) pList7[i].pFaceList[j] = true; // Check if the point lines within the BOTTOM RIGHT FRONT node if( (vPoint.x >= vCtr.x) && (vPoint.y <= vCtr.y) && (vPoint.z >= vCtr.z) ) pList8[i].pFaceList[j] = true; } } // Here we initialize the face count for each list that holds how many triangles // were found for each of the 8 subdivided nodes. 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; } // Here we create a variable for each list that holds how many triangles // were found for each of the 8 subdivided nodes. int triCount1 = 0; int triCount2 = 0; int triCount3 = 0; int triCount4 = 0; int triCount5 = 0; int triCount6 = 0; int triCount7 = 0; int triCount8 = 0; // Go through all of the objects of this current partition for(i = 0; i < pWorld->numOfObjects; i++) { // Go through all of the current objects triangles for(int j = 0; j < pWorld->pObject[i].numOfFaces; j++) { // Increase the triangle count for each node that has a "true" for the index i. // In other words, if the current triangle is in a child node, add 1 to the count. // We need to store the total triangle count for each object, but also // the total for the whole child node. That is why we increase 2 variables. 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++; } } } // Next we do the dirty work. We need to set up the new nodes with the triangles // that are assigned to each node, along with the new center point of the node. // Through recursion we subdivide this node into 8 more potential nodes. // Create the subdivided nodes if necessary and then recurse through them. // The information passed into CreateNewNode() are essential for creating the // new nodes. We pass the 8 ID's in so it knows how to calculate it's new center. 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); } else { // If we get here we must either be subdivided past our max level, or our triangle // count went below the minimum amount of triangles so we need to store them. // We pass in the current partition of world data to be assigned to this end node AssignTrianglesToNode(pWorld, numberOfTriangles); } /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * }