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

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