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

Revision 507, 14.6 KB checked in by bittner, 19 years ago (diff)

Preparation for hw based sampling

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