source: trunk/VUT/GtpVisibilityPreprocessor/src/GlRenderer.cpp @ 512

Revision 512, 16.2 KB checked in by mattausch, 19 years ago (diff)
  • Property svn:executable set to *
Line 
1#include "Mesh.h"
2#include "GlRenderer.h"
3#include "ViewCellsManager.h"
4#include "SceneGraph.h"
5#include "Pvs.h"
6#include "Viewcell.h"
7#include "Beam.h"
8#include <GL/glext.h>
9#include <Cg/cg.h>
10#include <Cg/cgGL.h>
11
12static CGcontext sCgContext = NULL;
13static CGprogram sCgFragmentProgram = NULL;
14
15static CGparameter sCgKdParam = NULL;
16static CGparameter sCgModelViewProjParam = NULL;
17
18
19static CGprofile sCgFragmentProfile = CG_PROFILE_FP30;
20
21GLuint depthMap;
22const int depthMapSize = 512;
23
24GlRendererWidget *rendererWidget = NULL;
25
26#ifdef _WIN32
27PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV;
28PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV;
29PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV;
30PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV;
31#endif
32
33GlRenderer::GlRenderer(SceneGraph *sceneGraph,
34                                           ViewCellsManager *viewCellsManager):
35  Renderer(sceneGraph, viewCellsManager)
36{
37  mSceneGraph->CollectObjects(&mObjects);
38  mViewPoint = mSceneGraph->GetBox().Center();
39  mViewDirection = Vector3(0,0,1);
40  //  timerId = startTimer(10);
41  mFrame = 0;
42  mWireFrame = false;
43}
44
45GlRenderer::~GlRenderer()
46{
47}
48
49void
50GlRenderer::RenderIntersectable(Intersectable *object)
51{
52
53  SetupFalseColor(object->mId);
54
55  switch (object->Type()) {
56  case Intersectable::MESH_INSTANCE:
57        RenderMeshInstance((MeshInstance *)object);
58        break;
59  default:
60        cerr<<"Rendering this object not yet implemented\n";
61        break;
62  }
63}
64
65
66void
67GlRenderer::RenderMeshInstance(MeshInstance *mi)
68{
69  RenderMesh(mi->GetMesh());
70}
71
72void
73GlRenderer::SetupFalseColor(const int id)
74{
75  // swap bits of the color
76 
77  glColor3ub(id&255, (id>>8)&255, (id>>16)&255);
78}
79
80void
81GlRenderer::SetupMaterial(Material *m)
82{
83  if (m)
84        glColor3fv(&(m->mDiffuseColor.r));
85  else
86        glColor3f(1.0f, 1.0f, 1.0f);
87}
88
89void
90GlRenderer::RenderMesh(Mesh *mesh)
91{
92  int i = 0;
93
94  if (!mUseFalseColors)
95        SetupMaterial(mesh->mMaterial);
96 
97  for (i=0; i < mesh->mFaces.size(); i++) {
98        if (mWireFrame)
99          glBegin(GL_LINE_LOOP);
100        else
101          glBegin(GL_POLYGON);
102
103        Face *face = mesh->mFaces[i];
104        for (int j = 0; j < face->mVertexIndices.size(); j++) {
105          glVertex3fv(&mesh->mVertices[face->mVertexIndices[j]].x);
106        }
107        glEnd();
108  }
109}
110       
111void
112GlRenderer::InitGL()
113{
114  glMatrixMode(GL_PROJECTION);
115  glLoadIdentity();
116 
117  glMatrixMode(GL_MODELVIEW);
118  glLoadIdentity();
119
120  glEnable(GL_CULL_FACE);
121  glShadeModel(GL_FLAT);
122  glEnable(GL_DEPTH_TEST);
123  glEnable(GL_CULL_FACE);
124 
125  glGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC)
126        wglGetProcAddress("glGenOcclusionQueriesNV");
127  glBeginOcclusionQueryNV = (PFNGLBEGINOCCLUSIONQUERYNVPROC)
128        wglGetProcAddress("glBeginOcclusionQueryNV");
129  glEndOcclusionQueryNV = (PFNGLENDOCCLUSIONQUERYNVPROC)
130        wglGetProcAddress("glEndOcclusionQueryNV");
131  glGetOcclusionQueryuivNV = (PFNGLGETOCCLUSIONQUERYUIVNVPROC)
132        wglGetProcAddress("glGetOcclusionQueryuivNV");
133
134  // initialise second depth buffer texture
135  glGenTextures(1, &depthMap);
136  glBindTexture(GL_TEXTURE_2D, depthMap);
137 
138  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthMapSize,
139                           depthMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
140  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
141  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
142  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
143  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
144
145  // cg initialization
146  sCgContext = cgCreateContext();
147
148  sCgFragmentProgram = cgCreateProgramFromFile(sCgContext,             
149                                                                                           CG_SOURCE, "dual_depth.cg",
150                                                                                           sCgFragmentProfile,
151                                                                                           NULL,
152                                                                                           NULL);
153}
154
155
156
157void
158GlRenderer::SetupProjection(const int w, const int h)
159{
160  glViewport(0, 0, w, h);
161  glMatrixMode(GL_PROJECTION);
162  glLoadIdentity();
163  gluPerspective(70.0, 1.0, 0.1, 2.0*Magnitude(mSceneGraph->GetBox().Diagonal()));
164  glMatrixMode(GL_MODELVIEW);
165}
166
167void
168GlRenderer::SetupCamera()
169{
170  Vector3 target = mViewPoint + mViewDirection;
171  Vector3 up(0,1,0);
172 
173  glLoadIdentity();
174  gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z,
175                        target.x, target.y, target.z,
176                        up.x, up.y, up.z);
177}
178
179void
180GlRenderer::RandomViewPoint()
181{
182  Vector3 pVector = Vector3(halton.GetNumber(1),
183                                                        halton.GetNumber(2),
184                                                        halton.GetNumber(3));
185 
186  Vector3 dVector = Vector3(2*M_PI*halton.GetNumber(4),
187                                                        M_PI*halton.GetNumber(5),
188                                                        0.0f);
189 
190  mViewPoint = mSceneGraph->GetBox().GetPoint(pVector);
191 
192  mViewDirection = Normalize(Vector3(sin(dVector.x),
193                                                                         //                                                                      cos(dVector.y),
194                                                                         0.0f,
195                                                                         cos(dVector.x)));
196
197  halton.GenerateNext();
198}
199
200
201float
202GlRenderer::GetPixelError()
203{
204  float pErrorPixels = -1.0f;
205
206  glReadBuffer(GL_BACK);
207 
208  mUseFalseColors = true;
209
210  SetupCamera();
211  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
212  glEnable( GL_CULL_FACE );
213 
214  RenderScene();
215
216  // now check whether any backfacing polygon would pass the depth test
217  static int query = -1;
218  if (query == -1)
219        glGenOcclusionQueriesNV(1, (unsigned int *)&query);
220 
221  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
222  glDepthMask(GL_FALSE);
223  glDisable( GL_CULL_FACE );
224 
225  glBeginOcclusionQueryNV(query);
226 
227  RenderScene();
228 
229  glEndOcclusionQueryNV();
230
231  // at this point, if possible, go and do some other computation
232  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
233  glDepthMask(GL_TRUE);
234  glEnable( GL_CULL_FACE );
235 
236  unsigned int pixelCount;
237  // reenable other state
238  glGetOcclusionQueryuivNV(query,
239                                                   GL_PIXEL_COUNT_NV,
240                                                   &pixelCount);
241
242  if (pixelCount > 0)
243        return -1.0f; // backfacing polygon found -> not a valid viewspace sample
244
245  ViewCell *viewcell = mViewCellsManager->GetViewCell(mViewPoint);
246 
247  if (viewcell) {
248        SetupCamera();
249        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
250
251        // Render PVS
252        std::map<Intersectable *,
253          PvsData<Intersectable *>,
254          LtSample<Intersectable *> >::const_iterator it = viewcell->GetPvs().mEntries.begin();
255       
256        for (; it != viewcell->GetPvs().mEntries.end(); ++ it) {
257          Intersectable *object = (*it).first;
258          RenderIntersectable(object);
259        }
260
261        glBeginOcclusionQueryNV(query);
262
263        SetupCamera();
264
265        RenderScene();
266       
267        glEndOcclusionQueryNV();
268       
269
270        unsigned int pixelCount;
271        // reenable other state
272        glGetOcclusionQueryuivNV(query,
273                                                         GL_PIXEL_COUNT_NV,
274                                                         &pixelCount);
275       
276        pErrorPixels = (100.f*pixelCount)/(GetWidth()*GetHeight());
277  }
278 
279  return pErrorPixels;
280}
281
282
283float
284GlRendererWidget::RenderErrors()
285{
286  float pErrorPixels = -1.0f;
287
288  glReadBuffer(GL_BACK);
289 
290  mUseFalseColors = true;
291
292  SetupCamera();
293  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
294  glEnable( GL_CULL_FACE );
295 
296  ObjectContainer::const_iterator oi = mObjects.begin();
297  for (; oi != mObjects.end(); oi++)
298        RenderIntersectable(*oi);
299
300  ViewCell *viewcell = mViewCellsManager->GetViewCell(mViewPoint);
301 
302  QImage im1, im2;
303  QImage diff;
304 
305  if (viewcell) {
306        // read back the texture
307        im1 = grabFrameBuffer(true);
308       
309        SetupCamera();
310        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
311       
312        std::map<Intersectable *,
313          PvsData<Intersectable *>,
314          LtSample<Intersectable *> >::const_iterator it = viewcell->GetPvs().mEntries.begin();
315       
316        for (; it != viewcell->GetPvs().mEntries.end(); ++ it) {
317          Intersectable *object = (*it).first;
318          RenderIntersectable(object);
319        }
320
321        // read back the texture
322        im2 = grabFrameBuffer(true);
323       
324        diff = im1;
325        int x, y;
326        int errorPixels = 0;
327       
328        for (y = 0; y < im1.height(); y++)
329          for (x = 0; x < im1.width(); x++)
330                if (im1.pixel(x, y) == im2.pixel(x, y))
331                  diff.setPixel(x, y, qRgba(0,0,0,0));
332                else {
333                  diff.setPixel(x, y, qRgba(255,128,128,255));
334                  errorPixels++;
335                }
336        pErrorPixels = (100.f*errorPixels)/(im1.height()*im1.width());
337  }
338
339  // now render the pvs again
340  SetupCamera();
341  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
342  mUseFalseColors = false;
343       
344  oi = mObjects.begin();
345  for (; oi != mObjects.end(); oi++)
346        RenderIntersectable(*oi);
347
348  // now render im1
349  if (viewcell) {
350        if (mTopView) {
351          mWireFrame = true;
352          RenderMeshInstance(viewcell);
353          mWireFrame = false;
354        }
355       
356        // init ortographic projection
357        glMatrixMode(GL_PROJECTION);
358        glPushMatrix();
359       
360        glLoadIdentity();
361        gluOrtho2D(0, 1.0f, 0, 1.0f);
362       
363        glMatrixMode(GL_MODELVIEW);
364        glLoadIdentity();
365       
366        bindTexture(diff);
367       
368        glPushAttrib(GL_ENABLE_BIT);
369        glEnable( GL_ALPHA_TEST );
370        glDisable( GL_CULL_FACE );
371        glAlphaFunc( GL_GREATER, 0.5 );
372       
373        glEnable( GL_TEXTURE_2D );
374        glBegin(GL_QUADS);
375       
376        glTexCoord2f(0,0);
377        glVertex3f(0,0,0);
378       
379        glTexCoord2f(1,0);
380        glVertex3f( 1, 0, 0);
381       
382        glTexCoord2f(1,1);
383        glVertex3f( 1, 1, 0);
384       
385        glTexCoord2f(0,1);
386        glVertex3f(0, 1, 0);
387        glEnd();
388       
389        glPopAttrib();
390       
391        // restore the projection matrix
392        glMatrixMode(GL_PROJECTION);
393        glPopMatrix();
394        glMatrixMode(GL_MODELVIEW);
395  }
396
397  return pErrorPixels;
398}
399
400
401bool
402GlRenderer::RenderScene()
403{
404  static int glList = -1;
405  if (glList != -1) {
406        glCallList(glList);
407  } else {
408        glList = glGenLists(1);
409        glNewList(glList, GL_COMPILE_AND_EXECUTE);
410        ObjectContainer::const_iterator oi = mObjects.begin();
411        for (; oi != mObjects.end(); oi++)
412          RenderIntersectable(*oi);
413        glEndList();
414  }
415  return true;
416}
417
418
419void
420GlRendererBuffer::ClearErrorBuffer()
421{
422  for (int i=0; i < mPvsStatFrames; i++) {
423        mPvsErrorBuffer[i] = 1.0f;
424  }
425}
426
427
428void
429GlRendererBuffer::EvalPvsStat()
430{
431  mPvsStat.Reset();
432  halton.Reset();
433
434  makeCurrent();
435  SetupProjection(GetWidth(), GetHeight());
436 
437  for (int i=0; i < mPvsStatFrames; i++) {
438        float err;
439        RandomViewPoint();
440        if (mPvsErrorBuffer[i] > 0.0f) {
441          mPvsErrorBuffer[i] = GetPixelError();
442          cout<<"("<<i<<","<<mPvsErrorBuffer[i]<<")";
443          //      swapBuffers();
444        }
445       
446        err = mPvsErrorBuffer[i];
447       
448        if (err >= 0.0f) {
449          if (err > mPvsStat.maxError)
450                mPvsStat.maxError = err;
451          mPvsStat.sumError += err;
452          if (err == 0.0f)
453                mPvsStat.errorFreeFrames++;
454          mPvsStat.frames++;
455        }
456  }
457 
458  doneCurrent();
459
460  cout<<endl<<flush;
461  mRenderingFinished.wakeAll();
462}
463
464
465
466
467
468void
469GlRendererWidget::mousePressEvent(QMouseEvent *e)
470{
471  int x = e->pos().x();
472  int y = e->pos().y();
473
474  mousePoint.x = x;
475  mousePoint.y = y;
476 
477}
478
479void
480GlRendererWidget::mouseMoveEvent(QMouseEvent *e)
481{
482  float MOVE_SENSITIVITY = Magnitude(mSceneGraph->GetBox().Diagonal())*1e-3;
483  float TURN_SENSITIVITY=0.1f;
484  float TILT_SENSITIVITY=32.0 ;
485  float TURN_ANGLE= M_PI/36.0 ;
486
487  int x = e->pos().x();
488  int y = e->pos().y();
489 
490  if (e->modifiers() & Qt::ControlModifier) {
491        mViewPoint.y += (y-mousePoint.y)*MOVE_SENSITIVITY/2.0;
492        mViewPoint.x += (x-mousePoint.x)*MOVE_SENSITIVITY/2.0;
493  } else {
494        mViewPoint += mViewDirection*((mousePoint.y - y)*MOVE_SENSITIVITY);
495        float adiff = TURN_ANGLE*(x - mousePoint.x)*-TURN_SENSITIVITY;
496        float angle = atan2(mViewDirection.x, mViewDirection.z);
497        mViewDirection.x = sin(angle+adiff);
498        mViewDirection.z = cos(angle+adiff);
499  }
500 
501  mousePoint.x = x;
502  mousePoint.y = y;
503 
504  updateGL();
505}
506
507void
508GlRendererWidget::mouseReleaseEvent(QMouseEvent *)
509{
510
511
512}
513
514void
515GlRendererWidget::resizeGL(int w, int h)
516{
517  SetupProjection(w, h);
518  updateGL();
519}
520
521void
522GlRendererWidget::paintGL()
523{
524  RenderErrors();
525  mFrame++;
526}
527
528
529void
530GlRendererWidget::SetupCamera()
531{
532  if (!mTopView)
533        GlRenderer::SetupCamera();
534  else {
535        float dist = Magnitude(mSceneGraph->GetBox().Diagonal())*0.05;
536        Vector3 pos = mViewPoint - dist*Vector3(mViewDirection.x,
537                                                                                        -1,
538                                                                                        mViewDirection.y);
539       
540        Vector3 target = mViewPoint + dist*mViewDirection;
541        Vector3 up(0,1,0);
542       
543        glLoadIdentity();
544        gluLookAt(pos.x, pos.y, pos.z,
545                          target.x, target.y, target.z,
546                          up.x, up.y, up.z);
547  }
548
549}
550
551void
552GlRendererWidget::keyPressEvent ( QKeyEvent * e )
553{
554  switch (e->key()) {
555  case Qt::Key_T:
556        mTopView = !mTopView;
557        updateGL();
558        break;
559  default:
560        e->ignore();
561        break;
562  }
563 
564}
565
566
567void GlRendererBuffer::SampleBeamContributions(Intersectable *sourceObject,
568                                                                                           Beam &beam,
569                                                                                           const int desiredSamples,
570                                                                                           BeamSampleStatistics &stat)
571{
572        // TODO: should be out of here
573        cgGLBindProgram(sCgFragmentProgram);
574        cgGLEnableProfile(sCgFragmentProfile);
575
576        // assumes that the beam is constructed and contains kd-tree nodes
577        // and viewcells which it intersects
578       
579
580 
581 
582        // Get the number of viewpoints to be sampled
583        // Now it is a sqrt but in general a wiser decision could be made.
584        // The less viewpoints the better for rendering performance, since less passes
585        // over the beam is needed.
586        // The viewpoints could actually be generated outside of the bounding box which
587        // would distribute the 'efective viewpoints' of the object surface and thus
588        // with a few viewpoints better sample the vipoint space....
589 
590        int viewPointSamples = sqrt((float)desiredSamples);
591
592        // the number of direction samples per pass is given by the number of viewpoints
593        int directionalSamples = desiredSamples/viewPointSamples;
594       
595        for (int i = 0; i < viewPointSamples; ++ i)
596        {
597                Vector3 viewPoint = beam.mBox.GetRandomPoint();
598               
599                // perhaps the viewpoint should be shifted back a little bit so that it always lies
600                // inside the source object
601                // 'ideally' the viewpoints would be distributed on the soureObject surface, but this
602        // would require more complicated sampling (perhaps hierarchical rejection sampling of
603                // the object surface is an option here - only the mesh faces which are inside the box
604                // are considered as candidates)
605               
606                SampleViewpointContributions(sourceObject,
607                                                                         beam,
608                                                                         directionalSamples,
609                                                                         stat);
610        }
611
612
613        // note:
614        // this routine would be called only if the number of desired samples is sufficiently
615        // large - for other rss tree cells the cpu based sampling is perhaps more efficient
616        // distributing the work between cpu and gpu would also allow us to place more sophisticated
617        // sample distributions (silhouette ones) using the cpu and the jittered once on the GPU
618        // in order that thios scheme is working well the gpu render buffer should run in a separate
619        // thread than the cpu sampler, which would not be such a big problem....
620
621        cgGLDisableProfile(sCgFragmentProfile);
622}
623
624
625void GlRendererBuffer::SampleViewpointContributions(Intersectable *sourceObject,
626                                                                                                        Beam &beam,
627                                                                                                        const int desiredSamples,
628                                                    BeamSampleStatistics &stat)
629{
630        // 1. setup the view port to match the desired samples
631        // 2. setup the projection matrix and view matrix to match the viewpoint + beam.mDirBox
632 
633        // 3. reset z-buffer to 0 and render the source object for the beam using
634        //    glDepthFunc(GL_GREATER)
635        //    and glCullFace(Enabled) and glFrontFace(GL_CW)
636        //    save result to depth buffer?
637       
638        // bind ray origin depth buffer
639        glClear(GL_DEPTH);
640        glBindTexture(GL_TEXTURE_2D, depthMap);
641    glEnable(GL_TEXTURE_2D);
642
643        // compare with second depth buffer: should be done in pixel shader
644        /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
645        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_GREATER);
646        glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
647        */
648
649
650        // 4. set back to normal rendering and clear the ray termination depth buffer
651        // 5. render all objects inside the beam using id based false color
652        //    (objects can be compiled to a gl list now so that subsequent rendering for
653        //     this beam is fast - the same hold for step 3)
654
655
656        // 6. Now we have a two depth buffers defining the ray origin and termination
657        //    only rays which have non-zero entry in the origin buffer are valid since
658        //    they realy start on the object surface (this can also be tagged by setting a
659        //    stencil buffer bit at step 3)
660
661        // 7. Use occlusion queries for all viewcell meshes associated with the beam ->
662        // a fragment passes if the corresponding stencil fragment is set and its depth is
663        // between origin and termination buffer
664
665        // 8. The number of visible pixels is the number of sample rays which see the source
666        //    object from the corresponding viewcell -> rember these values for later update
667        //   of the viewcell pvs - or update immediatelly?
668
669        //  In general it is not neccessary to rember to extract all the rays cast. I hope it
670        // would be sufficient to gain only the intergral statistics about the new contributions
671        // and so the rss tree would actually store no new rays (only the initial ones)
672        // the subdivision of the tree would only be driven by the statistics (the glrender could
673        // evaluate the contribution entropy for example)
674        // However might be an option to extract/store only those the rays which made a contribution
675        // (new viewcell has been discovered) or relative contribution greater than a threashold ...
676
677}
Note: See TracBrowser for help on using the repository browser.