source: GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.cpp @ 1999

Revision 1999, 28.5 KB checked in by mattausch, 17 years ago (diff)
  • Property svn:executable set to *
Line 
1#include "Environment.h"
2#include "GvsPreprocessor.h"
3#include "GlRenderer.h"
4#include "VssRay.h"
5#include "ViewCellsManager.h"
6#include "Triangle3.h"
7#include "IntersectableWrapper.h"
8#include "Plane3.h"
9#include "RayCaster.h"
10#include "Exporter.h"
11#include "SamplingStrategy.h"
12#include "BvHierarchy.h"
13
14
15namespace GtpVisibilityPreprocessor
16{
17 
18#define GVS_DEBUG 1
19
20struct VizStruct
21{
22        Polygon3 *enlargedTriangle;
23        Triangle3 originalTriangle;
24        VssRay *ray;
25};
26
27static const float MIN_DIST = 0.01f;
28
29static vector<VizStruct> vizContainer;
30
31GvsPreprocessor::GvsPreprocessor():
32Preprocessor(),
33//mSamplingType(SamplingStrategy::VIEWCELL_BASED_DISTRIBUTION),
34mSamplingType(SamplingStrategy::DIRECTION_BASED_DISTRIBUTION),
35mProcessedViewCells(0),
36mCurrentViewCell(NULL)
37{
38        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.totalSamples", mTotalSamples);
39        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.initialSamples", mInitialSamples);
40        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.samplesPerPass", mSamplesPerPass);
41        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.minContribution", mMinContribution);
42        Environment::GetSingleton()->GetFloatValue("GvsPreprocessor.epsilon", mEps);
43        Environment::GetSingleton()->GetFloatValue("GvsPreprocessor.threshold", mThreshold);   
44        Environment::GetSingleton()->GetBoolValue("GvsPreprocessor.perViewCell", mPerViewCell);
45        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.maxViewCells", mMaxViewCells);
46
47        char gvsStatsLog[100];
48        Environment::GetSingleton()->GetStringValue("GvsPreprocessor.stats", gvsStatsLog);
49        mGvsStatsStream.open(gvsStatsLog);
50
51        Debug << "Gvs preprocessor options" << endl;
52        Debug << "number of total samples: " << mTotalSamples << endl;
53        Debug << "number of initial samples: " << mInitialSamples << endl;
54        Debug << "number of samples per pass: " << mSamplesPerPass << endl;
55        Debug << "threshold: " << mThreshold << endl;
56        Debug << "epsilon: " << mEps << endl;
57        Debug << "stats: " << gvsStatsLog << endl;
58        Debug << "per view cell: " << mPerViewCell << endl;
59        Debug << "max view cells: " << mMaxViewCells << endl;
60        Debug << "min contribution: " << mMinContribution << endl;
61
62        if (1)
63                mOnlyRandomSampling = false;           
64        else
65                mOnlyRandomSampling = true;
66
67        mGvsStats.Reset();
68}
69
70
71GvsPreprocessor::~GvsPreprocessor()
72{
73        ClearRayQueue();
74}
75
76
77void GvsPreprocessor::ClearRayQueue()
78{
79        // clean ray queue
80        while (!mRayQueue.empty())
81        {
82                // handle next ray
83                VssRay *ray = mRayQueue.top();
84                mRayQueue.pop();
85
86                delete ray;
87        }
88}
89
90
91bool GvsPreprocessor::NextViewCell()
92{
93        //if (mViewCellsManager->GetNumViewCells() == mProcessedViewCells)
94        //      return false; // no more view cells
95
96        if (mProcessedViewCells == (int)mViewCells.size())
97                return false; // no more view cells
98
99        mCurrentViewCell = mViewCells[mProcessedViewCells];
100
101   if (!mCurrentViewCell->GetMesh())
102                mViewCellsManager->CreateMesh(mCurrentViewCell);
103
104        mGvsStats.mViewCellId = mCurrentViewCell->GetId();
105
106        Debug << "vc: " << mCurrentViewCell->GetId() << endl;
107
108        ++ mProcessedViewCells;
109   
110        return true;
111}
112
113
114int GvsPreprocessor::CheckDiscontinuity(const VssRay &currentRay,
115                                                                                const Triangle3 &hitTriangle,
116                                                                                const VssRay &oldRay)
117{
118        // the predicted hitpoint: we expect to hit the same mesh again
119        const Vector3 predictedHit = CalcPredictedHitPoint(currentRay, hitTriangle, oldRay);
120
121        const float predictedLen = Magnitude(predictedHit - currentRay.mOrigin);
122        const float len = Magnitude(currentRay.mTermination - currentRay.mOrigin);
123       
124        // distance large => this is likely to be a discontinuity
125#if 1
126        if ((predictedLen - len) > mThreshold)
127#else // rather use relative distance
128        if ((predictedLen / len) > mThreshold)
129#endif
130        {
131                //cout << "r";
132                // apply reverse sampling to find the gap
133                VssRay *newRay = ReverseSampling(currentRay, hitTriangle, oldRay);
134
135                if (!newRay)
136                        return 1;
137
138                // set flag for visualization
139                newRay->mFlags |= VssRay::ReverseSample;
140               
141                // if ray is not further processed => delete ray
142                if (!HandleRay(newRay))
143                {
144                        delete newRay;
145                }
146               
147
148                return 1;
149        }
150
151        return 0;
152}
153
154// #id: 1270
155bool GvsPreprocessor::HasContribution(VssRay &ray)
156{
157        if (!ray.mTerminationObject)
158                return false;
159
160        bool result;
161
162        if (!mPerViewCell)
163        {
164                // store the rays + the intersected view cells
165                const bool storeViewCells = false; //GVS_DEBUG;
166
167                mViewCellsManager->ComputeSampleContribution(ray,
168                                                                                                         true,
169                                                                                                         storeViewCells,
170                                                                                                         true);
171
172                result = ray.mPvsContribution > 0;
173        }
174        else
175        {
176                Intersectable *obj = ray.mTerminationObject;
177
178                if (!obj->mCounter)
179                {
180                        obj->mCounter = 1;
181                        mTrianglePvs.push_back(obj);
182
183                        /*mViewCellsManager->ComputeSampleContribution(ray,
184                                                                                                         true,
185                                                                                                         mCurrentViewCell,
186                                                                                                         true);*/
187                       
188                        result = true;
189                }
190                else
191                {
192                        result = false;
193                }
194        }
195
196        return result;
197}
198
199
200bool GvsPreprocessor::HandleRay(VssRay *vssRay)
201{
202        if (!HasContribution(*vssRay))
203                return false;
204
205        if (0 && GVS_DEBUG)
206                mVssRays.push_back(new VssRay(*vssRay));
207
208        // add new ray to ray queue
209        mRayQueue.push(vssRay);
210
211        ++ mGvsStats.mTotalContribution;
212
213        return true;
214}
215
216
217/** Creates 3 new vertices for triangle vertex with specified index.
218*/
219void GvsPreprocessor::CreateDisplacedVertices(VertexContainer &vertices,
220                                                                                          const Triangle3 &hitTriangle,
221                                                                                          const VssRay &ray,
222                                                                                          const int index) const
223{
224        const int indexU = (index + 1) % 3;
225        const int indexL = (index == 0) ? 2 : index - 1;
226
227        const Vector3 a = hitTriangle.mVertices[index] - ray.GetOrigin();
228        const Vector3 b = hitTriangle.mVertices[indexU] - hitTriangle.mVertices[index];
229        const Vector3 c = hitTriangle.mVertices[index] - hitTriangle.mVertices[indexL];
230       
231        const float len = Magnitude(a);
232       
233        const Vector3 dir1 = Normalize(CrossProd(a, b)); //N((pi-xp)×(pi+1- pi));
234        const Vector3 dir2 = Normalize(CrossProd(a, c)); // N((pi-xp)×(pi- pi-1))
235        const Vector3 dir3 = DotProd(dir2, dir1) > 0 ? // N((pi-xp)×di,i-1+di,i+1×(pi-xp))
236                Normalize(dir2 + dir1) : Normalize(CrossProd(a, dir1) + CrossProd(dir2, a));
237
238        // compute the new three hit points
239        // pi, i + 1:  pi+ e·|pi-xp|·di, j
240        const Vector3 pt1 = hitTriangle.mVertices[index] + mEps * len * dir1;
241        // pi, i - 1:  pi+ e·|pi-xp|·di, j
242    const Vector3 pt2 = hitTriangle.mVertices[index] + mEps * len * dir2;
243        // pi, i:  pi+ e·|pi-xp|·di, j
244        const Vector3 pt3 = hitTriangle.mVertices[index] + mEps * len * dir3;
245       
246        vertices.push_back(pt2);
247        vertices.push_back(pt3);
248        vertices.push_back(pt1);
249}
250
251
252void GvsPreprocessor::EnlargeTriangle(VertexContainer &vertices,
253                                                                          const Triangle3 &hitTriangle,
254                                                                          const VssRay &ray) const
255{
256        CreateDisplacedVertices(vertices, hitTriangle, ray, 0);
257        CreateDisplacedVertices(vertices, hitTriangle, ray, 1);
258        CreateDisplacedVertices(vertices, hitTriangle, ray, 2);
259}
260
261
262Vector3 GvsPreprocessor::CalcPredictedHitPoint(const VssRay &newRay,
263                                                                                           const Triangle3 &hitTriangle,
264                                                                                           const VssRay &oldRay) const
265{
266        // find the intersection of the plane induced by the
267        // hit triangle with the new ray
268        Plane3 plane(hitTriangle.GetNormal(), hitTriangle.mVertices[0]);
269
270        const Vector3 hitPt =
271                plane.FindIntersection(newRay.mTermination, newRay.mOrigin);
272       
273        return hitPt;
274}
275
276
277static bool EqualVisibility(const VssRay &a, const VssRay &b)
278{
279        return a.mTerminationObject == b.mTerminationObject;
280}
281
282
283int GvsPreprocessor::SubdivideEdge(const Triangle3 &hitTriangle,
284                                                                   const Vector3 &p1,
285                                                                   const Vector3 &p2,
286                                                                   const VssRay &ray1,
287                                                                   const VssRay &ray2,
288                                                                   const VssRay &oldRay)
289{
290        int castRays = 0;
291
292        // cast reverse rays if necessary
293        castRays += CheckDiscontinuity(ray1, hitTriangle, oldRay);
294        castRays += CheckDiscontinuity(ray2, hitTriangle, oldRay);
295
296        if (EqualVisibility(ray1, ray2) || (Magnitude(p1 - p2) <= MIN_DIST))
297        {
298                return castRays;
299        }
300       
301        // the new subdivision point
302        const Vector3 p = (p1 + p2) * 0.5f;
303
304        // cast ray into the new point
305        SimpleRay sray(oldRay.mOrigin, p - oldRay.mOrigin, SamplingStrategy::GVS, 1.0f);
306
307        VssRay *newRay = mRayCaster->CastRay(sray, mViewCellsManager->GetViewSpaceBox(), !mPerViewCell);
308       
309        ++ castRays;
310
311        if (!newRay) return castRays;
312
313        newRay->mFlags |= VssRay::BorderSample;
314
315        // add new ray to queue
316        const bool enqueued = HandleRay(newRay);
317
318        // subdivide further
319        castRays += SubdivideEdge(hitTriangle, p1, p, ray1, *newRay, oldRay);
320        castRays += SubdivideEdge(hitTriangle, p, p2, *newRay, ray2, oldRay);
321
322        // this ray will not be further processed
323        if (!enqueued)
324                delete newRay;
325
326        return castRays;
327}
328
329
330int GvsPreprocessor::AdaptiveBorderSampling(const VssRay &currentRay)
331{
332        Intersectable *tObj = currentRay.mTerminationObject;
333        Triangle3 hitTriangle;
334
335        // other types not implemented yet
336        if (tObj->Type() == Intersectable::TRIANGLE_INTERSECTABLE)
337        {
338                hitTriangle = dynamic_cast<TriangleIntersectable *>(tObj)->GetItem();
339        }
340        else
341        {
342                cout << "not yet implemented" << endl;
343        }
344
345        VertexContainer enlargedTriangle;
346       
347        /// create 3 new hit points for each vertex
348        EnlargeTriangle(enlargedTriangle, hitTriangle, currentRay);
349       
350        /// create rays from sample points and handle them
351        SimpleRayContainer simpleRays;
352        simpleRays.reserve(9);
353
354        VertexContainer::const_iterator vit, vit_end = enlargedTriangle.end();
355
356        for (vit = enlargedTriangle.begin(); vit != vit_end; ++ vit)
357        {
358                const Vector3 rayDir = (*vit) - currentRay.GetOrigin();
359
360                SimpleRay sr(currentRay.GetOrigin(), rayDir, SamplingStrategy::GVS, 1.0f);
361                simpleRays.AddRay(sr); 
362        }
363
364        if (0)
365        {
366                // visualize enlarged triangles
367                VizStruct dummy;
368                dummy.enlargedTriangle = new Polygon3(enlargedTriangle);
369                dummy.originalTriangle = hitTriangle;
370                vizContainer.push_back(dummy);
371        }
372
373        // cast rays to triangle vertices and determine visibility
374        VssRayContainer vssRays;
375
376        // don't cast double rays as we need only the forward rays
377        const bool castDoubleRays = !mPerViewCell;
378        // cannot prune invalid rays because we have to compare adjacent  rays.
379        const bool pruneInvalidRays = false;
380
381
382        //////////
383        //-- fill up simple rays with random rays so we can cast 16
384
385        //const int numRandomRays = 0;
386        const int numRandomRays = 16 - (int)simpleRays.size();
387        ViewCellBasedDistribution vcStrat(*this, mCurrentViewCell);
388
389        GenerateRays(numRandomRays, vcStrat, simpleRays);
390
391        /////////////////////
392
393
394        // keep origin for per view cell sampling
395        CastRays(simpleRays, vssRays, castDoubleRays, pruneInvalidRays);
396
397        const int numBorderSamples = (int)vssRays.size() - numRandomRays;
398
399        // set flags
400        VssRayContainer::const_iterator rit, rit_end = vssRays.end();
401        int i = 0;
402 
403        for (rit = vssRays.begin(); rit != rit_end; ++ rit, ++ i)
404        {
405                if (i < numBorderSamples)
406                        (*rit)->mFlags |= VssRay::BorderSample;
407        }
408
409        int castRays = (int)simpleRays.size();
410
411        VssRayContainer invalidSamples;
412
413        // handle rays
414        EnqueueRays(vssRays, invalidSamples);
415
416    // recursivly subdivide each edge
417        for (int i = 0; i < numBorderSamples; ++ i)
418        {
419                castRays += SubdivideEdge(hitTriangle,
420                                                                  enlargedTriangle[i],
421                                                                  enlargedTriangle[(i + 1) % numBorderSamples],
422                                                                  *vssRays[i],
423                                                                  *vssRays[(i + 1) % numBorderSamples],
424                                                                  currentRay);
425        }
426       
427        mGvsStats.mBorderSamples += castRays;
428
429        CLEAR_CONTAINER(invalidSamples);
430
431        return castRays;
432}
433
434
435bool GvsPreprocessor::GetPassingPoint(const VssRay &currentRay,
436                                                                          const Triangle3 &occluder,
437                                                                          const VssRay &oldRay,
438                                                                          Vector3 &newPoint) const
439{
440        //-- The plane p = (xp, hit(x), hit(xold)) is intersected
441        //-- with the newly found occluder (xold is the previous ray from
442        //-- which x was generated). On the intersecting line, we select a point
443        //-- pnew which lies just outside of the new triangle so the ray
444        //-- just passes through the gap
445
446        const Plane3 plane(currentRay.GetOrigin(),
447                                           currentRay.GetTermination(),
448                                           oldRay.GetTermination());
449       
450        Vector3 pt1, pt2;
451
452        const bool intersects = occluder.GetPlaneIntersection(plane, pt1, pt2);
453
454        if (!intersects)
455        {
456                //cerr << "big error!! no intersection " << pt1 << " " << pt2 << endl;
457                return false;
458        }
459
460        // get the intersection point on the old ray
461        const Plane3 triPlane(occluder.GetNormal(), occluder.mVertices[0]);
462
463        const float t = triPlane.FindT(oldRay.mOrigin, oldRay.mTermination);
464        const Vector3 pt3 = oldRay.mOrigin + t * (oldRay.mTermination - oldRay.mOrigin);
465
466        // Evaluate new hitpoint just outside the triangle
467        const float eps = mEps;
468
469        // the point is chosen to be on the side closer to the original ray
470        if (Distance(pt1, pt3) < Distance(pt2, pt3))
471        {
472                newPoint = pt1 + eps * (pt1 - pt2);
473        }       
474        else
475        {
476                newPoint = pt2 + eps * (pt2 - pt1);
477        }
478
479        //cout << "passing point: " << newPoint << endl << endl;
480        return true;
481}
482
483
484VssRay *GvsPreprocessor::ReverseSampling(const VssRay &currentRay,
485                                                                                 const Triangle3 &hitTriangle,
486                                                                                 const VssRay &oldRay)
487{
488        // get triangle occluding the path to the hit mesh
489        Triangle3 occluder;
490        Intersectable *tObj = currentRay.mTerminationObject;
491
492        // q: why can this happen?
493        if (!tObj)
494                return NULL;
495
496        // other types not implemented yet
497        if (tObj->Type() == Intersectable::TRIANGLE_INTERSECTABLE)
498                occluder = dynamic_cast<TriangleIntersectable *>(tObj)->GetItem();
499        else
500                cout << "not yet implemented" << endl;
501       
502        // get a point which is passing just outside of the occluder
503    Vector3 newPoint;
504
505        // why is there sometimes no intersecton found?
506        if (!GetPassingPoint(currentRay, occluder, oldRay, newPoint))
507                return NULL;
508
509        const Vector3 predicted = CalcPredictedHitPoint(currentRay, hitTriangle, oldRay);
510
511        Vector3 newDir, newOrigin;
512
513        //-- Construct the mutated ray with xnew,
514        //-- dir = predicted(x)- pnew as direction vector
515        newDir = predicted - newPoint;
516
517        // take xnew, p = intersect(viewcell, line(pnew, predicted(x)) as origin ?
518        // difficult to say!!
519        const float offset = 0.5f;
520        newOrigin = newPoint - newDir * offset;
521       
522        //////////////
523        //-- for per view cell sampling, we must check for intersection
524        //-- with the current view cell
525
526    if (mPerViewCell)
527        {
528                // send ray to view cell
529                static Ray ray;
530                ray.Clear();
531                ray.Init(newOrigin, -newDir, Ray::LOCAL_RAY);
532               
533                //cout << "z";
534                // check if ray intersects view cell
535                if (!mCurrentViewCell->CastRay(ray))
536                        return NULL;
537
538                Ray::Intersection &hit = ray.intersections[0];
539       
540                //cout << "q";
541                // the ray starts from the view cell
542                newOrigin = ray.Extrap(hit.mT);
543        }
544
545        const SimpleRay simpleRay(newOrigin, newDir, SamplingStrategy::GVS, 1.0f);
546
547        VssRay *reverseRay =
548                mRayCaster->CastRay(simpleRay, mViewCellsManager->GetViewSpaceBox(), !mPerViewCell);
549
550    ++ mGvsStats.mReverseSamples;
551
552        return reverseRay;
553}
554
555
556int GvsPreprocessor::CastInitialSamples(const int numSamples,
557                                                                                const int sampleType)
558{       
559        const long startTime = GetTime();
560
561        // generate simple rays
562        SimpleRayContainer simpleRays;
563       
564        ViewCellBasedDistribution vcStrat(*this, mCurrentViewCell);
565    GenerateRays(numSamples, vcStrat, simpleRays);
566
567        //cout << "sr: " << simpleRays.size() << endl;
568        // generate vss rays
569        VssRayContainer samples;
570       
571        const bool castDoubleRays = !mPerViewCell;
572        const bool pruneInvalidRays = true;
573       
574        CastRays(simpleRays, samples, castDoubleRays, pruneInvalidRays);
575       
576        VssRayContainer invalidSamples;
577
578        // add to ray queue
579        EnqueueRays(samples, invalidSamples);
580
581        CLEAR_CONTAINER(invalidSamples);
582        //Debug << "generated " <<  numSamples << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
583        return (int)simpleRays.size();
584}
585
586
587void GvsPreprocessor::EnqueueRays(VssRayContainer &samples, VssRayContainer &invalidSamples)
588{
589        // add samples to ray queue
590        VssRayContainer::const_iterator vit, vit_end = samples.end();
591        for (vit = samples.begin(); vit != vit_end; ++ vit)
592        {
593                VssRay *ray = *vit;
594
595                if (!HandleRay(ray))
596                        invalidSamples.push_back(ray);
597        }
598}
599
600
601int GvsPreprocessor::ProcessQueue()
602{
603        int castSamples = 0;
604        ++ mGvsStats.mGvsPass;
605
606        while (!mRayQueue.empty()
607                )//&& (mGvsStats.mTotalSamples + castSamples < mTotalSamples) )
608        {
609                // handle next ray
610                VssRay *ray = mRayQueue.top();
611                mRayQueue.pop();
612               
613                const int newSamples = AdaptiveBorderSampling(*ray);
614
615                castSamples += newSamples;
616
617                //cout << "new samples: " << newSamples << " " << "queue: "  << (int)mRayQueue.size() << endl;
618                delete ray;
619        }
620
621        return castSamples;
622}
623
624
625void ExportVssRays(Exporter *exporter, const VssRayContainer &vssRays)
626{
627        VssRayContainer vcRays, vcRays2, vcRays3;
628
629        VssRayContainer::const_iterator rit, rit_end = vssRays.end();
630
631        // prepare some rays for output
632        for (rit = vssRays.begin(); rit != rit_end; ++ rit)
633        {
634                //const float p = RandomValue(0.0f, (float)vssRays.size());
635
636                if (1)//(p < raysOut)
637                {
638                        if ((*rit)->mFlags & VssRay::BorderSample)
639                        {
640                                vcRays.push_back(*rit);
641                        }
642                        else if ((*rit)->mFlags & VssRay::ReverseSample)
643                        {
644                                vcRays2.push_back(*rit);
645                        }
646                        else
647                        {
648                                vcRays3.push_back(*rit);
649                        }       
650                }
651        }
652
653        //exporter->ExportRays(vcRays, RgbColor(1, 0, 0));
654        //exporter->ExportRays(vcRays2, RgbColor(0, 1, 0));
655        //exporter->ExportRays(vcRays3, RgbColor(1, 1, 1));
656}
657
658
659//void GvsPreprocessor::VisualizeViewCell(ViewCell *vc)
660void GvsPreprocessor::VisualizeViewCell(const ObjectContainer &objects)
661{
662    Intersectable::NewMail();
663
664        Material m;
665       
666        char str[64]; sprintf(str, "pass%06d.wrl", mProcessedViewCells);
667
668        Exporter *exporter = Exporter::GetExporter(str);
669        if (!exporter)
670                return;
671
672        /*ObjectPvsIterator pit = vc->GetPvs().GetIterator();
673
674        // output PVS of view cell
675        while (pit.HasMoreEntries())
676        {               
677                ObjectPvsEntry entry = pit.Next();
678
679                Intersectable *intersect = entry.mObject;
680               
681                if (intersect->Mailed())
682                        continue;
683               
684                intersect->Mail();
685                //m.mDiffuseColor = RgbColor(1, 0, 0);
686                m = RandomMaterial();
687                exporter->SetForcedMaterial(m);
688
689                exporter->ExportIntersectable(intersect);
690        }*/
691        ObjectContainer::const_iterator oit, oit_end = objects.end();
692
693        for (oit = objects.begin(); oit != oit_end; ++ oit)
694        {
695                Intersectable *intersect = *oit;
696               
697                m = RandomMaterial();
698                exporter->SetForcedMaterial(m);
699                exporter->ExportIntersectable(intersect);
700        }
701
702        cout << "vssrays: " << (int)mVssRays.size() << endl;
703        ExportVssRays(exporter, mVssRays);
704
705        /////////////////
706        //-- export view cell geometry
707
708        exporter->SetWireframe();
709
710        m.mDiffuseColor = RgbColor(0, 1, 0);
711        exporter->SetForcedMaterial(m);
712
713        //mViewCellsManager->ExportViewCellGeometry(exporter, vc, NULL, NULL);
714        //mViewCellsManager->ExportViewCellGeometry(exporter, mCurrentViewCell, NULL, NULL);
715
716        AxisAlignedBox3 bbox = mCurrentViewCell->GetMesh()->mBox;
717        exporter->ExportBox(bbox);
718        //exporter->SetFilled();
719
720        DEL_PTR(exporter);
721}
722
723
724void GvsPreprocessor::VisualizeViewCells()
725{
726        char str[64]; sprintf(str, "tmp/pass%06d_%04d-", mProcessedViewCells, mPass);
727                       
728        // visualization
729        if (mGvsStats.mPassContribution > 0)
730        {
731                const bool exportRays = true;
732                const bool exportPvs = true;
733
734                mViewCellsManager->ExportSingleViewCells(mObjects,
735                                                                                                 10,
736                                                                                                 false,
737                                                                                                 exportPvs,
738                                                                                                 exportRays,
739                                                                                                 1000,
740                                                                                                 str);
741        }
742
743        // remove pass samples
744        ViewCellContainer::const_iterator vit, vit_end = mViewCellsManager->GetViewCells().end();
745
746        for (vit = mViewCellsManager->GetViewCells().begin(); vit != vit_end; ++ vit)
747        {
748                (*vit)->DelRayRefs();
749        }
750}
751
752
753void GvsPreprocessor::ProcessViewCell()
754{
755        //Intersectable::NewMail();
756        // compute direct intersections with view cell
757        IntersectWithViewCell();
758
759        mGvsStats.mPerViewCellSamples = 0;
760        int oldContribution = mGvsStats.mTotalContribution;
761        int passSamples = 0;
762
763        //while (mGvsStats.mPerViewCellSamples < mTotalSamples)
764        while (1)
765        {
766                // Ray queue empty =>
767                // cast a number of uniform samples to fill ray queue
768                int newSamples = CastInitialSamples(mInitialSamples, mSamplingType);
769
770                if (!mOnlyRandomSampling)
771                        newSamples += ProcessQueue();
772
773                passSamples += newSamples;
774                mGvsStats.mPerViewCellSamples += newSamples;
775                //cout << "here2 " << passSamples % (mSamplesPerPass + 1) << endl;
776
777                if (passSamples >= mSamplesPerPass)
778                {
779                        ++ mPass;
780
781                        mGvsStats.mPassContribution = mGvsStats.mTotalContribution - oldContribution;
782
783                        ////////
784                        //-- stats
785
786                        mGvsStats.mPass = mPass;
787
788                        cout << "\nPass " << mPass << " #samples: " << mGvsStats.mPerViewCellSamples << endl;
789                        cout << "contribution=" << mGvsStats.mPassContribution << " (of " << mMinContribution << ")" << endl;
790
791                        // termination criterium
792                        if (mGvsStats.mPassContribution < mMinContribution)
793                        {
794                                break;
795                        }
796
797                        // reset
798                        oldContribution = mGvsStats.mTotalContribution;
799                        mGvsStats.mPassContribution = 0;
800                        passSamples = 0;
801                }
802        }
803}
804
805
806void GvsPreprocessor::CompileViewCellsList()
807{
808        while ((int)mViewCells.size() < mMaxViewCells)
809    {
810                if (0)
811                {
812                        mViewCells.push_back(mViewCellsManager->GetViewCell((int)mViewCells.size()));
813                        continue;
814                }
815               
816                // HACK
817                const int tries = 10000;
818                int i = 0;
819
820                for (i = 0; i < tries; ++ i)
821                {
822                        const int idx = (int)RandomValue(0.0f, (float)mViewCellsManager->GetNumViewCells() - 0.5f);
823       
824                        ViewCell *viewCell = mViewCellsManager->GetViewCell(idx);
825
826                        if (!viewCell->Mailed())
827                        {
828                                viewCell->Mail();
829                                break;
830                        }
831
832                        mViewCells.push_back(viewCell);
833                }
834
835                if (i == tries)
836                {
837                        cerr << "big error! no view cell found" << endl;
838                        return;
839                }
840        }
841}
842
843
844void GvsPreprocessor::IntersectWithViewCell()
845{
846        mCurrentViewCell->GetMesh()->ComputeBoundingBox();
847        AxisAlignedBox3 box = mCurrentViewCell->GetMesh()->mBox;
848        //cout << "box: " << box << endl;
849        vector<KdLeaf *> leaves;
850
851        mKdTree->GetBoxIntersections(box, leaves);
852
853        vector<KdLeaf *>::const_iterator lit, lit_end = leaves.end();
854
855        for (lit = leaves.begin(); lit != leaves.end(); ++ lit)
856        {
857                KdLeaf *leaf = *lit;
858                ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
859
860                for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
861                {
862                        TriangleIntersectable *triObj = dynamic_cast<TriangleIntersectable *>(*oit);
863
864                        if (box.Intersects(triObj->GetItem()))
865                        {
866                                if (!triObj->mCounter)
867                                {
868                                        triObj->mCounter = 1;
869                                        mTrianglePvs.push_back(triObj);
870                                }
871                        }
872                }
873        }
874}
875
876
877void GvsPreprocessor::PerViewCellComputation()
878{
879        // hack: reset counter
880        ObjectContainer::const_iterator oit, oit_end = mObjects.end();
881
882        for (oit = mObjects.begin(); oit != oit_end; ++ oit)
883        {
884                (*oit)->mCounter = 0;
885        }
886
887        while (NextViewCell())
888        {
889                cout << "\n***********************\n"
890                         << "processing view cell " << mProcessedViewCells
891                         << " (id: " << mCurrentViewCell->GetId() << ")" << endl;
892
893                // compute the pvs of the current view cell
894                ProcessViewCell();
895
896                //mGvsStats.mTrianglePvs = mCurrentViewCell->GetPvs().GetSize();
897                mGvsStats.mTrianglePvs = (int)mTrianglePvs.size();
898
899                ObjectContainer objectPvs;
900
901                // exchange triangle pvs with objects
902                //UpdatePvs(mCurrentViewCell);
903                GetObjectPvs(objectPvs);
904
905                cout << "triangle pvs of " << (int)mTrianglePvs.size() << " was converted to object pvs of " << (int)objectPvs.size() << endl;
906
907                ////////
908                //-- stats
909               
910                mGvsStats.mViewCells = mProcessedViewCells;//mPass;
911                //mGvsStats.mPerViewCellPvs = mCurrentViewCell->GetPvs().GetSize();
912                mGvsStats.mPerViewCellPvs = (int)mTrianglePvs.size();
913
914                mGvsStats.mTotalPvs += mGvsStats.mPerViewCellPvs;
915                mGvsStats.mTotalSamples += mGvsStats.mPerViewCellSamples;
916
917                mGvsStats.Stop();
918                mGvsStats.Print(mGvsStatsStream);
919
920                mTrianglePvs.clear();
921
922                if (GVS_DEBUG)
923                {
924                        //VisualizeViewCell(mCurrentViewCell);
925                        VisualizeViewCell(objectPvs);
926                        CLEAR_CONTAINER(mVssRays);
927                }
928
929                // is this really necessary?
930                ClearRayQueue();
931        }
932}
933
934
935void GvsPreprocessor::UpdatePvs(ViewCell *currentViewCell)
936{
937        ObjectPvs newPvs;
938        BvhLeaf::NewMail();
939
940        ObjectPvsIterator pit = currentViewCell->GetPvs().GetIterator();
941
942        // output PVS of view cell
943        while (pit.HasMoreEntries())
944        {               
945                ObjectPvsEntry entry = pit.Next();
946
947                Intersectable *intersect = entry.mObject;
948       
949                BvhLeaf *bv = intersect->mBvhLeaf;
950
951                if (!bv || bv->Mailed())
952                        continue;
953               
954                bv->Mail();
955
956                //m.mDiffuseColor = RgbColor(1, 0, 0);
957                newPvs.AddSampleDirty(bv, 1.0f);
958        }
959
960        newPvs.SimpleSort();
961
962        currentViewCell->SetPvs(newPvs);
963}
964
965 
966void GvsPreprocessor::GetObjectPvs(ObjectContainer &objectPvs) const
967{
968        BvhLeaf::NewMail();
969
970        ObjectContainer::const_iterator oit, oit_end = mTrianglePvs.end();
971
972        for (oit = mTrianglePvs.begin(); oit != oit_end; ++ oit)
973        {
974                Intersectable *intersect = *oit;
975       
976                BvhLeaf *bv = intersect->mBvhLeaf;
977
978                if (!bv || bv->Mailed())
979                        continue;
980               
981                bv->Mail();
982
983                objectPvs.push_back(bv);
984                // hack: reset counter
985                (*oit)->mCounter = 0;
986        }
987}
988
989
990void GvsPreprocessor::GlobalComputation()
991{
992        int passSamples = 0;
993        int oldContribution = 0;
994
995        while (mGvsStats.mTotalSamples < mTotalSamples)
996        {
997                // Ray queue empty =>
998                // cast a number of uniform samples to fill ray queue
999                int newSamples = CastInitialSamples(mInitialSamples, mSamplingType);
1000
1001                if (!mOnlyRandomSampling)
1002                        newSamples += ProcessQueue();
1003
1004                passSamples += newSamples;
1005                mGvsStats.mTotalSamples += newSamples;
1006
1007                if (passSamples % (mSamplesPerPass + 1) == mSamplesPerPass)
1008                {
1009                        ++ mPass;
1010
1011                        mGvsStats.mPassContribution = mGvsStats.mTotalContribution - oldContribution;
1012
1013                        ////////
1014                        //-- stats
1015
1016                        //cout << "\nPass " << mPass << " #samples: " << mGvsStats.mTotalSamples << " of " << mTotalSamples << endl;
1017                        mGvsStats.mPass = mPass;
1018                        mGvsStats.Stop();
1019                        mGvsStats.Print(mGvsStatsStream);
1020
1021                        // reset
1022                        oldContribution = mGvsStats.mTotalContribution;
1023                        mGvsStats.mPassContribution = 0;
1024                        passSamples = 0;
1025
1026                        if (GVS_DEBUG)
1027                                VisualizeViewCells();
1028                }
1029        }
1030}
1031
1032
1033bool GvsPreprocessor::ComputeVisibility()
1034{
1035        cout << "Gvs Preprocessor started\n" << flush;
1036        const long startTime = GetTime();
1037
1038        //Randomize(0);
1039       
1040        mGvsStats.Reset();
1041        mGvsStats.Start();
1042
1043        if (!mLoadViewCells)
1044        {       
1045                /// construct the view cells from the scratch
1046                ConstructViewCells();
1047                // reset pvs already gathered during view cells construction
1048                mViewCellsManager->ResetPvs();
1049                cout << "finished view cell construction" << endl;
1050        }
1051        else if (0)
1052        {       
1053                //-- test successful view cells loading by exporting them again
1054                VssRayContainer dummies;
1055                mViewCellsManager->Visualize(mObjects, dummies);
1056                mViewCellsManager->ExportViewCells("test.xml.gz", mViewCellsManager->GetExportPvs(), mObjects);
1057        }
1058
1059        mGvsStats.Stop();
1060        mGvsStats.Print(mGvsStatsStream);
1061
1062        if (mPerViewCell)
1063        {
1064                // list of view cells to compute
1065                CompileViewCellsList();
1066
1067                PerViewCellComputation();
1068        }
1069        else
1070        {
1071                GlobalComputation();
1072        }
1073
1074        cout << "cast " << 2 * mGvsStats.mTotalSamples / (1e3f * TimeDiff(startTime, GetTime())) << "M rays/s" << endl;
1075
1076        if (GVS_DEBUG)
1077        {
1078                Visualize();
1079                CLEAR_CONTAINER(mVssRays);
1080        }
1081
1082        return true;
1083}
1084
1085
1086void GvsPreprocessor::Visualize()
1087{
1088        Exporter *exporter = Exporter::GetExporter("gvs.wrl");
1089
1090        if (!exporter)
1091                return;
1092       
1093        vector<VizStruct>::const_iterator vit, vit_end = vizContainer.end();
1094       
1095        for (vit = vizContainer.begin(); vit != vit_end; ++ vit)
1096        {
1097                exporter->SetWireframe();
1098                exporter->ExportPolygon((*vit).enlargedTriangle);
1099                //Material m;
1100                exporter->SetFilled();
1101                Polygon3 poly = Polygon3((*vit).originalTriangle);
1102                exporter->ExportPolygon(&poly);
1103        }
1104
1105        VssRayContainer::const_iterator rit, rit_end = mVssRays.end();
1106
1107        for (rit = mVssRays.begin(); rit != rit_end; ++ rit)
1108        {
1109                Intersectable *obj = (*rit)->mTerminationObject;
1110                exporter->ExportIntersectable(obj);
1111        }
1112
1113        ExportVssRays(exporter, mVssRays);
1114       
1115        delete exporter;
1116}
1117
1118
1119void GvsStatistics::Print(ostream &app) const
1120{
1121        app << "#Pass\n" << mPass << endl;
1122        app << "#ViewCellId\n" << mViewCellId << endl;
1123        app << "#Time\n" << Time() << endl;
1124        app << "#TotalSamples\n" << mTotalSamples << endl;
1125        app << "#ScDiff\n" << mPassContribution << endl;
1126        app     << "#SamplesContri\n" << mTotalContribution << endl;
1127        app << "#ReverseSamples\n" << mReverseSamples << endl;
1128        app << "#BorderSamples\n" << mBorderSamples << endl;           
1129        app << "#GvsRuns\n" << mGvsPass << endl;
1130        app << "#ViewCells\n" << mViewCells << endl;
1131        app << "#TotalPvs\n" << mTotalPvs << endl;
1132        app << "#PerViewCellPvs\n" << mPerViewCellPvs << endl;
1133        app << "#TrianglePvs\n" << mTrianglePvs << endl;
1134        app << "#RaysPerSec\n" << RaysPerSec() << endl;
1135        app << "#PerViewCellSamples\n" << mPerViewCellSamples << endl << endl;
1136}
1137
1138
1139}
Note: See TracBrowser for help on using the repository browser.