| // This code contains NVIDIA Confidential Information and is disclosed to you | |
| // under a form of NVIDIA software license agreement provided separately to you. | |
| // | |
| // Notice | |
| // NVIDIA Corporation and its licensors retain all intellectual property and | |
| // proprietary rights in and to this software and related documentation and | |
| // any modifications thereto. Any use, reproduction, disclosure, or | |
| // distribution of this software and related documentation without an express | |
| // license agreement from NVIDIA Corporation is strictly prohibited. | |
| // | |
| // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES | |
| // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO | |
| // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, | |
| // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. | |
| // | |
| // Information and code furnished is believed to be accurate and reliable. | |
| // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such | |
| // information or for any infringement of patents or other rights of third parties that may | |
| // result from its use. No license is granted by implication or otherwise under any patent | |
| // or patent rights of NVIDIA Corporation. Details are subject to change without notice. | |
| // This code supersedes and replaces all information previously supplied. | |
| // NVIDIA Corporation products are not authorized for use as critical | |
| // components in life support devices or systems without express written approval of | |
| // NVIDIA Corporation. | |
| // | |
| // Copyright (c) 2013-2016 NVIDIA Corporation. All rights reserved. | |
| using namespace std; | |
| _declspec (thread) uint32_t AABBTree::s_traceDepth; | |
| AABBTree::AABBTree(const Vec3* vertices, uint32_t numVerts, const uint32_t* indices, uint32_t numFaces) | |
| : m_vertices(vertices) | |
| , m_numVerts(numVerts) | |
| , m_indices(indices) | |
| , m_numFaces(numFaces) | |
| { | |
| // build stats | |
| m_treeDepth = 0; | |
| m_innerNodes = 0; | |
| m_leafNodes = 0; | |
| Build(); | |
| } | |
| namespace | |
| { | |
| struct FaceSorter | |
| { | |
| FaceSorter(const Vec3* positions, const uint32_t* indices, uint32_t n, uint32_t axis) | |
| : m_vertices(positions) | |
| , m_indices(indices) | |
| , m_numIndices(n) | |
| , m_axis(axis) | |
| { | |
| } | |
| inline bool operator()(uint32_t lhs, uint32_t rhs) const | |
| { | |
| float a = GetCentroid(lhs); | |
| float b = GetCentroid(rhs); | |
| if (a == b) | |
| return lhs < rhs; | |
| else | |
| return a < b; | |
| } | |
| inline float GetCentroid(uint32_t face) const | |
| { | |
| const Vec3& a = m_vertices[m_indices[face*3+0]]; | |
| const Vec3& b = m_vertices[m_indices[face*3+1]]; | |
| const Vec3& c = m_vertices[m_indices[face*3+2]]; | |
| return (a[m_axis] + b[m_axis] + c[m_axis])/3.0f; | |
| } | |
| const Vec3* m_vertices; | |
| const uint32_t* m_indices; | |
| uint32_t m_numIndices; | |
| uint32_t m_axis; | |
| }; | |
| inline uint32_t LongestAxis(const Vector3& v) | |
| { | |
| if (v.x > v.y && v.x > v.z) | |
| return 0; | |
| else | |
| return (v.y > v.z) ? 1 : 2; | |
| } | |
| } // anonymous namespace | |
| void AABBTree::CalculateFaceBounds(uint32_t* faces, uint32_t numFaces, Vector3& outMinExtents, Vector3& outMaxExtents) | |
| { | |
| Vector3 minExtents(FLT_MAX); | |
| Vector3 maxExtents(-FLT_MAX); | |
| // calculate face bounds | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| Vector3 a = Vector3(m_vertices[m_indices[faces[i]*3+0]]); | |
| Vector3 b = Vector3(m_vertices[m_indices[faces[i]*3+1]]); | |
| Vector3 c = Vector3(m_vertices[m_indices[faces[i]*3+2]]); | |
| minExtents = Min(a, minExtents); | |
| maxExtents = Max(a, maxExtents); | |
| minExtents = Min(b, minExtents); | |
| maxExtents = Max(b, maxExtents); | |
| minExtents = Min(c, minExtents); | |
| maxExtents = Max(c, maxExtents); | |
| } | |
| outMinExtents = minExtents; | |
| outMaxExtents = maxExtents; | |
| } | |
| // track current tree depth | |
| static uint32_t s_depth = 0; | |
| void AABBTree::Build() | |
| { | |
| assert(m_numFaces*3); | |
| //const double startTime = GetSeconds(); | |
| const uint32_t numFaces = m_numFaces; | |
| // build initial list of faces | |
| m_faces.reserve(numFaces); | |
| /* | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| m_faces[i] = i; | |
| } | |
| */ | |
| // calculate bounds of each face and store | |
| m_faceBounds.reserve(numFaces); | |
| std::vector<Bounds> stack; | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| Bounds top; | |
| CalculateFaceBounds(&i, 1, top.m_min, top.m_max); | |
| m_faces.push_back(i); | |
| m_faceBounds.push_back(top); | |
| /* | |
| stack.push_back(top); | |
| while (!stack.empty()) | |
| { | |
| Bounds b = stack.back(); | |
| stack.pop_back(); | |
| const float kAreaThreshold = 200.0f; | |
| if (b.GetSurfaceArea() < kAreaThreshold) | |
| { | |
| // node is good, append to our face list | |
| m_faces.push_back(i); | |
| m_faceBounds.push_back(b); | |
| } | |
| else | |
| { | |
| // split along longest axis | |
| uint32_t a = LongestAxis(b.m_max-b.m_min); | |
| float splitPos = (b.m_min[a] + b.m_max[a])*0.5f; | |
| Bounds left(b); | |
| left.m_max[a] = splitPos; | |
| assert(left.GetSurfaceArea() < b.GetSurfaceArea()); | |
| Bounds right(b); | |
| right.m_min[a] = splitPos; | |
| assert(right.GetSurfaceArea() < b.GetSurfaceArea()); | |
| stack.push_back(left); | |
| stack.push_back(right); | |
| } | |
| } | |
| */ | |
| } | |
| m_nodes.reserve(uint32_t(numFaces*1.5f)); | |
| // allocate space for all the nodes | |
| m_freeNode = 1; | |
| // start building | |
| BuildRecursive(0, &m_faces[0], numFaces); | |
| assert(s_depth == 0); | |
| /* | |
| const double buildTime = (GetSeconds()-startTime); | |
| cout << "AAABTree Build Stats:" << endl; | |
| cout << "Node size: " << sizeof(Node) << endl; | |
| cout << "Build time: " << buildTime << "s" << endl; | |
| cout << "Inner nodes: " << m_innerNodes << endl; | |
| cout << "Leaf nodes: " << m_leafNodes << endl; | |
| cout << "Alloc nodes: " << m_nodes.size() << endl; | |
| cout << "Avg. tris/leaf: " << m_faces.size() / float(m_leafNodes) << endl; | |
| cout << "Max depth: " << m_treeDepth << endl; | |
| */ | |
| // free some memory | |
| FaceBoundsArray f; | |
| m_faceBounds.swap(f); | |
| } | |
| // partion faces around the median face | |
| uint32_t AABBTree::PartitionMedian(Node& n, uint32_t* faces, uint32_t numFaces) | |
| { | |
| FaceSorter predicate(&m_vertices[0], &m_indices[0], m_numFaces*3, LongestAxis(n.m_maxExtents-n.m_minExtents)); | |
| std::nth_element(faces, faces+numFaces/2, faces+numFaces, predicate); | |
| return numFaces/2; | |
| } | |
| // partion faces based on the surface area heuristic | |
| uint32_t AABBTree::PartitionSAH(Node& n, uint32_t* faces, uint32_t numFaces) | |
| { | |
| /* | |
| Vector3 mean(0.0f); | |
| Vector3 variance(0.0f); | |
| // calculate best axis based on variance | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| mean += 0.5f*(m_faceBounds[faces[i]].m_min + m_faceBounds[faces[i]].m_max); | |
| } | |
| mean /= float(numFaces); | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| Vector3 v = 0.5f*(m_faceBounds[faces[i]].m_min + m_faceBounds[faces[i]].m_max) - mean; | |
| v *= v; | |
| variance += v; | |
| } | |
| uint32_t bestAxis = LongestAxis(variance); | |
| */ | |
| uint32_t bestAxis = 0; | |
| uint32_t bestIndex = 0; | |
| float bestCost = FLT_MAX; | |
| for (uint32_t a=0; a < 3; ++a) | |
| //uint32_t a = bestAxis; | |
| { | |
| // sort faces by centroids | |
| FaceSorter predicate(&m_vertices[0], &m_indices[0], m_numFaces*3, a); | |
| std::sort(faces, faces+numFaces, predicate); | |
| // two passes over data to calculate upper and lower bounds | |
| vector<float> cumulativeLower(numFaces); | |
| vector<float> cumulativeUpper(numFaces); | |
| Bounds lower; | |
| Bounds upper; | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| lower.Union(m_faceBounds[faces[i]]); | |
| upper.Union(m_faceBounds[faces[numFaces-i-1]]); | |
| cumulativeLower[i] = lower.GetSurfaceArea(); | |
| cumulativeUpper[numFaces-i-1] = upper.GetSurfaceArea(); | |
| } | |
| float invTotalSA = 1.0f / cumulativeUpper[0]; | |
| // test all split positions | |
| for (uint32_t i=0; i < numFaces-1; ++i) | |
| { | |
| float pBelow = cumulativeLower[i] * invTotalSA; | |
| float pAbove = cumulativeUpper[i] * invTotalSA; | |
| float cost = 0.125f + (pBelow*i + pAbove*(numFaces-i)); | |
| if (cost <= bestCost) | |
| { | |
| bestCost = cost; | |
| bestIndex = i; | |
| bestAxis = a; | |
| } | |
| } | |
| } | |
| // re-sort by best axis | |
| FaceSorter predicate(&m_vertices[0], &m_indices[0], m_numFaces*3, bestAxis); | |
| std::sort(faces, faces+numFaces, predicate); | |
| return bestIndex+1; | |
| } | |
| void AABBTree::BuildRecursive(uint32_t nodeIndex, uint32_t* faces, uint32_t numFaces) | |
| { | |
| const uint32_t kMaxFacesPerLeaf = 6; | |
| // if we've run out of nodes allocate some more | |
| if (nodeIndex >= m_nodes.size()) | |
| { | |
| uint32_t s = std::max(uint32_t(1.5f*m_nodes.size()), 512U); | |
| //cout << "Resizing tree, current size: " << m_nodes.size()*sizeof(Node) << " new size: " << s*sizeof(Node) << endl; | |
| m_nodes.resize(s); | |
| } | |
| // a reference to the current node, need to be careful here as this reference may become invalid if array is resized | |
| Node& n = m_nodes[nodeIndex]; | |
| // track max tree depth | |
| ++s_depth; | |
| m_treeDepth = max(m_treeDepth, s_depth); | |
| CalculateFaceBounds(faces, numFaces, n.m_minExtents, n.m_maxExtents); | |
| // calculate bounds of faces and add node | |
| if (numFaces <= kMaxFacesPerLeaf) | |
| { | |
| n.m_faces = faces; | |
| n.m_numFaces = numFaces; | |
| ++m_leafNodes; | |
| } | |
| else | |
| { | |
| ++m_innerNodes; | |
| // face counts for each branch | |
| //const uint32_t leftCount = PartitionMedian(n, faces, numFaces); | |
| const uint32_t leftCount = PartitionSAH(n, faces, numFaces); | |
| const uint32_t rightCount = numFaces-leftCount; | |
| // alloc 2 nodes | |
| m_nodes[nodeIndex].m_children = m_freeNode; | |
| // allocate two nodes | |
| m_freeNode += 2; | |
| // split faces in half and build each side recursively | |
| BuildRecursive(m_nodes[nodeIndex].m_children+0, faces, leftCount); | |
| BuildRecursive(m_nodes[nodeIndex].m_children+1, faces+leftCount, rightCount); | |
| } | |
| --s_depth; | |
| } | |
| struct StackEntry | |
| { | |
| uint32_t m_node; | |
| float m_dist; | |
| }; | |
| /* | |
| bool AABBTree::TraceRay(const Vec3& start, const Vector3& dir, float& outT, float& outU, float& outV, float& outW, float& outSign, uint32_t& outIndex) const | |
| { | |
| #if _WIN32 | |
| // reset stats | |
| s_traceDepth = 0; | |
| #endif | |
| const Vector3 rcp_dir(1.0f/dir.x, 1.0f/dir.y, 1.0f/dir.z); | |
| // some temp variables | |
| Vector3 normal; | |
| float t, u, v, w, s; | |
| float minT, minU, minV, minW, minSign; | |
| minU = minV = minW = minSign = minT = FLT_MAX; | |
| uint32_t minIndex = 0; | |
| Vector3 minNormal; | |
| const uint32_t kStackDepth = 50; | |
| StackEntry stack[kStackDepth]; | |
| stack[0].m_node = 0; | |
| stack[0].m_dist = 0.0f; | |
| uint32_t stackCount = 1; | |
| while (stackCount) | |
| { | |
| // pop node from back | |
| StackEntry& e = stack[--stackCount]; | |
| // ignore if another node has already come closer | |
| if (e.m_dist >= minT) | |
| { | |
| continue; | |
| } | |
| const Node* node = &m_nodes[e.m_node]; | |
| filth: | |
| if (node->m_faces == NULL) | |
| { | |
| #if TRACE_STATS | |
| extern uint32_t g_nodesChecked; | |
| ++g_nodesChecked; | |
| #endif | |
| #if _WIN32 | |
| ++s_traceDepth; | |
| #endif | |
| // find closest node | |
| const Node& leftChild = m_nodes[node->m_children+0]; | |
| const Node& rightChild = m_nodes[node->m_children+1]; | |
| float dist[2] = {FLT_MAX, FLT_MAX}; | |
| IntersectRayAABBOmpf(start, rcp_dir, leftChild.m_minExtents, leftChild.m_maxExtents, dist[0]); | |
| IntersectRayAABBOmpf(start, rcp_dir, rightChild.m_minExtents, rightChild.m_maxExtents, dist[1]); | |
| const uint32_t closest = dist[1] < dist[0]; // 0 or 1 | |
| const uint32_t furthest = closest ^ 1; | |
| if (dist[furthest] < minT) | |
| { | |
| StackEntry& e = stack[stackCount++]; | |
| e.m_node = node->m_children+furthest; | |
| e.m_dist = dist[furthest]; | |
| } | |
| // lifo | |
| if (dist[closest] < minT) | |
| { | |
| node = &m_nodes[node->m_children+closest]; | |
| goto filth; | |
| } | |
| } | |
| else | |
| { | |
| for (uint32_t i=0; i < node->m_numFaces; ++i) | |
| { | |
| const uint32_t faceIndex = node->m_faces[i]; | |
| const uint32_t indexStart = faceIndex*3; | |
| const Vec3& a = m_vertices[m_indices[indexStart+0]]; | |
| const Vec3& b = m_vertices[m_indices[indexStart+1]]; | |
| const Vec3& c = m_vertices[m_indices[indexStart+2]]; | |
| #if TRACE_STATS | |
| extern uint32_t g_trisChecked; | |
| ++g_trisChecked; | |
| #endif | |
| if (IntersectRayTriTwoSided(start, dir, a, b, c, t, u, v, w, s)) | |
| { | |
| if (t < minT && t > 0.01f) | |
| { | |
| minT = t; | |
| minU = u; | |
| minV = v; | |
| minW = w; | |
| minSign = s; | |
| minIndex = faceIndex; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // copy to outputs | |
| outT = minT; | |
| outU = minU; | |
| outV = minV; | |
| outW = minW; | |
| outSign = minSign; | |
| outIndex = minIndex; | |
| return (outT != FLT_MAX); | |
| } | |
| */ | |
| bool AABBTree::TraceRay(const Vec3& start, const Vector3& dir, float& outT, float& u, float& v, float& w, float& faceSign, uint32_t& faceIndex) const | |
| { | |
| //s_traceDepth = 0; | |
| Vector3 rcp_dir(1.0f/dir.x, 1.0f/dir.y, 1.0f/dir.z); | |
| outT = FLT_MAX; | |
| TraceRecursive(0, start, dir, outT, u, v, w, faceSign, faceIndex); | |
| return (outT != FLT_MAX); | |
| } | |
| void AABBTree::TraceRecursive(uint32_t nodeIndex, const Vec3& start, const Vector3& dir, float& outT, float& outU, float& outV, float& outW, float& faceSign, uint32_t& faceIndex) const | |
| { | |
| const Node& node = m_nodes[nodeIndex]; | |
| if (node.m_faces == NULL) | |
| { | |
| ++s_traceDepth; | |
| extern uint32_t g_nodesChecked; | |
| ++g_nodesChecked; | |
| // find closest node | |
| const Node& leftChild = m_nodes[node.m_children+0]; | |
| const Node& rightChild = m_nodes[node.m_children+1]; | |
| float dist[2] = {FLT_MAX, FLT_MAX}; | |
| IntersectRayAABB(start, dir, leftChild.m_minExtents, leftChild.m_maxExtents, dist[0], NULL); | |
| IntersectRayAABB(start, dir, rightChild.m_minExtents, rightChild.m_maxExtents, dist[1], NULL); | |
| uint32_t closest = 0; | |
| uint32_t furthest = 1; | |
| if (dist[1] < dist[0]) | |
| { | |
| closest = 1; | |
| furthest = 0; | |
| } | |
| if (dist[closest] < outT) | |
| TraceRecursive(node.m_children+closest, start, dir, outT, outU, outV, outW, faceSign, faceIndex); | |
| if (dist[furthest] < outT) | |
| TraceRecursive(node.m_children+furthest, start, dir, outT, outU, outV, outW, faceSign, faceIndex); | |
| } | |
| else | |
| { | |
| Vector3 normal; | |
| float t, u, v, w, s; | |
| for (uint32_t i=0; i < node.m_numFaces; ++i) | |
| { | |
| uint32_t indexStart = node.m_faces[i]*3; | |
| const Vec3& a = m_vertices[m_indices[indexStart+0]]; | |
| const Vec3& b = m_vertices[m_indices[indexStart+1]]; | |
| const Vec3& c = m_vertices[m_indices[indexStart+2]]; | |
| extern uint32_t g_trisChecked; | |
| ++g_trisChecked; | |
| if (IntersectRayTriTwoSided(start, dir, a, b, c, t, u, v, w, s)) | |
| { | |
| if (t < outT) | |
| { | |
| outT = t; | |
| outU = u; | |
| outV = v; | |
| outW = w; | |
| faceSign = s; | |
| faceIndex = node.m_faces[i]; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* | |
| bool AABBTree::TraceRay(const Vec3& start, const Vector3& dir, float& outT, Vector3* outNormal) const | |
| { | |
| outT = FLT_MAX; | |
| TraceRecursive(0, start, dir, outT, outNormal); | |
| return (outT != FLT_MAX); | |
| } | |
| void AABBTree::TraceRecursive(uint32_t n, const Vec3& start, const Vector3& dir, float& outT, Vector3* outNormal) const | |
| { | |
| const Node& node = m_nodes[n]; | |
| if (node.m_numFaces == 0) | |
| { | |
| extern _declspec(thread) uint32_t g_traceDepth; | |
| ++g_traceDepth; | |
| #if _DEBUG | |
| extern uint32_t g_nodesChecked; | |
| ++g_nodesChecked; | |
| #endif | |
| float t; | |
| if (IntersectRayAABB(start, dir, node.m_minExtents, node.m_maxExtents, t, NULL)) | |
| { | |
| if (t <= outT) | |
| { | |
| TraceRecursive(n*2+1, start, dir, outT, outNormal); | |
| TraceRecursive(n*2+2, start, dir, outT, outNormal); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| Vector3 normal; | |
| float t, u, v, w; | |
| for (uint32_t i=0; i < node.m_numFaces; ++i) | |
| { | |
| uint32_t indexStart = node.m_faces[i]*3; | |
| const Vec3& a = m_vertices[m_indices[indexStart+0]]; | |
| const Vec3& b = m_vertices[m_indices[indexStart+1]]; | |
| const Vec3& c = m_vertices[m_indices[indexStart+2]]; | |
| #if _DEBUG | |
| extern uint32_t g_trisChecked; | |
| ++g_trisChecked; | |
| #endif | |
| if (IntersectRayTri(start, dir, a, b, c, t, u, v, w, &normal)) | |
| { | |
| if (t < outT) | |
| { | |
| outT = t; | |
| if (outNormal) | |
| *outNormal = normal; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| */ | |
| bool AABBTree::TraceRaySlow(const Vec3& start, const Vector3& dir, float& outT, float& outU, float& outV, float& outW, float& faceSign, uint32_t& faceIndex) const | |
| { | |
| const uint32_t numFaces = GetNumFaces(); | |
| float minT, minU, minV, minW, minS; | |
| minT = minU = minV = minW = minS = FLT_MAX; | |
| Vector3 minNormal(0.0f, 1.0f, 0.0f); | |
| Vector3 n(0.0f, 1.0f, 0.0f); | |
| float t, u, v, w, s; | |
| bool hit = false; | |
| uint32_t minIndex = 0; | |
| for (uint32_t i=0; i < numFaces; ++i) | |
| { | |
| const Vec3& a = m_vertices[m_indices[i*3+0]]; | |
| const Vec3& b = m_vertices[m_indices[i*3+1]]; | |
| const Vec3& c = m_vertices[m_indices[i*3+2]]; | |
| if (IntersectRayTriTwoSided(start, dir, a, b, c, t, u, v, w, s)) | |
| { | |
| if (t < minT) | |
| { | |
| minT = t; | |
| minU = u; | |
| minV = v; | |
| minW = w; | |
| minS = s; | |
| minNormal = n; | |
| minIndex = i; | |
| hit = true; | |
| } | |
| } | |
| } | |
| outT = minT; | |
| outU = minU; | |
| outV = minV; | |
| outW = minW; | |
| faceSign = minS; | |
| faceIndex = minIndex; | |
| return hit; | |
| } | |
| void AABBTree::DebugDraw() | |
| { | |
| /* | |
| glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); | |
| DebugDrawRecursive(0, 0); | |
| glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); | |
| */ | |
| } | |
| void AABBTree::DebugDrawRecursive(uint32_t nodeIndex, uint32_t depth) | |
| { | |
| static uint32_t kMaxDepth = 3; | |
| if (depth > kMaxDepth) | |
| return; | |
| /* | |
| Node& n = m_nodes[nodeIndex]; | |
| Vector3 minExtents = FLT_MAX; | |
| Vector3 maxExtents = -FLT_MAX; | |
| // calculate face bounds | |
| for (uint32_t i=0; i < m_vertices.size(); ++i) | |
| { | |
| Vector3 a = m_vertices[i]; | |
| minExtents = Min(a, minExtents); | |
| maxExtents = Max(a, maxExtents); | |
| } | |
| glBegin(GL_QUADS); | |
| glVertex3f(minExtents.x, maxExtents.y, 0.0f); | |
| glVertex3f(maxExtents.x, maxExtents.y, 0.0f); | |
| glVertex3f(maxExtents.x, minExtents.y, 0.0f); | |
| glVertex3f(minExtents.x, minExtents.y, 0.0f); | |
| glEnd(); | |
| n.m_center = Vec3(minExtents+maxExtents)/2; | |
| n.m_extents = (maxExtents-minExtents)/2; | |
| */ | |
| /* | |
| if (n.m_minEtextents != Vector3(0.0f)) | |
| { | |
| Vec3 corners[8]; | |
| corners[0] = n.m_center + Vector3(-n.m_extents.x, n.m_extents.y, n.m_extents.z); | |
| corners[1] = n.m_center + Vector3(n.m_extents.x, n.m_extents.y, n.m_extents.z); | |
| corners[2] = n.m_center + Vector3(n.m_extents.x, -n.m_extents.y, n.m_extents.z); | |
| corners[3] = n.m_center + Vector3(-n.m_extents.x, -n.m_extents.y, n.m_extents.z); | |
| corners[4] = n.m_center + Vector3(-n.m_extents.x, n.m_extents.y, -n.m_extents.z); | |
| corners[5] = n.m_center + Vector3(n.m_extents.x, n.m_extents.y, -n.m_extents.z); | |
| corners[6] = n.m_center + Vector3(n.m_extents.x, -n.m_extents.y, -n.m_extents.z); | |
| corners[7] = n.m_center + Vector3(-n.m_extents.x, -n.m_extents.y, -n.m_extents.z); | |
| glBegin(GL_QUADS); | |
| glColor3f(0.0f, 1.0f, 0.0f); | |
| glVertex3fv(corners[0]); | |
| glVertex3fv(corners[1]); | |
| glVertex3fv(corners[2]); | |
| glVertex3fv(corners[3]); | |
| glVertex3fv(corners[1]); | |
| glVertex3fv(corners[5]); | |
| glVertex3fv(corners[6]); | |
| glVertex3fv(corners[2]); | |
| glVertex3fv(corners[0]); | |
| glVertex3fv(corners[4]); | |
| glVertex3fv(corners[5]); | |
| glVertex3fv(corners[1]); | |
| glVertex3fv(corners[4]); | |
| glVertex3fv(corners[5]); | |
| glVertex3fv(corners[6]); | |
| glVertex3fv(corners[7]); | |
| glVertex3fv(corners[0]); | |
| glVertex3fv(corners[4]); | |
| glVertex3fv(corners[7]); | |
| glVertex3fv(corners[3]); | |
| glVertex3fv(corners[3]); | |
| glVertex3fv(corners[7]); | |
| glVertex3fv(corners[6]); | |
| glVertex3fv(corners[2]); | |
| glEnd(); | |
| DebugDrawRecursive(nodeIndex*2+1, depth+1); | |
| DebugDrawRecursive(nodeIndex*2+2, depth+1); | |
| } | |
| */ | |
| } | |