source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/HierarchyNode.cpp @ 2782

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