#include "Mesh.h" #include "GlRenderer.h" #include "ViewCellsManager.h" #include "SceneGraph.h" #include "Pvs.h" #include "Viewcell.h" #include "Beam.h" #include "KdTree.h" #include "Environment.h" //#define GL_GLEXT_PROTOTYPES #include #include #include #include namespace GtpVisibilityPreprocessor { static CGcontext sCgContext = NULL; static CGprogram sCgFragmentProgram = NULL; static CGprofile sCgFragmentProfile; GLuint frontDepthMap; GLuint backDepthMap; const int depthMapSize = 512; static vector sQueries; GlRendererWidget *rendererWidget = NULL; GlDebuggerWidget *debuggerWidget = NULL; #ifdef _WIN32 PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV; PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV; PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV; PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV; //PFNGLGENQUERIESARBPROC glGenQueriesARB; //PFNGLBEGINQUERYARBPROC glBeginQueryARB; //PFNGLENDQUERYARBPROC glEndQueryARB; //PFNGLGETQUERYUIVARBPROC glGetQueryuivARB; #endif GlRenderer::GlRenderer(SceneGraph *sceneGraph, ViewCellsManager *viewCellsManager, KdTree *tree): Renderer(sceneGraph, viewCellsManager), mKdTree(tree) { mSceneGraph->CollectObjects(&mObjects); mViewPoint = mSceneGraph->GetBox().Center(); mViewDirection = Vector3(0,0,1); mViewPoint = Vector3(991.7, 187.8, -271); mViewDirection = Vector3(0.9, 0, -0.4); // timerId = startTimer(10); // debug coords for atlanta // mViewPoint = Vector3(3473, 6.778, -1699); // mViewDirection = Vector3(-0.2432, 0, 0.97); mFrame = 0; mWireFrame = false; environment->GetBoolValue("Preprocessor.detectEmptyViewSpace", mDetectEmptyViewSpace); mSnapErrorFrames = true; mSnapPrefix = "snap/"; mUseForcedColors = false; mUseGlLists = true; } GlRenderer::~GlRenderer() { cerr<<"gl renderer destructor..\n"; if (sCgFragmentProgram) cgDestroyProgram(sCgFragmentProgram); if (sCgContext) cgDestroyContext(sCgContext); cerr<<"done."<mId); switch (object->Type()) { case Intersectable::MESH_INSTANCE: RenderMeshInstance((MeshInstance *)object); break; case Intersectable::VIEW_CELL: RenderViewCell(dynamic_cast(object)); break; default: cerr<<"Rendering this object not yet implemented\n"; break; } glPopAttrib(); } void GlRenderer::RenderViewCell(ViewCell *vc) { if (vc->GetMesh()) { if (!mUseFalseColors) { if (vc->GetValid()) glColor3f(0,1,0); else glColor3f(0,0,1); } RenderMesh(vc->GetMesh()); } else { // render viewcells in the subtree if (!vc->IsLeaf()) { ViewCellInterior *vci = (ViewCellInterior *) vc; ViewCellContainer::iterator it = vci->mChildren.begin(); for (; it != vci->mChildren.end(); ++it) { RenderViewCell(*it); } } else { // cerr<<"Empty viewcell mesh\n"; } } } 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); } int GlRenderer::GetId(int r, int g, int b) const { return r + (g << 8) + (b << 16); } void GlRenderer::SetupMaterial(Material *m) { if (m) glColor3fv(&(m->mDiffuseColor.r)); } void GlRenderer::RenderMesh(Mesh *mesh) { int i = 0; if (!mUseFalseColors && !mUseForcedColors) SetupMaterial(mesh->mMaterial); for (i=0; i < mesh->mFaces.size(); i++) { if (mWireFrame) glBegin(GL_LINE_LOOP); else 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::InitGL() { 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"); #if 0 glGenQueriesARB = (PFNGLGENDQUERIESARBPROC) wglGetProcAddress("glGenQueriesARB"); glBeginQueryARB = (PFNGLBEGINQUERYARBPROC) wglGetProcAddress("glBeginQueryARB"); glEndQueryARB = (PFNGLENDQUERYARBPROC) wglGetProcAddress("glEndQueryARB"); glGetQueryuivARB = (PFNGLGETQUERYUIVARBPROC) wglGetProcAddress("glGetQueryuivARB"); #endif #if 0 GLfloat mat_ambient[] = { 0.5, 0.5, 0.5, 1.0 }; /* mat_specular and mat_shininess are NOT default values */ GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_specular[] = { 0.3, 0.3, 0.3, 1.0 }; GLfloat mat_shininess[] = { 1.0 }; GLfloat light_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat light_diffuse[] = { 0.4, 0.4, 0.4, 1.0 }; GLfloat light_specular[] = { 0.3, 0.3, 0.3, 1.0 }; GLfloat lmodel_ambient[] = { 0.3, 0.3, 0.3, 1.0 }; // default Material glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); // a light glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); // set position of the light GLfloat infinite_light[] = { 1.0, 0.8, 1.0, 0.0 }; glLightfv (GL_LIGHT0, GL_POSITION, infinite_light); // set position of the light2 GLfloat infinite_light2[] = { -0.3, 1.5, 1.0, 0.0 }; glLightfv (GL_LIGHT1, GL_POSITION, infinite_light2); glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); // glColorMaterial( GL_FRONT_AND_BACK, GL_SPECULAR); glEnable(GL_COLOR_MATERIAL); glShadeModel( GL_FLAT ); glDepthFunc( GL_LESS ); glEnable( GL_DEPTH_TEST ); #endif glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); glEnable( GL_NORMALIZE ); glClearColor(0.0f, 0.0f, 1.0f, 1.0f); } void GlRendererWidget::RenderInfo() { QString s; int vc = 0; if (mViewCellsManager) vc = mViewCellsManager->GetViewCells().size(); int filter = 0; if (mViewCellsManager) filter = mViewCellsManager->GetMaxFilterSize(); s.sprintf("frame:%04d viewpoint:(%4.1f,%4.1f,%4.1f) dir:(%4.1f,%4.1f,%4.1f) viewcells:%04d filter:%04d pvs:%04d error:%5.5f\%", mFrame, mViewPoint.x, mViewPoint.y, mViewPoint.z, mViewDirection.x, mViewDirection.y, mViewDirection.z, vc, filter, mPvsSize, mRenderError*100.0f ); glColor3f(0.0f,0.0f,0.0f); renderText(0,20,s); if (mShowRenderCost) { static vector costFunction; static float maxCost = -1; if (costFunction.size()==0) { ViewCellsTree *tree = mViewCellsManager->GetViewCellsTree(); if (tree) { tree->GetCostFunction(costFunction); maxCost = -1; for (int i=0; i < costFunction.size(); i++) { // cout< maxCost) maxCost = costFunction[i]; } } } int currentPos = mViewCellsManager->GetViewCells().size(); float currentCost=-1; if (currentPos < costFunction.size()) currentCost = costFunction[currentPos]; #if 0 cout<<"costFunction.size()="<mCounter += pixelCount; } j += q; } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); } void GlRendererBuffer::EvalRenderCostSample( RenderCostSample &sample ) { // choose a random view point mViewCellsManager->GetViewPoint(mViewPoint); sample.mPosition = mViewPoint; //cout << "viewpoint: " << mViewPoint << endl; // take a render cost sample by rendering a cube Vector3 directions[6]; directions[0] = Vector3(1,0,0); directions[1] = Vector3(0,1,0); directions[2] = Vector3(0,0,1); directions[3] = Vector3(-1,0,0); directions[4] = Vector3(0,-1,0); directions[5] = Vector3(0,0,-1); sample.mVisibleObjects = 0; int i, j; // reset object visibility for (i=0; i < mObjects.size(); i++) { mObjects[i]->mCounter = 0; } ++ mFrame; // either use occlusion queries or item buffer bool useOcclusionQueries; environment->GetBoolValue("RenderSampler.useOcclusionQueries", useOcclusionQueries); //if (useOcclusionQueries) cout << "using occlusion queries" << endl; //else cout << "using item buffer" << endl; glCullFace(GL_FRONT); if (mDetectEmptyViewSpace) { glEnable(GL_CULL_FACE); cout << "culling" << endl; } else { cout << "not culling" << endl; glDisable(GL_CULL_FACE); } for (i = 0; i < 6; ++ i) { mViewDirection = directions[i]; SetupCamera(); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthFunc(GL_LESS); mUseFalseColors = true; // the actual scene rendering RenderScene(); if (0) { char filename[256]; sprintf(filename, "snap/frame-%04d-%d.png", mFrame, i); QImage im = toImage(); im.save(filename, "PNG"); } if (useOcclusionQueries) { EvalQueryWithOcclusionQueries(); } else { EvalQueryWithItemBuffer(); } } // now evaluate the statistics over that sample // currently only the number of visible objects is taken into account sample.Reset(); for (j = 0; j < mObjects.size(); j++) { if (mObjects[j]->mCounter) { ++ sample.mVisibleObjects; sample.mVisiblePixels += mObjects[j]->mCounter; } } cout << "RS=" << sample.mVisibleObjects << " "; } void GlRendererBuffer::SampleRenderCost( const int n, vector &samples ) { makeCurrent(); if (mPixelBuffer == NULL) mPixelBuffer = new unsigned int[GetWidth()*GetHeight()]; SetupProjection(GetHeight(), GetHeight(), 90.0f); samples.resize(n); halton.Reset(); int i; int numQ = 500; if (mOcclusionQueries.size() < numQ) { cout << "allocating occ queries..." << endl; unsigned int *queries = new unsigned int[numQ]; // matt: ? for (i = 0; i < numQ; ++ i) queries[i] = 111; glGenOcclusionQueriesNV(numQ, queries); mOcclusionQueries.resize(numQ); for (i = 0; i < numQ; ++ i) { mOcclusionQueries[i] = queries[i]; } DEL_PTR(queries); } for (i = 0; i < n; ++ i) { EvalRenderCostSample(samples[i]); } doneCurrent(); } void GlRendererBuffer::RandomViewPoint() { // do not use this function since it could return different viewpoints for // different executions of the algorithm //mViewCellsManager->GetViewPoint(mViewPoint); while (1) { Vector3 pVector = Vector3(halton.GetNumber(1), halton.GetNumber(2), halton.GetNumber(3)); mViewPoint = mSceneGraph->GetBox().GetPoint(pVector); ViewCell *v = mViewCellsManager->GetViewCell(mViewPoint); if (v && v->GetValid()) break; // generate a new vector halton.GenerateNext(); } Vector3 dVector = Vector3(2*M_PI*halton.GetNumber(4), M_PI*halton.GetNumber(5), 0.0f); mViewDirection = Normalize(Vector3(sin(dVector.x), // cos(dVector.y), 0.0f, cos(dVector.x))); halton.GenerateNext(); } GlRendererBuffer::GlRendererBuffer(const int w, const int h, SceneGraph *sceneGraph, ViewCellsManager *viewcells, KdTree *tree): QGLPixelBuffer(QSize(w, h)), GlRenderer(sceneGraph, viewcells, tree) { environment->GetIntValue("Preprocessor.pvsRenderErrorSamples", mPvsStatFrames); mPvsErrorBuffer.resize(mPvsStatFrames); ClearErrorBuffer(); mPixelBuffer = NULL; makeCurrent(); InitGL(); doneCurrent(); } float GlRendererBuffer::GetPixelError(int &pvsSize) { float pErrorPixels = -1.0f; glReadBuffer(GL_BACK); // mUseFalseColors = true; mUseFalseColors = false; static int query = -1; unsigned int pixelCount; if (query == -1) glGenOcclusionQueriesNV(1, (unsigned int *)&query); if (mDetectEmptyViewSpace) { // now check whether any backfacing polygon would pass the depth test SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable( GL_CULL_FACE ); RenderScene(); 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 ); // reenable other state glGetOcclusionQueryuivNV(query, GL_PIXEL_COUNT_NV, &pixelCount); if (pixelCount > 0) return -1.0f; // backfacing polygon found -> not a valid viewspace sample } else glDisable( GL_CULL_FACE ); ViewCell *viewcell = NULL; PrVs prvs; // mViewCellsManager->SetMaxFilterSize(1); mViewCellsManager->GetPrVS(mViewPoint, prvs, mViewCellsManager->GetFilterWidth()); viewcell = prvs.mViewCell; // ViewCell *viewcell = mViewCellsManager->GetViewCell(mViewPoint); pvsSize = 0; if (viewcell) { SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); // Render PVS std::map, LtSample >::const_iterator it = viewcell->GetPvs().mEntries.begin(); pvsSize = viewcell->GetPvs().mEntries.size(); for (; it != viewcell->GetPvs().mEntries.end(); ++ it) { Intersectable *object = (*it).first; RenderIntersectable(object); } // glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); mUseFalseColors = true; glBeginOcclusionQueryNV(query); SetupCamera(); RenderScene(); glEndOcclusionQueryNV(); unsigned int pixelCount; // reenable other state glGetOcclusionQueryuivNV(query, GL_PIXEL_COUNT_NV, &pixelCount); pErrorPixels = ((float)pixelCount)/(GetWidth()*GetHeight()); if (mSnapErrorFrames && pErrorPixels > 0.01) { char filename[256]; sprintf(filename, "error-frame-%04d-%0.5f.png", mFrame, pErrorPixels); QImage im = toImage(); im.save(mSnapPrefix + filename, "PNG"); if (1) { //0 && mFrame == 1543) { int x,y; int lastIndex = -1; for (y=0; y < im.height(); y++) for (x=0; x < im.width(); x++) { QRgb p = im.pixel(x,y); int index = qRed(p) + (qGreen(p)<<8) + (qBlue(p)<<16); if (qGreen(p) != 255 && index!=0) { if (index != lastIndex) { Debug<<"ei="<, LtSample >::const_iterator it = viewcell->GetPvs().mEntries.begin(); for (; it != viewcell->GetPvs().mEntries.end(); ++ it) { Intersectable *object = (*it).first; RenderIntersectable(object); } im = toImage(); sprintf(filename, "error-frame-%04d-%0.5f-pvs.png", mFrame, pErrorPixels); im.save(mSnapPrefix + filename, "PNG"); glPopAttrib(); } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } if (viewcell) mViewCellsManager->DeleteLocalMergeTree(viewcell); return pErrorPixels; } void GlRendererWidget::SetupProjection(const int w, const int h) { if (!mTopView) GlRenderer::SetupProjection(w, h); else { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0, 1.0, 0.1, 20.0*Magnitude(mSceneGraph->GetBox().Diagonal())); glMatrixMode(GL_MODELVIEW); } } void GlRendererWidget::RenderPvs() { SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ViewCell *viewcell = NULL; PrVs prvs; if (!mUseFilter) { viewcell = mViewCellsManager->GetViewCell(mViewPoint, true); } else { // mViewCellsManager->SetMaxFilterSize(1); mViewCellsManager->GetPrVS(mViewPoint, prvs, mViewCellsManager->GetFilterWidth()); viewcell = prvs.mViewCell; } if (viewcell) { // copy the pvs so that it can be filtered... ObjectPvs pvs = viewcell->GetPvs(); if (mUseSpatialFilter) { mViewCellsManager->ApplySpatialFilter(mKdTree, mSpatialFilterSize* Magnitude(mViewCellsManager->GetViewSpaceBox().Size()), pvs); } // read back the texture std::map, LtSample >::const_iterator it = pvs.mEntries.begin(); mPvsSize = pvs.mEntries.size(); for (; it != pvs.mEntries.end(); ++ it) { Intersectable *object = (*it).first; float visibility = log10((*it).second.mSumPdf + 1)/5.0f; glColor3f(visibility, 0.0f, 0.0f); mUseForcedColors = true; RenderIntersectable(object); mUseForcedColors = false; } if (mRenderFilter) { mWireFrame = true; RenderIntersectable(viewcell); mWireFrame = false; } if (mUseFilter) mViewCellsManager->DeleteLocalMergeTree(viewcell); } else { ObjectContainer::const_iterator oi = mObjects.begin(); for (; oi != mObjects.end(); oi++) RenderIntersectable(*oi); } } float GlRendererWidget::RenderErrors() { float pErrorPixels = -1.0f; glReadBuffer(GL_BACK); mUseFalseColors = true; SetupCamera(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); double eq[4]; eq[0] = mSceneCutPlane.mNormal.x; eq[1] = mSceneCutPlane.mNormal.y; eq[2] = mSceneCutPlane.mNormal.z; eq[3] = mSceneCutPlane.mD; if (mCutScene) { glClipPlane(GL_CLIP_PLANE0, eq); glEnable(GL_CLIP_PLANE0); } if (mDetectEmptyViewSpace) glEnable( GL_CULL_FACE ); else glDisable( GL_CULL_FACE ); ObjectContainer::const_iterator oi = mObjects.begin(); for (; oi != mObjects.end(); oi++) RenderIntersectable(*oi); ViewCell *viewcell = NULL; QImage im1, im2; QImage diff; if (viewcell) { // read back the texture im1 = grabFrameBuffer(true); RenderPvs(); // 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 = ((float)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) { if (0 && mTopView) { mWireFrame = true; RenderIntersectable(viewcell); mWireFrame = false; } // 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); } glDisable(GL_CLIP_PLANE0); mRenderError = pErrorPixels; return pErrorPixels; } void GlRenderer::_RenderScene() { ObjectContainer::const_iterator oi = mObjects.begin(); for (; oi != mObjects.end(); oi++) RenderIntersectable(*oi); } bool GlRenderer::RenderScene() { static int glList = -1; if (mUseGlLists) { if (glList == -1) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); _RenderScene(); glEndList(); } glCallList(glList); } else _RenderScene(); return true; } void GlRendererBuffer::ClearErrorBuffer() { for (int i=0; i < mPvsStatFrames; i++) { mPvsErrorBuffer[i].mError = 1.0f; } } void GlRendererBuffer::EvalPvsStat() { mPvsStat.Reset(); halton.Reset(); makeCurrent(); SetupProjection(GetWidth(), GetHeight()); for (int i=0; i < mPvsStatFrames; i++) { float err; // set frame id for saving the error buffer mFrame = i; RandomViewPoint(); // atlanta problematic frames: 325 525 691 1543 #if 0 if (mFrame != 325 && mFrame != 525 && mFrame != 691 && mFrame != 1543) mPvsErrorBuffer[i] = -1; else { Debug<<"frame ="<= 0.0f) { if (err > mPvsStat.maxError) mPvsStat.maxError = err; mPvsStat.sumError += err; mPvsStat.sumPvsSize += mPvsErrorBuffer[i].mPvsSize; if (err == 0.0f) mPvsStat.errorFreeFrames++; mPvsStat.frames++; } } glFinish(); doneCurrent(); cout<pos().x(); int y = e->pos().y(); mousePoint.x = x; mousePoint.y = y; } void GlRendererWidget::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 GlRendererWidget::mouseReleaseEvent(QMouseEvent *) { } void GlRendererWidget::resizeGL(int w, int h) { SetupProjection(w, h); updateGL(); } void GlRendererWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (!mRenderViewCells) { if (mRenderErrors) RenderErrors(); else RenderPvs(); RenderInfo(); } else { RenderViewCells(); mWireFrame = true; RenderScene(); mWireFrame = false; RenderInfo(); } mFrame++; } void GlRendererWidget::SetupCamera() { if (!mTopView) GlRenderer::SetupCamera(); else { if (0) { float dist = Magnitude(mSceneGraph->GetBox().Diagonal())*0.05; Vector3 pos = mViewPoint - dist*Vector3(mViewDirection.x, -1, mViewDirection.y); Vector3 target = mViewPoint + dist*mViewDirection; Vector3 up(0,1,0); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, target.x, target.y, target.z, up.x, up.y, up.z); } else { float dist = Magnitude(mSceneGraph->GetBox().Diagonal())*mTopDistance; Vector3 pos = mViewPoint + dist*Vector3(0, 1, 0); Vector3 target = mViewPoint; Vector3 up(mViewDirection.x, 0, mViewDirection.z); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, target.x, target.y, target.z, up.x, up.y, up.z); } } } void GlRendererWidget::keyPressEvent ( QKeyEvent * e ) { switch (e->key()) { case Qt::Key_T: mTopView = !mTopView; SetupProjection(width(), height()); updateGL(); break; case Qt::Key_V: mRenderViewCells = !mRenderViewCells; updateGL(); break; default: e->ignore(); break; } } RendererControlWidget::RendererControlWidget(QWidget * parent, Qt::WFlags f): QWidget(parent, f) { QVBoxLayout *vl = new QVBoxLayout; setLayout(vl); QWidget *vbox = new QGroupBox("ViewCells", this); layout()->addWidget(vbox); vl = new QVBoxLayout; vbox->setLayout(vl); QLabel *label = new QLabel("Granularity"); vbox->layout()->addWidget(label); QSlider *slider = new QSlider(Qt::Horizontal, vbox); vl->addWidget(slider); slider->show(); slider->setRange(1, 10000); slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); slider->setValue(200); connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetViewCellGranularity(int))); label = new QLabel("Filter size"); vbox->layout()->addWidget(label); slider = new QSlider(Qt::Horizontal, vbox); vbox->layout()->addWidget(slider); slider->show(); slider->setRange(1, 100); slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); slider->setValue(3); connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetVisibilityFilterSize(int))); label = new QLabel("Spatial Filter size"); vbox->layout()->addWidget(label); slider = new QSlider(Qt::Horizontal, vbox); vbox->layout()->addWidget(slider); slider->show(); slider->setRange(1, 100); slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); slider->setValue(10); connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetSpatialFilterSize(int))); QWidget *hbox = new QWidget(vbox); vl->addWidget(hbox); QHBoxLayout *hlayout = new QHBoxLayout; hbox->setLayout(hlayout); QCheckBox *cb = new QCheckBox("Show viewcells", hbox); hlayout->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetShowViewCells(bool))); cb = new QCheckBox("Show render cost", hbox); hlayout->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetShowRenderCost(bool))); cb = new QCheckBox("Show pvs sizes", hbox); hlayout->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetShowPvsSizes(bool))); vbox->resize(800,100); vbox = new QGroupBox("Rendering", this); layout()->addWidget(vbox); vl = new QVBoxLayout; vbox->setLayout(vl); slider = new QSlider(Qt::Horizontal, vbox); vbox->layout()->addWidget(slider); slider->show(); slider->setRange(0, 1000); slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); slider->setValue(1000); connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetSceneCut(int))); cb = new QCheckBox("Render errors", vbox); vbox->layout()->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetRenderErrors(bool))); cb = new QCheckBox("Use filter", vbox); vbox->layout()->addWidget(cb); cb->setChecked(true); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetUseFilter(bool))); cb = new QCheckBox("Use spatial filter", vbox); vbox->layout()->addWidget(cb); cb->setChecked(true); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetUseSpatialFilter(bool))); cb = new QCheckBox("Render filter", vbox); vbox->layout()->addWidget(cb); cb->setChecked(true); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetRenderFilter(bool))); cb = new QCheckBox("Cut view cells", vbox); vbox->layout()->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetCutViewCells(bool))); cb = new QCheckBox("Cut scene", vbox); vbox->layout()->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetCutScene(bool))); slider = new QSlider(Qt::Horizontal, vbox); vbox->layout()->addWidget(slider); slider->show(); slider->setRange(1, 1000); slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); slider->setValue(500); connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetTopDistance(int))); cb = new QCheckBox("Top View", vbox); vbox->layout()->addWidget(cb); cb->setChecked(false); connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetTopView(bool))); vbox = new QGroupBox("PVS Errors", this); layout()->addWidget(vbox); vl = new QVBoxLayout; vbox->setLayout(vl); mPvsErrorWidget = new QListWidget(vbox); vbox->layout()->addWidget(mPvsErrorWidget); connect(mPvsErrorWidget, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(PvsErrorClicked(const QModelIndex &))); QPushButton *button = new QPushButton("Next Error Frame", vbox); vbox->layout()->addWidget(button); connect(button, SIGNAL(clicked(void)), SLOT(FocusNextPvsErrorFrame(void))); setWindowTitle("Preprocessor Control Widget"); adjustSize(); } void RendererControlWidget::FocusNextPvsErrorFrame(void) { } void RendererControlWidget::UpdatePvsErrorItem(int row, GlRendererBuffer::PvsErrorEntry &pvsErrorEntry) { QListWidgetItem *i = mPvsErrorWidget->item(row); QString s; s.sprintf("%5.5f", pvsErrorEntry.mError); if (i) { i->setText(s); } else { new QListWidgetItem(s, mPvsErrorWidget); } mPvsErrorWidget->update(); } GlRendererWidget::GlRendererWidget(SceneGraph *sceneGraph, ViewCellsManager *viewcells, KdTree *tree, QWidget * parent, const QGLWidget * shareWidget, Qt::WFlags f ) : GlRenderer(sceneGraph, viewcells, tree), QGLWidget(parent, shareWidget, f) { mTopView = false; mRenderViewCells = false; mTopDistance = 1.0f; mCutViewCells = false; mCutScene = false; mRenderErrors = false; mRenderFilter = true; mUseFilter = true; mUseSpatialFilter = true; mShowRenderCost = false; mShowPvsSizes = false; mSpatialFilterSize = 0.01; mPvsSize = 0; mRenderError = 0.0f; mControlWidget = new RendererControlWidget(NULL); connect(mControlWidget, SIGNAL(SetViewCellGranularity(int)), this, SLOT(SetViewCellGranularity(int))); connect(mControlWidget, SIGNAL(SetSceneCut(int)), this, SLOT(SetSceneCut(int))); connect(mControlWidget, SIGNAL(SetTopDistance(int)), this, SLOT(SetTopDistance(int))); connect(mControlWidget, SIGNAL(SetVisibilityFilterSize(int)), this, SLOT(SetVisibilityFilterSize(int))); connect(mControlWidget, SIGNAL(SetSpatialFilterSize(int)), this, SLOT(SetSpatialFilterSize(int))); connect(mControlWidget, SIGNAL(SetShowViewCells(bool)), this, SLOT(SetShowViewCells(bool))); connect(mControlWidget, SIGNAL(SetShowRenderCost(bool)), this, SLOT(SetShowRenderCost(bool))); connect(mControlWidget, SIGNAL(SetShowPvsSizes(bool)), this, SLOT(SetShowPvsSizes(bool))); connect(mControlWidget, SIGNAL(SetTopView(bool)), this, SLOT(SetTopView(bool))); connect(mControlWidget, SIGNAL(SetCutViewCells(bool)), this, SLOT(SetCutViewCells(bool))); connect(mControlWidget, SIGNAL(SetCutScene(bool)), this, SLOT(SetCutScene(bool))); connect(mControlWidget, SIGNAL(SetRenderErrors(bool)), this, SLOT(SetRenderErrors(bool))); connect(mControlWidget, SIGNAL(SetRenderFilter(bool)), this, SLOT(SetRenderFilter(bool))); connect(mControlWidget, SIGNAL(SetUseFilter(bool)), this, SLOT(SetUseFilter(bool))); connect(mControlWidget, SIGNAL(SetUseSpatialFilter(bool)), this, SLOT(SetUseSpatialFilter(bool))); mControlWidget->show(); } void GlRendererWidget::SetViewCellGranularity(int number) { if (mViewCellsManager) // mViewCellsManager->SetMaxFilterSize(number); mViewCellsManager->CollectViewCells(number); updateGL(); } void GlRendererWidget::SetVisibilityFilterSize(int number) { if (mViewCellsManager) mViewCellsManager->SetMaxFilterSize(number); updateGL(); } void GlRendererWidget::SetSpatialFilterSize(int number) { mSpatialFilterSize = 1e-3*number; updateGL(); } void GlRendererWidget::SetSceneCut(int number) { // assume the cut plane can only be aligned with xz plane // shift it along y according to number, which is percentage of the bounding // box position if (mViewCellsManager) { AxisAlignedBox3 box = mViewCellsManager->GetViewSpaceBox(); Vector3 p = box.Min() + (number/1000.0f)*box.Max(); mSceneCutPlane.mNormal = Vector3(0,-1,0); mSceneCutPlane.mD = -DotProd(mSceneCutPlane.mNormal, p); updateGL(); } } void GlRendererWidget::SetTopDistance(int number) { mTopDistance = number/1000.0f; updateGL(); } void GlRendererWidget::RenderViewCells() { mUseFalseColors = true; SetupCamera(); glEnable(GL_CULL_FACE); //glDisable(GL_CULL_FACE); glCullFace(GL_FRONT); double eq[4]; eq[0] = mSceneCutPlane.mNormal.x; eq[1] = mSceneCutPlane.mNormal.y; eq[2] = mSceneCutPlane.mNormal.z; eq[3] = mSceneCutPlane.mD; if (mCutViewCells) { glClipPlane(GL_CLIP_PLANE0, eq); glEnable(GL_CLIP_PLANE0); } int i; ViewCellContainer &viewcells = mViewCellsManager->GetViewCells(); int maxPvs = -1; for (i=0; i < viewcells.size(); i++) { ViewCell *vc = viewcells[i]; int p = vc->GetPvs().GetSize(); if (p > maxPvs) maxPvs = p; } for (i=0; i < viewcells.size(); i++) { ViewCell *vc = viewcells[i]; // Mesh *m = vc->GetMesh(); RgbColor c; if (!mShowPvsSizes) c = vc->GetColor(); else { float importance = (float)vc->GetPvs().GetSize() / (float)maxPvs; c = RgbColor(importance, 1.0f - importance, 0.0f); } glColor3f(c.r, c.g, c.b); RenderViewCell(vc); } glDisable(GL_CLIP_PLANE0); } void GlRendererBuffer::SampleBeamContributions(Intersectable *sourceObject, Beam &beam, const int desiredSamples, BeamSampleStatistics &stat) { // TODO: should be moved out of here (not to be done every time) // only back faces are interesting for the depth pass glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); // needed to kill the fragments for the front buffer glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); // assumes that the beam is constructed and contains kd-tree nodes // and viewcells which it intersects // Get the number of viewpoints to be sampled // Now it is a sqrt but in general a wiser decision could be made. // The less viewpoints the better for rendering performance, since less passes // over the beam is needed. // The viewpoints could actually be generated outside of the bounding box which // would distribute the 'efective viewpoints' of the object surface and thus // with a few viewpoints better sample the viewpoint space.... //TODO: comment in //int viewPointSamples = sqrt((float)desiredSamples); int viewPointSamples = max(desiredSamples / (GetWidth() * GetHeight()), 1); // the number of direction samples per pass is given by the number of viewpoints int directionalSamples = desiredSamples / viewPointSamples; Debug << "directional samples: " << directionalSamples << endl; for (int i = 0; i < viewPointSamples; ++ i) { Vector3 viewPoint = beam.mBox.GetRandomPoint(); // perhaps the viewpoint should be shifted back a little bit so that it always lies // inside the source object // 'ideally' the viewpoints would be distributed on the soureObject surface, but this // would require more complicated sampling (perhaps hierarchical rejection sampling of // the object surface is an option here - only the mesh faces which are inside the box // are considered as candidates) SampleViewpointContributions(sourceObject, viewPoint, beam, directionalSamples, stat); } // note: // this routine would be called only if the number of desired samples is sufficiently // large - for other rss tree cells the cpu based sampling is perhaps more efficient // distributing the work between cpu and gpu would also allow us to place more sophisticated // sample distributions (silhouette ones) using the cpu and the jittered once on the GPU // in order that thios scheme is working well the gpu render buffer should run in a separate // thread than the cpu sampler, which would not be such a big problem.... // disable alpha test again glDisable(GL_ALPHA_TEST); } void GlRendererBuffer::SampleViewpointContributions(Intersectable *sourceObject, const Vector3 viewPoint, Beam &beam, const int samples, BeamSampleStatistics &stat) { // 1. setup the view port to match the desired samples glViewport(0, 0, samples, samples); // 2. setup the projection matrix and view matrix to match the viewpoint + beam.mDirBox SetupProjectionForViewPoint(viewPoint, beam, sourceObject); // 3. reset z-buffer to 0 and render the source object for the beam // with glCullFace(Enabled) and glFrontFace(GL_CW) // save result to the front depth map // the front depth map holds ray origins // front depth buffer must be initialised to 0 float clearDepth; glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth); glClearDepth(0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //glFrontFace(GL_CW); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glColorMask(0, 0, 0, 0); // stencil is increased where the source object is located glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0x1, 0x1); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); #if 0 static int glSourceObjList = -1; if (glSourceObjList != -1) { glSourceObjList = glGenLists(1); glNewList(glSourceObjList, GL_COMPILE); RenderIntersectable(sourceObject); glEndList(); } glCallList(glSourceObjList); #else RenderIntersectable(sourceObject); #endif // copy contents of the front depth buffer into depth texture glBindTexture(GL_TEXTURE_2D, frontDepthMap); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, depthMapSize, depthMapSize); // reset clear function glClearDepth(clearDepth); // 4. set up the termination depth buffer (= standard depth buffer) // only rays which have non-zero entry in the origin buffer are valid since // they realy start on the object surface (this is tagged by setting a // stencil buffer bit at step 3). glStencilFunc(GL_EQUAL, 0x1, 0x1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthMask(1); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // setup front depth buffer glEnable(GL_TEXTURE_2D); // bind pixel shader implementing the front depth buffer functionality cgGLBindProgram(sCgFragmentProgram); cgGLEnableProfile(sCgFragmentProfile); // 5. render all objects inside the beam // we can use id based false color to read them back for gaining the pvs glColorMask(1, 1, 1, 1); // if objects not stored in beam => extract objects if (beam.mFlags & !Beam::STORE_OBJECTS) { vector::const_iterator it, it_end = beam.mKdNodes.end(); Intersectable::NewMail(); for (it = beam.mKdNodes.begin(); it != it_end; ++ it) { mKdTree->CollectObjects(*it, beam.mObjects); } } // (objects can be compiled to a gl list now so that subsequent rendering for // this beam is fast - the same hold for step 3) // Afterwards we have two depth buffers defining the ray origin and termination #if 0 static int glObjList = -1; if (glObjList != -1) { glObjList = glGenLists(1); glNewList(glObjList, GL_COMPILE); ObjectContainer::const_iterator it, it_end = beam.mObjects.end(); for (it = beam.mObjects.begin(); it != it_end; ++ it) { // render all objects except the source object if (*it != sourceObject) RenderIntersectable(*it); } glEndList(); } glCallList(glObjList); #else ObjectContainer::const_iterator it, it_end = beam.mObjects.end(); for (it = beam.mObjects.begin(); it != it_end; ++ it) { // render all objects except the source object if (*it != sourceObject) RenderIntersectable(*it); } #endif // 6. Use occlusion queries for all viewcell meshes associated with the beam -> // a fragment passes if the corresponding stencil fragment is set and its depth is // between origin and termination buffer // create new queries if necessary GenQueries((int)beam.mViewCells.size()); // check whether any backfacing polygon would pass the depth test? // matt: should check both back /front facing because of dual depth buffer // and danger of cutting the near plane with front facing polys. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); glDisable(GL_CULL_FACE); ViewCellContainer::const_iterator vit, vit_end = beam.mViewCells.end(); int queryIdx = 0; for (vit = beam.mViewCells.begin(); vit != vit_end; ++ vit) { glBeginOcclusionQueryNV(sQueries[queryIdx ++]); RenderIntersectable(*vit); glEndOcclusionQueryNV(); } // at this point, if possible, go and do some other computation // 7. The number of visible pixels is the number of sample rays which see the source // object from the corresponding viewcell -> remember these values for later update // of the viewcell pvs - or update immediately? queryIdx = 0; unsigned int pixelCount; for (vit = beam.mViewCells.begin(); vit != vit_end; ++ vit) { // fetch queries glGetOcclusionQueryuivNV(sQueries[queryIdx ++], GL_PIXEL_COUNT_NV, &pixelCount); if (pixelCount) Debug << "view cell " << (*vit)->GetId() << " visible pixels: " << pixelCount << endl; } // 8. Copmpute rendering statistics // In general it is not neccessary to remember to extract all the rays cast. I hope it // would be sufficient to gain only the intergral statistics about the new contributions // and so the rss tree would actually store no new rays (only the initial ones) // the subdivision of the tree would only be driven by the statistics (the glrender could // evaluate the contribution entropy for example) // However might be an option to extract/store only those the rays which made a contribution // (new viewcell has been discovered) or relative contribution greater than a threshold ... ObjectContainer pvsObj; stat.pvsSize = ComputePvs(beam.mObjects, pvsObj); // to gain ray source and termination // copy contents of ray termination buffer into depth texture // and compare with ray source buffer #if 0 VssRayContainer rays; glBindTexture(GL_TEXTURE_2D, backDepthMap); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, depthMapSize, depthMapSize); ComputeRays(Intersectable *sourceObj, rays); #endif //-- cleanup // reset gl state glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); glEnable(GL_CULL_FACE); glDisable(GL_STENCIL_TEST); cgGLDisableProfile(sCgFragmentProfile); glDisable(GL_TEXTURE_2D); // remove objects from beam if (beam.mFlags & !Beam::STORE_OBJECTS) beam.mObjects.clear(); } void GlRendererBuffer::GenQueries(const int numQueries) { if ((int)sQueries.size() < numQueries) { const int n = numQueries - (int)sQueries.size(); unsigned int *newQueries = new unsigned int[n]; glGenOcclusionQueriesNV(n, (unsigned int *)newQueries); for (int i = 0; i < n; ++ i) { sQueries.push_back(newQueries[i]); } delete [] newQueries; } } void GlRendererBuffer::SetupProjectionForViewPoint(const Vector3 &viewPoint, const Beam &beam, Intersectable *sourceObject) { float left, right, bottom, top, znear, zfar; beam.ComputePerspectiveFrustum(left, right, bottom, top, znear, zfar, mSceneGraph->GetBox()); //Debug << left << " " << right << " " << bottom << " " << top << " " << znear << " " << zfar << endl; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(left, right, bottom, top, znear, zfar); //glFrustum(-1, 1, -1, 1, 1, 20000); const Vector3 center = viewPoint + beam.GetMainDirection() * (zfar - znear) * 0.3f; const Vector3 up = Normalize(CrossProd(beam.mPlanes[0].mNormal, beam.mPlanes[4].mNormal)); #ifdef _DEBUG Debug << "view point: " << viewPoint << endl; Debug << "eye: " << center << endl; Debug << "up: " << up << endl; #endif glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(viewPoint.x, viewPoint.y, viewPoint.z, center.x, center.y, center.z, up.x, up.y, up.z); } void GlRendererBuffer::InitGL() { makeCurrent(); GlRenderer::InitGL(); #if 1 // initialise dual depth buffer textures glGenTextures(1, &frontDepthMap); glBindTexture(GL_TEXTURE_2D, frontDepthMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthMapSize, depthMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glGenTextures(1, &backDepthMap); glBindTexture(GL_TEXTURE_2D, backDepthMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthMapSize, depthMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); // cg initialization cgSetErrorCallback(handleCgError); sCgContext = cgCreateContext(); if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1)) sCgFragmentProfile = CG_PROFILE_ARBFP1; else { // try FP30 if (cgGLIsProfileSupported(CG_PROFILE_FP30)) sCgFragmentProfile = CG_PROFILE_FP30; else { Debug << "Neither arbfp1 or fp30 fragment profiles supported on this system" << endl; exit(1); } } sCgFragmentProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, "../src/dual_depth.cg", sCgFragmentProfile, NULL, NULL); if (!cgIsProgramCompiled(sCgFragmentProgram)) cgCompileProgram(sCgFragmentProgram); cgGLLoadProgram(sCgFragmentProgram); cgGLBindProgram(sCgFragmentProgram); Debug << "---- PROGRAM BEGIN ----\n" << cgGetProgramString(sCgFragmentProgram, CG_COMPILED_PROGRAM) << "---- PROGRAM END ----\n"; #endif doneCurrent(); } void GlRendererBuffer::ComputeRays(Intersectable *sourceObj, VssRayContainer &rays) { for (int i = 0; i < depthMapSize * depthMapSize; ++ i) { //todo glGetTexImage() } } inline bool ilt(Intersectable *obj1, Intersectable *obj2) { return obj1->mId < obj2->mId; } int GlRendererBuffer::ComputePvs(ObjectContainer &objects, ObjectContainer &pvs) const { int pvsSize = 0; QImage image = toImage(); Intersectable::NewMail(); std::stable_sort(objects.begin(), objects.end(), ilt); MeshInstance dummy(NULL); Intersectable *obj = NULL; for (int x = 0; x < image.width(); ++ x) { for (int y = 0; y < image.height(); ++ y) { QRgb pix = image.pixel(x, y); const int id = GetId(qRed(pix), qGreen(pix), qBlue(pix)); dummy.SetId(id); ObjectContainer::iterator oit = lower_bound(objects.begin(), objects.end(), &dummy, ilt); if (//(oit != oit.end()) && ((*oit)->GetId() == id) && !obj->Mailed()) { obj = *oit; obj->Mail(); ++ pvsSize; pvs.push_back(obj); } } } return pvsSize; } /***********************************************************************/ /* GlDebuggerWidget implementation */ /***********************************************************************/ GlDebuggerWidget::GlDebuggerWidget(GlRendererBuffer *buf, QWidget *parent) : QGLWidget(QGLFormat(QGL::SampleBuffers), parent), mRenderBuffer(buf) { // create the pbuffer //pbuffer = new QGLPixelBuffer(QSize(512, 512), format(), this); timerId = startTimer(20); setWindowTitle(("OpenGL pbuffers")); } GlDebuggerWidget::~GlDebuggerWidget() { mRenderBuffer->releaseFromDynamicTexture(); glDeleteTextures(1, &dynamicTexture); DEL_PTR(mRenderBuffer); } void GlDebuggerWidget::initializeGL() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 10, 100); glTranslatef(-0.5f, -0.5f, -0.5f); glTranslatef(0.0f, 0.0f, -15.0f); glMatrixMode(GL_MODELVIEW); glEnable(GL_CULL_FACE); initCommon(); initPbuffer(); } void GlDebuggerWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void GlDebuggerWidget::paintGL() { // draw a spinning cube into the pbuffer.. mRenderBuffer->makeCurrent(); BeamSampleStatistics stats; mRenderBuffer->SampleBeamContributions(mSourceObject, mBeam, mSamples, stats); glFlush(); // rendering directly to a texture is not supported on X11, unfortunately mRenderBuffer->updateDynamicTexture(dynamicTexture); // and use the pbuffer contents as a texture when rendering the // background and the bouncing cubes makeCurrent(); glBindTexture(GL_TEXTURE_2D, dynamicTexture); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw the background glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } void GlDebuggerWidget::initPbuffer() { // set up the pbuffer context mRenderBuffer->makeCurrent(); /*mRenderBuffer->InitGL(); glViewport(0, 0, mRenderBuffer->size().width(), mRenderBuffer->size().height()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1, 1, -1, 1, -99, 99); glTranslatef(-0.5f, -0.5f, 0.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);*/ // generate a texture that has the same size/format as the pbuffer dynamicTexture = mRenderBuffer->generateDynamicTexture(); // bind the dynamic texture to the pbuffer - this is a no-op under X11 mRenderBuffer->bindToDynamicTexture(dynamicTexture); makeCurrent(); } void GlDebuggerWidget::initCommon() { glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); } }