source: GTP/trunk/App/Demos/Vis/CHC_revisited/HierarchyNode.cpp @ 2642

Revision 2642, 10.9 KB checked in by mattausch, 16 years ago (diff)

new demo

Line 
1#include "HierarchyNode.h"
2#include "glInterface.h"
3#include <math.h>
4#include <limits.h>
5#include <float.h>
6
7typedef vector<Geometry *> GeometryList;
8
9// criteria and values partly taken from Piringer's thesis
10
11// values used as termination criteria for the tree generation
12// the overall surface
13float HierarchyNode::sSurfaceThreshold;
14// the maximum tree depth
15int HierarchyNode::sMaxDepth;
16// maximum number of objects in a node
17int HierarchyNode::sGeometryThreshold;
18
19// percentage of allowed deviation from the center split plane
20float HierarchyNode::sSplitBandwith;
21
22// also render bounding volume
23bool HierarchyNode::sRenderBoundingVolume = false;
24
25HierarchyNode::HierarchyNode():
26mVisible(false),
27mLastVisited(0),
28mParent(NULL),
29mOcclusionQuery(0),
30mAABValid(false),
31mLeftChild(NULL),
32mRightChild(NULL),
33mNumHierarchyNodes(1),
34mSplitAxis(X_AXIS),
35mLastRendered(-1),
36mSplitValue(0),
37mDepth(0),
38mEnclosedSpaceValid(false),
39mDistance(0)
40{
41        copyVector3Values(mBoundingBox.min, 0, 0, 0);
42        copyVector3Values(mBoundingBox.max, 0, 0, 0);
43
44        copyVector3Values(mEnclosedSpace.min, 0, 0, 0);
45        copyVector3Values(mEnclosedSpace.max, 0, 0, 0);
46
47        // bounding box color
48        mBoxColor[0] = mBoxColor[2] = 0; mBoxColor[1] = 1.0;
49}
50
51
52HierarchyNode::HierarchyNode(const Vector3 boundLower,
53                                                         const Vector3 boundUpper,
54                                                         HierarchyNode *parent,
55                                                         int depth)
56:mNumHierarchyNodes(1),
57mOcclusionQuery(0),
58mLeftChild(NULL),
59mRightChild(NULL),
60mSplitAxis(X_AXIS),
61mVisible(false),
62mLastVisited(0),
63mParent(parent),
64mAABValid(false),
65mLastRendered(-1),
66mSplitValue(0),
67mDepth(depth),
68mEnclosedSpaceValid(true),
69mDistance(0)
70{
71        copyVector3Values(mBoundingBox.min, 0, 0, 0);
72        copyVector3Values(mBoundingBox.max, 0, 0, 0);
73
74        copyVector3(mEnclosedSpace.min, boundLower);
75        copyVector3(mEnclosedSpace.max, boundUpper);
76
77        float vol = calcAABoxSurface(mEnclosedSpace);
78
79        mBoxColor[0] = mBoxColor[2] = 0; mBoxColor[1] = 1.0;
80}
81
82
83void HierarchyNode::InitKdTree(HierarchyNode *root)
84{
85        sMaxDepth = (int)((log((float) root->GetGeometry().size())/log(2.0f)) * 20.0f);
86
87        sSurfaceThreshold = FLT_MAX;
88
89        // factor times mininal surface as determination criterium
90        const float factor = 2.5;
91
92        for (GeometryList::const_iterator it = root->GetGeometry().begin(); it != root->GetGeometry().end(); it++)
93        {
94                // same geometry can possible be in to or more nodes => also test for them
95                float surface = calcAABoxSurface((*it)->GetBoundingVolume()) * factor;
96
97                if(surface < sSurfaceThreshold) sSurfaceThreshold = surface;
98        }
99
100        // number of objects in a leaf
101        sGeometryThreshold = 1;
102
103        // percentage of allowed deviation from the center split plane
104        sSplitBandwith = 0.15;
105}
106
107
108HierarchyNode::~HierarchyNode()
109{
110        if(mLeftChild)
111                delete mLeftChild;
112
113        if(mRightChild)
114                delete mRightChild;
115}
116
117int HierarchyNode::Render()
118{
119        int renderedGeometry = 0;
120
121        if(sRenderBoundingVolume)
122        {
123                glColor3fv(mBoxColor);
124        RenderBoundingVolumeForVisualization();
125        }
126
127        // prevent the geometry to be rendered several times in the same frame
128        if(mLastRendered != mLastVisited)
129        {
130                for (GeometryList::const_iterator it = mGeometry.begin(); it != mGeometry.end(); it++)
131                {
132                        // same geometry can possible be in to or more nodes => also test for them
133                        if((*it)->GetLastVisited() != mLastVisited)
134                        {
135                                (*it)->SetLastVisited(mLastVisited);
136                                (*it)->Render();
137                                renderedGeometry ++;
138                        }
139                }
140                mLastRendered = mLastVisited;
141        }
142
143        return renderedGeometry;
144}
145
146bool HierarchyNode::Visible()
147{
148        return mVisible;
149}
150
151void HierarchyNode::SetVisible(bool visible)
152{
153        mVisible = visible;
154}
155
156void HierarchyNode::SetLeftChild(HierarchyNode *child)
157{
158        mLeftChild = child;
159}
160
161void HierarchyNode::SetRightChild(HierarchyNode *child)
162{
163        mRightChild = child;
164}
165
166HierarchyNode *HierarchyNode::GetLeftChild()
167{
168        return mLeftChild;
169}
170
171HierarchyNode *HierarchyNode::GetRightChild()
172{
173        return mRightChild;
174}
175
176unsigned int HierarchyNode::LastVisited()
177{
178        return mLastVisited;
179}
180
181void HierarchyNode::SetLastVisited(unsigned int lastVisited)
182{
183        mLastVisited = lastVisited;
184}
185
186bool HierarchyNode::IsLeaf()
187{
188        return (!mLeftChild && !mRightChild);
189}
190
191void HierarchyNode::AddGeometry(Geometry *geometry)
192{
193        mGeometry.push_back(geometry);
194               
195        if(!mAABValid)
196        {
197                copyVector3(mBoundingBox.min, geometry->GetBoundingVolume().min);
198                copyVector3(mBoundingBox.max, geometry->GetBoundingVolume().max);
199
200                mAABValid = true;
201        }
202        else
203                combineAABoxes(&mBoundingBox, geometry->GetBoundingVolume());
204
205        // root node
206        if(mDepth == 0)
207        {
208                if(!mEnclosedSpaceValid)
209                {
210                        copyVector3(mEnclosedSpace.min, geometry->GetBoundingVolume().min);
211                        copyVector3(mEnclosedSpace.max, geometry->GetBoundingVolume().max);
212
213                        mEnclosedSpaceValid = true;
214                }
215                else
216                        combineAABoxes(&mEnclosedSpace, geometry->GetBoundingVolume());
217        }
218        else
219        {
220                // cut boxes so they fit into the enclosed space
221                clipAABoxByAABox(&mBoundingBox, mEnclosedSpace);
222        }
223}
224
225HierarchyNode *HierarchyNode::GetParent()
226{
227        return mParent;
228}
229
230int HierarchyNode::GetOcclusionQuery()
231{
232        return mOcclusionQuery;
233}
234
235void HierarchyNode::SetOcclusionQuery(int occlusionQuery)
236{
237        mOcclusionQuery = occlusionQuery;
238}
239
240void HierarchyNode::RenderBoundingVolume()
241{
242        Vector3x8 vertices;
243
244        calcAABoxPoints(vertices, mBoundingBox);
245
246        //glPolygonMode(GL_FRONT, GL_LINE);
247        //     7+------+6
248        //     /|     /|
249        //    / |    / |
250        //   / 4+---/--+5
251        // 3+------+2 /    y   z
252        //  | /    | /     |  /
253        //  |/     |/      |/
254        // 0+------+1      *---x
255
256        //---- render AABB
257        glBegin(GL_TRIANGLE_FAN);
258                glVertex3dv(vertices[6]);
259                glVertex3dv(vertices[5]);
260                glVertex3dv(vertices[4]);
261                glVertex3dv(vertices[7]);
262                glVertex3dv(vertices[3]);
263                glVertex3dv(vertices[2]);
264                glVertex3dv(vertices[1]);
265                glVertex3dv(vertices[5]);
266        glEnd();
267
268        //---- render second half of AABB
269        glBegin(GL_TRIANGLE_FAN);
270                glVertex3dv(vertices[0]);
271                glVertex3dv(vertices[1]);
272                glVertex3dv(vertices[2]);
273                glVertex3dv(vertices[3]);
274                glVertex3dv(vertices[7]);
275                glVertex3dv(vertices[4]);
276                glVertex3dv(vertices[5]);
277                glVertex3dv(vertices[1]);
278        glEnd();
279}
280
281
282void HierarchyNode::RenderBoundingVolumeForVisualization()
283{
284        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
285        glDisable(GL_LIGHTING);
286        glDisable(GL_CULL_FACE);
287               
288        RenderBoundingVolume();
289
290        glEnable(GL_CULL_FACE);
291        glEnable(GL_LIGHTING);
292        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
293}
294
295
296
297const AABox &HierarchyNode::GetBoundingVolume()
298{
299        return mBoundingBox;
300}
301
302int     HierarchyNode::GenerateKdTree()
303{
304        // check the termination criterium (a heuristic)
305        if (SimpleEnough())
306        {
307                return 1;
308        }
309
310        // largest dimension will be split
311        Vector3 size;
312        diffVector3(size, mBoundingBox.max, mBoundingBox.min);
313   
314        if (size[X_AXIS] > size[Y_AXIS])       
315                mSplitAxis      = (size[X_AXIS] > size[Z_AXIS]) ? X_AXIS : Z_AXIS;
316        else                                   
317                mSplitAxis      = (size[Y_AXIS] > size[Z_AXIS]) ? Y_AXIS : Z_AXIS;
318
319        // select the value of the split plane
320        mSplitValue = ComputeSplitPlane();
321       
322        // generate the children
323        Vector3 changedLower;
324        Vector3 changedUpper;
325
326        copyVector3(changedLower, mEnclosedSpace.min);
327        copyVector3(changedUpper, mEnclosedSpace.max);
328               
329        changedLower[mSplitAxis] = mSplitValue;
330        changedUpper[mSplitAxis] = mSplitValue;
331
332        mLeftChild      = new HierarchyNode(mEnclosedSpace.min, changedUpper, this, mDepth + 1);
333        mRightChild     = new HierarchyNode(changedLower, mEnclosedSpace.max, this, mDepth + 1);
334
335        // add the geometry to the according children
336        for (GeometryList::iterator it = mGeometry.begin(); it != mGeometry.end(); it++)
337        {
338                if ((*it)->GetBoundingVolume().min[mSplitAxis] >= mSplitValue)
339                {
340                        // box lies completely within right part
341                        mRightChild->AddGeometry(*it);
342                }
343                else if ((*it)->GetBoundingVolume().max[mSplitAxis] <= mSplitValue)
344                {
345                        // box lies completely within left part
346                        mLeftChild->AddGeometry((*it));
347                }
348                else
349                {
350                        //---- box intersects both parts
351                        mLeftChild->AddGeometry((*it));
352                        mRightChild->AddGeometry((*it));
353                }
354        }
355
356        //---- we continue with the children
357        int leftSize  = mLeftChild->GenerateKdTree();
358        int rightSize = mRightChild->GenerateKdTree();
359
360        // since the geometry is now referenced by the children
361        mGeometry.clear();
362       
363        mNumHierarchyNodes = leftSize + rightSize + 1;
364
365        return mNumHierarchyNodes;
366}
367
368bool HierarchyNode::SimpleEnough()
369{
370        return ((mGeometry.size() <= (unsigned int)sGeometryThreshold) ||
371                    (calcAABoxSurface(mBoundingBox) <= sSurfaceThreshold) ||
372                        (sMaxDepth <= mDepth));
373}
374
375float HierarchyNode::ComputeSplitPlane()
376{
377        float left      = mBoundingBox.min[mSplitAxis];
378        float right     = mBoundingBox.max[mSplitAxis];
379
380        // the smaller the value returned from the heuristic, the better => big starting value
381        float bestValue = FLT_MAX;
382        float result = 0.0f;
383
384        bool found      = false;
385
386        // calculate the borders of the band
387        float currLeft, currRight;
388        currLeft = currRight = (left + right) / 2.0f;
389       
390        currLeft  -= (right - left) * sSplitBandwith;
391        currRight += (right - left) * sSplitBandwith;
392
393        // check all geometry within that node
394        for (GeometryList::const_iterator it = mGeometry.begin(); it != mGeometry.end(); it++)
395        {
396                // one border of the geometry's AABB
397                float leftPlane  = (*it)->GetBoundingVolume().min[mSplitAxis];
398                // the other border of the geometry's AABB
399                float rightPlane = (*it)->GetBoundingVolume().max[mSplitAxis];
400               
401                // only consider planes that lie within the band
402                if ((leftPlane > currLeft) && (leftPlane < currRight))
403                {
404                        // compute the heuristic for the left plane and note the value if it was good
405                        float currValue = ComputeHeuristics(leftPlane);
406
407                        if (currValue < bestValue)
408                        {
409                                bestValue = currValue;
410                                result    = leftPlane;
411                                found     = true;
412                        }
413                }
414
415                if ((rightPlane > currLeft) && (rightPlane < currRight))
416                {
417                        // compute the heuristic for the right plane and note the value if it was good
418                        float currValue = ComputeHeuristics(rightPlane);
419
420                        if (currValue < bestValue)
421                        {
422                                bestValue       = currValue;
423                                result          = rightPlane;
424                                found           = true;
425                        }
426                }
427        }
428
429        // in case we haven't found any proper plane, we simply take the center
430        if (!found)     
431                result = (left + right) / 2.0f;
432                       
433        return result;
434}
435
436float HierarchyNode::ComputeHeuristics(float pos)
437{
438        // this implements a very simple heuristic: it simply counts the nodes being intersected by the splitplane
439        float result = 0.0f;
440
441        for (GeometryList::const_iterator it = mGeometry.begin(); it != mGeometry.end(); it++)
442        {
443                if (((*it)->GetBoundingVolume().min[mSplitAxis] < pos) &&
444                        ((*it)->GetBoundingVolume().max[mSplitAxis] > pos))
445                {
446                        result += 1.0f;
447                }
448        }
449
450        return result;
451}
452
453int HierarchyNode::GetNumHierarchyNodes()
454{
455        return mNumHierarchyNodes;
456}
457
458void HierarchyNode::PushChildrenOrdered(const Vector3 viewpoint, TraversalStack &traversalStack)
459{
460        if(viewpoint[mSplitAxis] > mSplitValue)
461        {
462                traversalStack.push(mLeftChild);
463                traversalStack.push(mRightChild);
464        }
465        else
466        {
467                traversalStack.push(mRightChild);
468                traversalStack.push(mLeftChild);
469        }
470}
471
472
473void HierarchyNode::SetRenderBoundingVolume(bool renderBoundingVolume)
474{
475        sRenderBoundingVolume = renderBoundingVolume;
476}
477
478
479GeometryList &HierarchyNode::GetGeometry()
480{
481        return mGeometry;
482}
483
484void HierarchyNode::SetDistance(float distance)
485{
486        mDistance = distance;
487}
Note: See TracBrowser for help on using the repository browser.