source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.cpp @ 3269

Revision 3269, 9.0 KB checked in by mattausch, 15 years ago (diff)
Line 
1#include "BvhConstructor.h"
2#include "Triangle3.h"
3#include "SceneEntity.h"
4#include "Geometry.h"
5#include "gzstream.h"
6
7#include <queue>
8#include <stack>
9#include <fstream>
10
11#define MAX_FLOAT 1e20f
12
13
14#ifdef _CRT_SET
15        #define _CRTDBG_MAP_ALLOC
16        #include <stdlib.h>
17        #include <crtdbg.h>
18
19        // redefine new operator
20        #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
21        #define new DEBUG_NEW
22#endif
23
24
25using namespace std;
26
27
28namespace CHCDemoEngine
29{
30
31BvhConstructor::BvhConstructor(SceneEntity **entities,
32                                                           int first,
33                                                           int last):
34mEntities(entities),
35mFirst(first),
36mLast(last),
37mMaxDepth(20),
38mMaxObjects(1),
39mMaxTriangles(1),
40mNumNodes(0),
41mSplitType(SAH)
42{
43}
44
45
46float BvhConstructor::EvaluateSahCost(BvhLeaf *leaf, int axis, float position)
47{
48        // count triangles on the left / right
49        int left = 0;
50        int right = 0;
51        AxisAlignedBox3 leftBox, rightBox;
52
53        leftBox.Initialize();
54        rightBox.Initialize();
55
56        const int candidates = std::max(50, (int)(leaf->CountPrimitives() / 20));
57        const float finc = leaf->CountPrimitives() / (float)candidates;
58
59        int i = leaf->mFirst;
60        float fi = leaf->mFirst + 0.5f;
61
62        AxisAlignedBox3 box;
63
64        for (; i <= leaf->mLast;)
65        {
66                box = mEntities[i]->GetWorldBoundingBox();
67
68                if (box.Center(axis) < position)
69                {
70                        ++ left;
71                        // update the box
72                        leftBox.Include(box);
73                }
74                else
75                {
76                        ++ right;
77                        rightBox.Include(box);
78                }
79                 
80                fi += finc;
81                i = (int)fi;
82        }
83
84        float bW = 1.0f;
85        float leftRatio = left / (float)leaf->CountPrimitives();
86        float rightRatio = right / (float)leaf->CountPrimitives();
87
88        float saLeft = 0.0f;
89        float saRight = 0.0f;
90
91        // not a valid split
92        if (!left || !right)
93                return 1e25f;
94
95        saLeft = leftBox.SurfaceArea();
96        saRight = rightBox.SurfaceArea();
97
98
99        return
100                saLeft  * ((1.0f - bW) + bW * leftRatio) +
101                saRight * ((1.0f - bW) + bW * rightRatio);
102}
103
104
105float BvhConstructor::SelectPlaneSah(BvhLeaf *leaf, int &axis, float &minCost)
106{
107        minCost = MAX_FLOAT;
108        float bestPos = minCost;
109        int bestAxis = 0;
110
111        //  cout<<"Evaluating axis..."<<endl<<flush;
112
113        const int initialPlanes = 3;
114
115        // initiate the costs
116        for (axis = 0; axis < 3; ++ axis)
117        {
118                const float size = leaf->mBox.Size(axis);
119
120                for (int i = 0; i < initialPlanes; ++ i)
121                {
122                        const float pos = leaf->mBox.Min(axis) + (i + 1) * size / (initialPlanes + 1);
123                        const float cost = EvaluateSahCost(leaf, axis, pos);
124
125                        if (cost < minCost)
126                        {
127                                minCost = cost;
128                                bestPos = pos;
129                                bestAxis = axis;
130                        }
131                }
132        }
133
134        axis = bestAxis;
135
136        //  cout<<axis<<endl<<flush;
137        const float shrink = 0.5f;
138
139        // now hierarchically refine the initial interval
140        float size = shrink *
141                (leaf->mBox.Max(axis) - leaf->mBox.Min(axis)) / (initialPlanes + 1);
142
143        const int steps = 4;
144        float cost;
145
146        for (int i = 0; i < steps; ++ i)
147        {
148                const float left = bestPos - size;
149                const float right = bestPos + size;
150
151                cost = EvaluateSahCost(leaf, axis, left);
152
153                if (cost < minCost)
154                {
155                        minCost = cost;
156                        bestPos = left;
157                }
158
159                cost = EvaluateSahCost(leaf, axis, right);
160
161                if (cost < minCost)
162                {
163                        minCost = cost;
164                        bestPos = right;
165                }
166
167                size = shrink * size;
168        }
169
170        //OUT1("best axis: " << axis << " " << bestPos << " " << minCost);
171
172        return bestPos;
173}
174
175
176int BvhConstructor::SortTriangles(BvhLeaf *leaf,
177                                                                  int axis,
178                                                                  float position
179                                                                  )
180{
181        int i = leaf->mFirst;
182        int j = leaf->mLast;
183
184    while (1)
185        {
186                //while (mEntities[i]->GetWorldCenter()[axis] < position) ++ i;
187                //while (position < mEntities[j]->GetWorldCenter()[axis]) -- j;
188
189                while ((i < leaf->mLast) && (mEntities[i]->GetWorldCenter()[axis] < position)) ++ i;
190                while ((j > leaf->mFirst) && (position < mEntities[j]->GetWorldCenter()[axis])) -- j;
191
192                // sorting finished
193                if (i >= j) break;
194
195                // swap entities
196                swap(mEntities[i], mEntities[j]);
197                       
198                ++ i;
199                -- j;
200        }
201
202        return j;
203}
204
205
206void BvhConstructor::UpdateBoundingBoxes(BvhNode *node)
207{
208        if (node->IsLeaf())
209        {
210                int numEntities = node->CountPrimitives();
211                SceneEntity **entities = mEntities + node->mFirst;
212
213                node->mBox = SceneEntity::ComputeBoundingBox(entities, numEntities);
214                //cout << "box: " << node->mBox << endl;
215        }
216        else
217        {
218                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
219                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
220
221                UpdateBoundingBoxes(f);
222                UpdateBoundingBoxes(b);
223
224                node->mBox = f->mBox;
225                node->mBox.Include(b->mBox);
226        }
227}
228
229
230int BvhConstructor::SortTrianglesSpatialMedian(BvhLeaf *leaf,
231                                                                                           int axis)
232{
233        // spatial median
234        float m = leaf->GetBox().Center()[axis];
235        return SortTriangles(leaf, axis, m);
236}
237
238
239int BvhConstructor::SortTrianglesObjectMedian(BvhLeaf *leaf, int axis, float &pos)
240{
241        // Now distribute the objects into the subnodes
242        // Use QuickMedian sort
243        int l = leaf->mFirst;
244        int r = leaf->mLast;
245        int k = (l + r) / 2;
246
247        while (l < r)
248        {
249                int i = l;
250                int j = r;
251
252                // get some estimation of the pivot
253                pos = mEntities[(l + r) / 2]->GetBoundingBox().Center(axis);
254
255                while (1)
256                {
257                        while ((i <= leaf->mLast) && (mEntities[i]->GetWorldBoundingBox().Center(axis) < pos))
258                                ++ i;
259
260                        while((j >= leaf->mFirst) && (pos < mEntities[j]->GetWorldBoundingBox().Center(axis)))
261                                -- j;
262
263                        if (i <= j)
264                        {
265                                std::swap(mEntities[i], mEntities[j]);
266                                ++ i;
267                                -- j;
268                        }
269                        else
270                        {
271                                break;
272                        }
273                }
274
275                // now check the extents
276                if (i >= k)
277                        r = j;
278                else
279                        l = i;
280        }
281
282        return k;
283}
284
285
286BvhNode *BvhConstructor::SubdivideLeaf(BvhLeaf *leaf,
287                                                                           int parentAxis
288                                                                           )
289{
290        if (TerminationCriteriaMet(leaf))
291        {
292                //if (leaf->CountPrimitives() <= 0)
293                //cout << "leaf constructed:" << leaf->mBox << " " << leaf->mFirst << " " << leaf->mLast << endl;
294                return leaf;
295        }
296
297        //const int axis = (parentAxis + 1) % 3;
298        int axis = leaf->mBox.MajorAxis();
299        const int scale = 20;
300
301        // position of the split in the partailly sorted array of triangles
302        // corresponding to this leaf
303        int split = -1;
304        float pos = -1.0f;
305
306        // Spatial median subdivision
307        switch (mSplitType)
308        {
309        case SPATIAL_MEDIAN:
310                split = SortTrianglesSpatialMedian(leaf, axis);
311                pos = leaf->mBox.Center()[axis];
312                break;
313        case OBJECT_MEDIAN:
314                // Object median subdivision: approximately the same number
315                // of objects on the left of the the splitting point.
316                split = SortTrianglesObjectMedian(leaf, axis, pos);
317                break;
318        case SAH:
319                {
320                        float cost;
321                        pos = SelectPlaneSah(leaf, axis, cost);
322
323                        if (pos != MAX_FLOAT)
324                        {
325                                split = SortTriangles(leaf, axis, pos);
326                        }
327
328                        if ((pos == MAX_FLOAT) || (split == leaf->mLast))
329                        {
330                                split = -1;
331                                split = SortTrianglesObjectMedian(leaf, axis, pos);
332                        }
333                }
334                break;
335        default:
336                cerr << "should not come here" << endl;
337                break;
338        }
339       
340        if (split == leaf->mLast)
341        {
342                // no split could be achieved => just halve number of objects
343                split = (leaf->mLast + leaf->mFirst) / 2;
344                //cerr << "no reduction " << leaf->CountPrimitives() << " " << leaf->mFirst << " " << leaf->mLast << endl;
345        }
346
347        // create two more nodes
348        mNumNodes += 2;
349        BvhInterior *parent = new BvhInterior(leaf->GetParent());
350        parent->mFirst = leaf->mFirst;
351        parent->mLast = leaf->mLast;
352       
353        parent->mAxis = axis;
354        parent->mBox = leaf->mBox;
355        parent->mDepth = leaf->mDepth;
356
357        BvhLeaf *front = new BvhLeaf(parent);
358
359        parent->mBack = leaf;
360        parent->mFront = front;
361               
362        // now assign the triangles to the subnodes
363        front->mFirst = split + 1;
364        front->mLast = leaf->mLast;
365        front->mDepth = leaf->mDepth + 1;
366
367        leaf->mLast = split;
368        leaf->mDepth = front->mDepth;
369        leaf->mParent = parent;
370       
371        front->mBox = SceneEntity::ComputeBoundingBox(mEntities + front->mFirst, front->CountPrimitives());
372        leaf->mBox = SceneEntity::ComputeBoundingBox(mEntities + leaf->mFirst, leaf->CountPrimitives());
373
374        // recursively continue subdivision
375        parent->mBack = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mBack), axis);
376        parent->mFront = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mFront), axis);
377       
378        return parent;
379}
380
381
382int BvhConstructor::CountTriangles(BvhNode *node) const
383{
384        int numTriangles = 0;
385
386        for (int i = node->mFirst; i <= node->mLast; ++ i)
387        {
388                numTriangles += mEntities[i]->CountNumTriangles(0);
389        }
390
391        return numTriangles;
392}
393
394
395bool BvhConstructor::TerminationCriteriaMet(BvhLeaf *leaf) const
396{
397        const bool criteriaMet =
398                (leaf->mDepth > mMaxDepth) ||
399                (leaf->CountPrimitives() <= mMaxObjects) ||
400                (CountTriangles(leaf) <= mMaxTriangles);
401
402        return criteriaMet;
403}
404
405
406BvhNode *BvhConstructor::Construct(int &numNodes)
407{
408        BvhNode *root;
409        mNumNodes = 1;
410
411        BvhLeaf *l = new BvhLeaf(NULL);
412       
413        l->mFirst = mFirst;
414        l->mLast = mLast;
415
416        cout << "\n================================" << endl;
417        cout << "constructing bvh for " << l->mLast - l->mFirst + 1 << " entities" << endl;
418
419        l->mBox = SceneEntity::ComputeBoundingBox(mEntities + mFirst, mLast - mFirst + 1);
420        l->mArea = l->mBox.SurfaceArea();
421       
422        root = SubdivideLeaf(l, 0);
423
424        UpdateBoundingBoxes(root);
425
426        numNodes = mNumNodes;
427
428        return root;
429}
430
431
432}
Note: See TracBrowser for help on using the repository browser.