#include "Mesh.h" #include "GlRenderer.h" #include "ViewCellsManager.h" #include "SceneGraph.h" #include "Pvs.h" #include "Viewcell.h" #include GlRenderer *renderer = NULL; #ifdef _WIN32 PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV; PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV; PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV; PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV; #endif GlRenderer::GlRenderer(SceneGraph *sceneGraph, ViewCellsManager *viewCellsManager): QGLWidget(), mSceneGraph(sceneGraph), mViewCellsManager(viewCellsManager) { mSceneGraph->CollectObjects(&mObjects); mViewPoint = mSceneGraph->GetBox().Center(); mViewDirection = Vector3(0,0,1); mRender = true; // timerId = startTimer(10); mFrame = 0; mPvsStatFrames = 10000; mPvsErrorBuffer.resize(mPvsStatFrames); ClearErrorBuffer(); pbuffer = NULL; } GlRenderer::~GlRenderer() { if (pbuffer) delete pbuffer; } void GlRenderer::RenderIntersectable(Intersectable *object) { SetupFalseColor(object->mId); switch (object->Type()) { case Intersectable::MESH_INSTANCE: RenderMeshInstance((MeshInstance *)object); break; default: cerr<<"Rendering this object not yet implemented\n"; break; } } void GlRenderer::RenderMeshInstance(MeshInstance *mi) { RenderMesh(mi->GetMesh()); } void GlRenderer::SetupFalseColor(const int id) { // swap bits of the color glColor3ub(id&255, (id>>8)&255, (id>>16)&255); } void GlRenderer::SetupMaterial(Material *m) { if (m) glColor3fv(&(m->mDiffuseColor.r)); else glColor3f(1.0f, 1.0f, 1.0f); } void GlRenderer::RenderMesh(Mesh *mesh) { int i = 0; if (!mUseFalseColors) SetupMaterial(mesh->mMaterial); for (i=0; i < mesh->mFaces.size(); i++) { glBegin(GL_POLYGON); Face *face = mesh->mFaces[i]; for (int j = 0; j < face->mVertexIndices.size(); j++) { glVertex3fv(&mesh->mVertices[face->mVertexIndices[j]].x); } glEnd(); } } void GlRenderer::initializeGL() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_CULL_FACE); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC) wglGetProcAddress("glGenOcclusionQueriesNV"); glBeginOcclusionQueryNV = (PFNGLBEGINOCCLUSIONQUERYNVPROC) wglGetProcAddress("glBeginOcclusionQueryNV"); glEndOcclusionQueryNV = (PFNGLENDOCCLUSIONQUERYNVPROC) wglGetProcAddress("glEndOcclusionQueryNV"); glGetOcclusionQueryuivNV = (PFNGLGETOCCLUSIONQUERYUIVNVPROC) wglGetProcAddress("glGetOcclusionQueryuivNV"); } void GlRenderer::resizeGL(int w, int h) { SetupProjection(w, h); if (pbuffer == NULL || pbuffer->size().width() != w || pbuffer->size().height() != h) { if (pbuffer) delete pbuffer; pbuffer = new QGLPixelBuffer(QSize(w,h)); } updateGL(); } void GlRenderer::SetupProjection(const int w, const int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70.0, 1.0, 0.1, 2.0*Magnitude(mSceneGraph->GetBox().Diagonal())); glMatrixMode(GL_MODELVIEW); } void GlRenderer::SetupCamera() { Vector3 target = mViewPoint + mViewDirection; Vector3 up(0,1,0); glLoadIdentity(); gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z, target.x, target.y, target.z, up.x, up.y, up.z); } void GlRenderer::RandomViewPoint() { Vector3 pVector = Vector3(halton.GetNumber(1), halton.GetNumber(2), halton.GetNumber(3)); Vector3 dVector = Vector3(2*M_PI*halton.GetNumber(4), M_PI*halton.GetNumber(5), 0.0f); mViewPoint = mSceneGraph->GetBox().GetPoint(pVector); mViewDirection = Normalize(Vector3(sin(dVector.x), // cos(dVector.y), 0.0f, cos(dVector.x))); halton.GenerateNext(); } void GlRenderer::paintGL() { if (mRender) { Render(); mFrame++; } } void GlRenderer::ClearErrorBuffer() { for (int i=0; i < mPvsStatFrames; i++) { mPvsErrorBuffer[i] = 1.0f; } } void GlRenderer::EvalPvsStat() { mPvsStat.Reset(); halton.Reset(); pbuffer->makeCurrent(); initializeGL(); SetupProjection(pbuffer->size().width(), pbuffer->size().height()); for (int i=0; i < mPvsStatFrames; i++) { float err; RandomViewPoint(); if (mPvsErrorBuffer[i] > 0.0f) { mPvsErrorBuffer[i] = GetPixelError(); cout<<"("<= 0.0f) { if (err > mPvsStat.maxError) mPvsStat.maxError = err; mPvsStat.sumError += err; if (err == 0.0f) mPvsStat.errorFreeFrames++; mPvsStat.frames++; } } pbuffer->doneCurrent(); cout<GetViewCell(mViewPoint); QImage im1, im2; QImage diff; if (viewcell) { // read back the texture im1 = grabFrameBuffer(true); SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); std::map, LtSample >::const_iterator it = viewcell->GetPvs().mEntries.begin(); for (; it != viewcell->GetPvs().mEntries.end(); ++ it) { Intersectable *object = (*it).first; RenderIntersectable(object); } // read back the texture im2 = grabFrameBuffer(true); diff = im1; int x, y; int errorPixels = 0; for (y = 0; y < im1.height(); y++) for (x = 0; x < im1.width(); x++) if (im1.pixel(x, y) == im2.pixel(x, y)) diff.setPixel(x, y, qRgba(0,0,0,0)); else { diff.setPixel(x, y, qRgba(255,128,128,255)); errorPixels++; } pErrorPixels = (100.f*errorPixels)/(im1.height()*im1.width()); } // now render the pvs again SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mUseFalseColors = false; oi = mObjects.begin(); for (; oi != mObjects.end(); oi++) RenderIntersectable(*oi); // now render im1 if (viewcell) { // init ortographic projection glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, 1.0f, 0, 1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); bindTexture(diff); glPushAttrib(GL_ENABLE_BIT); glEnable( GL_ALPHA_TEST ); glDisable( GL_CULL_FACE ); glAlphaFunc( GL_GREATER, 0.5 ); glEnable( GL_TEXTURE_2D ); glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex3f(0,0,0); glTexCoord2f(1,0); glVertex3f( 1, 0, 0); glTexCoord2f(1,1); glVertex3f( 1, 1, 0); glTexCoord2f(0,1); glVertex3f(0, 1, 0); glEnd(); glPopAttrib(); // restore the projection matrix glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } return pErrorPixels; } void GlRenderer::RenderScene() { static int glList = -1; if (glList != -1) { glCallList(glList); } else { glList = glGenLists(1); glNewList(glList, GL_COMPILE_AND_EXECUTE); ObjectContainer::const_iterator oi = mObjects.begin(); for (; oi != mObjects.end(); oi++) RenderIntersectable(*oi); glEndList(); } } float GlRenderer::GetPixelError() { float pErrorPixels = -1.0f; glReadBuffer(GL_BACK); mUseFalseColors = true; SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable( GL_CULL_FACE ); RenderScene(); // now check whether any backfacing polygon would pass the depth test static int query = -1; if (query == -1) glGenOcclusionQueriesNV(1, (unsigned int *)&query); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); glDisable( GL_CULL_FACE ); glBeginOcclusionQueryNV(query); RenderScene(); glEndOcclusionQueryNV(); // at this point, if possible, go and do some other computation glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); glEnable( GL_CULL_FACE ); unsigned int pixelCount; // reenable other state glGetOcclusionQueryuivNV(query, GL_PIXEL_COUNT_NV, &pixelCount); if (pixelCount > 0) return -1.0f; // backfacing polygon found -> not a valid viewspace sample ViewCell *viewcell = mViewCellsManager->GetViewCell(mViewPoint); if (viewcell) { SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Render PVS std::map, LtSample >::const_iterator it = viewcell->GetPvs().mEntries.begin(); for (; it != viewcell->GetPvs().mEntries.end(); ++ it) { Intersectable *object = (*it).first; RenderIntersectable(object); } glBeginOcclusionQueryNV(query); SetupCamera(); RenderScene(); glEndOcclusionQueryNV(); unsigned int pixelCount; // reenable other state glGetOcclusionQueryuivNV(query, GL_PIXEL_COUNT_NV, &pixelCount); pErrorPixels = (100.f*pixelCount)/(height()*width()); } return pErrorPixels; } void GlRenderer::mousePressEvent(QMouseEvent *e) { int x = e->pos().x(); int y = e->pos().y(); mousePoint.x = x; mousePoint.y = y; } void GlRenderer::mouseMoveEvent(QMouseEvent *e) { float MOVE_SENSITIVITY = Magnitude(mSceneGraph->GetBox().Diagonal())*1e-3; float TURN_SENSITIVITY=0.1f; float TILT_SENSITIVITY=32.0 ; float TURN_ANGLE= M_PI/36.0 ; int x = e->pos().x(); int y = e->pos().y(); if (e->modifiers() & Qt::ControlModifier) { mViewPoint.y += (y-mousePoint.y)*MOVE_SENSITIVITY/2.0; mViewPoint.x += (x-mousePoint.x)*MOVE_SENSITIVITY/2.0; } else { mViewPoint += mViewDirection*((mousePoint.y - y)*MOVE_SENSITIVITY); float adiff = TURN_ANGLE*(x - mousePoint.x)*-TURN_SENSITIVITY; float angle = atan2(mViewDirection.x, mViewDirection.z); mViewDirection.x = sin(angle+adiff); mViewDirection.z = cos(angle+adiff); } mousePoint.x = x; mousePoint.y = y; updateGL(); } void GlRenderer::mouseReleaseEvent(QMouseEvent *) { }