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

Revision 2633, 32.4 KB checked in by mattausch, 16 years ago (diff)

revived hash pvs

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