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

Revision 2615, 32.1 KB checked in by mattausch, 16 years ago (diff)

did some stuff for the visualization

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