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

Revision 2116, 31.7 KB checked in by mattausch, 17 years ago (diff)

implemented hashpvs

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