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

Revision 1524, 11.7 KB checked in by mattausch, 18 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
12
13namespace GtpVisibilityPreprocessor
14{
15 
16struct VizStruct
17{
18        Polygon3 *enlargedTriangle;
19        Triangle3 originalTriangle;
20        VssRay *ray;
21};
22
23static vector<VizStruct> vizContainer;
24
25GvsPreprocessor::GvsPreprocessor(): Preprocessor(), mSamplingType(0)
26{
27        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.totalSamples", mTotalSamples);
28        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.initialSamples", mInitialSamples);
29        Environment::GetSingleton()->GetIntValue("GvsPreprocessor.samplesPerPass", mSamplesPerPass);
30        Environment::GetSingleton()->GetFloatValue("GvsPreprocessor.epsilon", mEps);
31        Environment::GetSingleton()->GetFloatValue("GvsPreprocessor.threshold", mThreshold);   
32
33        Debug << "Gvs preprocessor options" << endl;
34        Debug << "number of total samples: " << mTotalSamples << endl;
35        Debug << "number of initial samples: " << mInitialSamples << endl;
36        Debug << "number of samples per pass: " << mSamplesPerPass << endl;
37        Debug << "threshold: " << mThreshold << endl;
38        Debug << "eps: " << mEps << endl;
39
40        mStats.open("gvspreprocessor.log");
41}
42
43
44bool GvsPreprocessor::CheckDiscontinuity(const VssRay &currentRay,
45                                                                                 const Triangle3 &hitTriangle,
46                                                                                 const VssRay &oldRay)
47{
48        const float dist = Magnitude(oldRay.GetDir());
49        const float newDist = Magnitude(currentRay.GetDir());
50 
51#if 0
52        if ((dist - newDist) > mThresHold)
53#else // rather take relative distance
54        if ((dist / newDist) > mThreshold)
55#endif
56        {
57                VssRay *newRay = ReverseSampling(currentRay, hitTriangle, oldRay);
58                if (!HandleRay(newRay))
59                        delete newRay;
60
61                return true;
62        }
63
64        return false;
65}
66
67
68bool GvsPreprocessor::HandleRay(VssRay *vssRay)
69{
70        const int oldContri = vssRay->mPvsContribution;
71        mViewCellsManager->ComputeSampleContribution(*vssRay, true, false);
72
73         // some pvs contribution for this ray?
74        if ((vssRay->mPvsContribution - oldContri) > 0)
75        {
76                //cout << "h";
77                mRayQueue.push(vssRay);
78                mVssRays.push_back(new VssRay(*vssRay));
79                return true;
80        }
81
82        return false;
83}
84
85
86/** Creates 3 new vertices for triangle vertex with specified index.
87*/
88static void CreateNewVertices(VertexContainer &vertices,
89                                                          const Triangle3 &hitTriangle,
90                                                          const VssRay &ray,
91                                                          const int index,
92                                                          const float eps)
93{
94        const int indexU = (index + 1) % 3;
95        const int indexL = (index == 0) ? 2 : index - 1;
96
97        const Vector3 a = hitTriangle.mVertices[index] - ray.GetOrigin();
98        const Vector3 b = hitTriangle.mVertices[indexU] - hitTriangle.mVertices[index];
99        const Vector3 c = hitTriangle.mVertices[index] - hitTriangle.mVertices[indexL];
100       
101        const float len = Magnitude(a);
102
103        const Vector3 dir1 = Normalize(CrossProd(a, b)); //N((pi-xp)×(pi+1- pi));
104        const Vector3 dir2 = Normalize(CrossProd(a, c)); // N((pi-xp)×(pi- pi-1))
105        const Vector3 dir3 = DotProd(dir2, dir1) > 0 ? // N((pi-xp)×di,i-1+di,i+1×(pi-xp))
106                Normalize(dir2 + dir1) : Normalize(CrossProd(a, dir1) + CrossProd(dir2, a));
107
108        // compute the new three hit points
109        // pi, i + 1:  pi+ e·|pi-xp|·di, j
110        const Vector3 pt1 = hitTriangle.mVertices[index] + eps * len * dir1;
111        // pi, i - 1:  pi+ e·|pi-xp|·di, j
112    const Vector3 pt2 = hitTriangle.mVertices[index] + eps * len * dir2;
113        // pi, i:  pi+ e·|pi-xp|·di, j
114        const Vector3 pt3 = hitTriangle.mVertices[index] + eps * len * dir3;
115       
116        vertices.push_back(pt2);
117        vertices.push_back(pt3);
118        vertices.push_back(pt1);
119}
120
121
122void GvsPreprocessor::EnlargeTriangle(VertexContainer &vertices,
123                                                                          const Triangle3 &hitTriangle,
124                                                                          const VssRay &ray)
125{
126        CreateNewVertices(vertices, hitTriangle, ray, 0, mEps);
127        CreateNewVertices(vertices, hitTriangle, ray, 1, mEps);
128        CreateNewVertices(vertices, hitTriangle, ray, 2, mEps);
129}
130
131
132static Vector3 CalcPredictedHitPoint(const VssRay &newRay,
133                                                                         const Triangle3 &hitTriangle,
134                                                                         const VssRay &oldRay)
135{
136        Plane3 plane(hitTriangle.GetNormal(), hitTriangle.mVertices[0]);
137
138        const Vector3 hitPt =
139                plane.FindIntersection(newRay.mTermination, newRay.mOrigin);
140       
141        return hitPt;
142}
143
144
145static bool EqualVisibility(const VssRay &a, const VssRay &b)
146{
147        return a.mTerminationObject == b.mTerminationObject;
148}
149
150
151int GvsPreprocessor::SubdivideEdge(const Triangle3 &hitTriangle,
152                                                                   const Vector3 &p1,
153                                                                   const Vector3 &p2,
154                                                                   const VssRay &x,
155                                                                   const VssRay &y,
156                                                                   const VssRay &oldRay)
157{
158        // the predicted hitpoint expects to hit the same mesh again
159        const Vector3 predictedHitX = CalcPredictedHitPoint(x, hitTriangle, oldRay);
160        const Vector3 predictedHitY = CalcPredictedHitPoint(y, hitTriangle, oldRay);
161
162        CheckDiscontinuity(x, hitTriangle, oldRay);
163        CheckDiscontinuity(y, hitTriangle, oldRay);
164
165        if (EqualVisibility(x, y))
166        {
167                return 2;
168        }
169        else
170        {
171                const Vector3 p = (p1 + p2) * 0.5f;
172                SimpleRay sray(oldRay.mOrigin, p - oldRay.mOrigin);
173       
174                VssRay *newRay = mRayCaster->CastSingleRay(sray.mOrigin, sray.mDirection, 1, mViewSpaceBox);
175
176                if (!newRay) return 0;
177                const bool enqueued = HandleRay(newRay);
178               
179                const int s1 = SubdivideEdge(hitTriangle, p1, p, x, *newRay, oldRay);
180                const int s2 = SubdivideEdge(hitTriangle, p, p2, *newRay, y, oldRay);
181                return s1 + s2;
182               
183                if (!enqueued)
184                        delete newRay;
185        }
186}
187
188
189int GvsPreprocessor::AdaptiveBorderSampling(const VssRay &currentRay)
190{
191        cout << "a";
192        Intersectable *tObj = currentRay.mTerminationObject;
193        Triangle3 hitTriangle;
194
195        // other types not implemented yet
196        if (tObj->Type() == Intersectable::TRIANGLE_INTERSECTABLE)
197        {
198                hitTriangle = dynamic_cast<TriangleIntersectable *>(tObj)->GetItem();
199        }
200        else
201        {
202                cout << "not yet implemented" << endl;
203        }
204
205        VertexContainer enlargedTriangle;
206       
207        /// create 3 new hit points for each vertex
208        EnlargeTriangle(enlargedTriangle, hitTriangle, currentRay);
209       
210        /// create rays from sample points and handle them
211        SimpleRayContainer simpleRays;
212        simpleRays.reserve(9);
213
214        VertexContainer::const_iterator vit, vit_end = enlargedTriangle.end();
215
216        for (vit = enlargedTriangle.begin(); vit != vit_end; ++ vit)
217        {
218                const Vector3 rayDir = (*vit) - currentRay.GetOrigin();
219                simpleRays.push_back(SimpleRay(currentRay.GetOrigin(), rayDir));
220        }
221
222        VizStruct dummy;
223        dummy.enlargedTriangle = new Polygon3(enlargedTriangle);
224        dummy.originalTriangle = hitTriangle;
225        //dummy.ray = new VssRay(currentRay);
226        vizContainer.push_back(dummy);
227
228        // cast rays to triangle vertices and determine visibility
229        VssRayContainer vssRays;
230        CastRays(simpleRays, vssRays, false);
231cout << "here211 " << simpleRays.size() << " " << vssRays.size() << endl;
232        // add to ray queue
233        EnqueueRays(vssRays);
234        const int n = (int)enlargedTriangle.size();
235       
236#if 1
237    // recursivly subdivide each edge
238        for (int i = 0; i < n; ++ i)
239        {
240                SubdivideEdge(
241                        hitTriangle,
242                        enlargedTriangle[i],
243                        enlargedTriangle[(i + 1) % n],
244                        *vssRays[i],
245                        *vssRays[(i + 1) % n],
246                        currentRay);
247        }
248#endif
249        return (int)vssRays.size();
250}
251
252
253static Vector3 GetPassingPoint(const VssRay &currentRay,
254                                                                                 const Triangle3 &hitTriangle,
255                                                                                 const VssRay &oldRay)
256{
257        // intersect triangle plane with plane spanned by current samples
258        Plane3 plane(currentRay.GetOrigin(), currentRay.GetTermination(), oldRay.GetTermination());
259        Plane3 triPlane(hitTriangle.GetNormal(), hitTriangle.mVertices[0]);
260
261        SimpleRay intersectLine = GetPlaneIntersection(plane, triPlane);
262
263        // Evaluate new hitpoint just outside the triangle
264        const float factor = 0.95f;
265        float t = triPlane.FindT(intersectLine);
266
267        const Vector3 newPoint = intersectLine.mOrigin + t * factor * intersectLine.mDirection;
268
269        return newPoint;
270}
271
272
273VssRay *GvsPreprocessor::ReverseSampling(const VssRay &currentRay,
274                                                                                 const Triangle3 &hitTriangle,
275                                                                                 const VssRay &oldRay)
276{
277        cout << "r" << endl;
278        //-- The plane p = (xp, hit(x), hit(xold)) is intersected
279        //-- with the newly found triangle (xold is the previous ray from
280        //-- which x was generated). On the intersecting line, we select a point
281        //-- pnew which lies just outside of the new triangle so the ray
282        //-- just passes by inside the gap
283    const Vector3 newPoint = GetPassingPoint(currentRay, hitTriangle, oldRay);
284        const Vector3 predicted = CalcPredictedHitPoint(currentRay, hitTriangle, oldRay);
285
286        //-- Construct the mutated ray with xnew,dir = predicted(x)- pnew
287        //-- as direction vector
288        const Vector3 newDir = predicted - newPoint ;
289        // take xnew,p = intersect(viewcell, line(pnew, predicted(x)) as origin ?
290        // difficult to say!!
291        const Vector3 newOrigin = newDir * -5000.0f;
292
293        return new VssRay(currentRay);
294}
295
296
297int GvsPreprocessor::CastInitialSamples(const int numSamples,
298                                                                                const int sampleType)
299{       
300        const long startTime = GetTime();
301
302        // generate simple rays
303        SimpleRayContainer simpleRays;
304        GenerateRays(numSamples, sampleType, simpleRays);
305       
306        // generate vss rays
307        VssRayContainer samples;
308        CastRays(simpleRays, samples, true);
309       
310        // add to ray queue
311        EnqueueRays(samples);
312
313        Debug << "generated " <<  numSamples << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
314
315        return (int)samples.size();
316}
317
318
319void GvsPreprocessor::EnqueueRays(VssRayContainer &samples)
320{
321        // add samples to ray queue
322        VssRayContainer::const_iterator vit, vit_end = samples.end();
323       
324        for (vit = samples.begin(); vit != vit_end; ++ vit)
325        {
326                HandleRay(*vit);
327        }
328}
329
330
331int GvsPreprocessor::Pass()
332{
333        int castSamples = 0;
334        const int mSampleType = 0;
335        while (castSamples < mSamplesPerPass)
336        {
337                // Ray queue empty =>
338                // cast a number of uniform samples to fill ray Queue
339                CastInitialSamples(mInitialSamples, mSampleType);
340
341                const int gvsSamples = ProcessQueue();
342#if 0
343                castSamples += gvsSamples;
344#else
345                castSamples += mInitialSamples;
346#endif
347                cout << "\nround finished, cast " << castSamples << " of " << mSamplesPerPass << endl;
348        }
349
350        return castSamples;
351}
352
353
354int GvsPreprocessor::ProcessQueue()
355{
356        int castSamples = 0;
357
358        while (!mRayQueue.empty())
359        {
360                // handle next ray
361                VssRay *ray = mRayQueue.top();
362                mRayQueue.pop();
363               
364                castSamples += AdaptiveBorderSampling(*ray);
365
366                delete ray;
367        }
368
369        return castSamples;
370}
371
372
373bool GvsPreprocessor::ComputeVisibility()
374{
375        Randomize(0);
376        const long startTime = GetTime();
377       
378        mViewSpaceBox = mKdTree->GetBox();
379        cout << "Gvs Preprocessor started\n" << flush;
380       
381        if (!mLoadViewCells)
382        {       /// construct the view cells from the scratch
383                ConstructViewCells(mViewSpaceBox);
384                cout << "view cells loaded" << endl;
385        }
386
387        int castSamples = 0;
388
389        while (castSamples < mTotalSamples)
390        {
391                const int passSamples = Pass();
392                castSamples += passSamples;
393               
394                ////////
395                //-- stats
396                cout << "+";
397                cout << "\nsamples cast " << passSamples << " (=" << castSamples << " of " << mTotalSamples << ")" << endl;
398                //mVssRays.PrintStatistics(mStats);
399                mStats << "#Time\n" << TimeDiff(startTime, GetTime())*1e-3 << endl
400                           << "#TotalSamples\n" << castSamples << endl;
401
402                mViewCellsManager->PrintPvsStatistics(mStats);
403                // ComputeRenderError();
404        }
405
406        Visualize();   
407        return true;
408}
409
410
411void GvsPreprocessor::Visualize()
412{
413        Exporter *exporter = Exporter::GetExporter("gvs.wrl");
414
415        if (!exporter)
416                return;
417       
418        vector<VizStruct>::const_iterator vit, vit_end = vizContainer.end();
419        for (vit = vizContainer.begin(); vit != vit_end; ++ vit)
420        {
421                exporter->SetWireframe();
422                exporter->ExportPolygon((*vit).enlargedTriangle);
423                //Material m;
424                exporter->SetFilled();
425                Polygon3 poly = Polygon3((*vit).originalTriangle);
426                exporter->ExportPolygon(&poly);
427        }
428
429        exporter->ExportRays(mVssRays);
430        delete exporter;
431}
432
433}
Note: See TracBrowser for help on using the repository browser.