From 41df01263fab9489e3929a10de560f4c856d9fd5 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Sat, 9 Feb 2008 17:55:19 +0000 Subject: [PATCH] - Introducing rendering to multiple render targets. In order to allow more vertices to be processed by the hardware, MRTs became a necessity. In this way we can multiply by 4 or even by 8 (GF 8xxx +) the maximum number of vertices processed. - Texture size for vertices and normals are choosen automatically, picking the smallest one possible in order to greatly speeding up the calculations. - Max textures size is now 2048 for a couple of reasons.. - Small bugs fixed --- src/meshlabplugins/filter_ao/AOGLWidget.cpp | 3 +- src/meshlabplugins/filter_ao/filter_ao.cpp | 290 +++++++++++++------- src/meshlabplugins/filter_ao/filter_ao.h | 16 +- 3 files changed, 202 insertions(+), 107 deletions(-) diff --git a/src/meshlabplugins/filter_ao/AOGLWidget.cpp b/src/meshlabplugins/filter_ao/AOGLWidget.cpp index 9f05098e2..44844e00e 100644 --- a/src/meshlabplugins/filter_ao/AOGLWidget.cpp +++ b/src/meshlabplugins/filter_ao/AOGLWidget.cpp @@ -24,7 +24,8 @@ AOGLWidget::AOGLWidget (QWidget * parent, AmbientOcclusionPlugin *_plugin) :QGLW void AOGLWidget::initializeGL () { - plugin->initGL(cb); + plugin->initGL(cb,m->cm.vn); + setFixedSize(plugin->maxTexSize,plugin->maxTexSize); } diff --git a/src/meshlabplugins/filter_ao/filter_ao.cpp b/src/meshlabplugins/filter_ao/filter_ao.cpp index ab25839dc..d031304a6 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.cpp +++ b/src/meshlabplugins/filter_ao/filter_ao.cpp @@ -20,6 +20,18 @@ * for more details. * * * ****************************************************************************/ +/**************************************************************************** +History + +$Log$ +Revision 1.27 2008/02/09 17:55:19 mischitelli +- Introducing rendering to multiple render targets. In order to allow more vertices to be processed by the hardware, MRTs became a necessity. In this way we can multiply by 4 or even by 8 (GF 8xxx +) the maximum number of vertices processed. +- Texture size for vertices and normals are choosen automatically, picking the smallest one possible in order to greatly speeding up the calculations. +- Max textures size is now 2048 for a couple of reasons.. +- Small bugs fixed + + +****************************************************************************/ @@ -54,7 +66,7 @@ #include "AOGLWidget.h" #include -#define AMBOCC_MAX_TEXTURE_SIZE 4096 +#define AMBOCC_MAX_TEXTURE_SIZE 2048 #define AMBOCC_DEFAULT_TEXTURE_SIZE 512 #define AMBOCC_DEFAULT_NUM_VIEWS 128 #define AMBOCC_USEGPU_BY_DEFAULT false @@ -73,6 +85,7 @@ AmbientOcclusionPlugin::AmbientOcclusionPlugin() numViews = AMBOCC_DEFAULT_NUM_VIEWS; depthTexSize = AMBOCC_DEFAULT_TEXTURE_SIZE; depthTexArea = depthTexSize*depthTexSize; + maxTexSize = 16; } AmbientOcclusionPlugin::~AmbientOcclusionPlugin() @@ -131,24 +144,27 @@ void AmbientOcclusionPlugin::initParameterSet(QAction *action, MeshModel &m, Fil } bool AmbientOcclusionPlugin::applyFilter(QAction *filter, MeshModel &m, FilterParameterSet & par, vcg::CallBackPos *cb) { - assert(filter->text() == filterName(FP_AMBIENT_OCCLUSION)); useGPU = par.getBool("useGPU"); useVBO = par.getBool("useVBO"); depthTexSize = par.getInt("depthTexSize"); depthTexArea = depthTexSize*depthTexSize; numViews = par.getInt("reqViews"); + errInit = false; AOGLWidget *qWidget = new AOGLWidget(0,this); qWidget->cb = cb; qWidget->m = &m; qWidget->show(); //Ugly, but HAVE to be shown in order for it to work! - return true; + return !errInit; } bool AmbientOcclusionPlugin::processGL(AOGLWidget *aogl, MeshModel &m, vcg::CallBackPos *cb) { + if (errInit) + return false; + checkGLError::qDebug("start"); int tInitElapsed = 0; QTime tInit, tAll; @@ -212,16 +228,15 @@ bool AmbientOcclusionPlugin::processGL(AOGLWidget *aogl, MeshModel &m, vcg::Call // FIRST PASS - fill depth buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboDepth); - glBindTexture(GL_TEXTURE_2D, depthBufferTex); + //glBindTexture(GL_TEXTURE_2D, depthBufferTex); ///// non dovrebbe servire a na mazza glClear(GL_DEPTH_BUFFER_BIT); glColorMask(0, 0, 0, 0); renderMesh(m); glColorMask(1, 1, 1, 1); - glViewport(0,0,maxTexSize,maxTexSize); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboResult); - + glViewport(0,0,maxTexSize,maxTexSize); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); //final.rgba = min(2^31, src.rgba*1 + dest.rgba*1); @@ -267,18 +282,21 @@ bool AmbientOcclusionPlugin::processGL(AOGLWidget *aogl, MeshModel &m, vcg::Call { glDisable(GL_BLEND); - glDetachObjectARB(fboDepth, depthBufferTex); - glDetachObjectARB(fboResult, resultBufferTex); + glUseProgram(0); + glDeleteFramebuffersEXT(1, &fboDepth); glDeleteFramebuffersEXT(1, &fboResult); glDeleteTextures(1, &vertexCoordTex); glDeleteTextures(1, &vertexNormalsTex); - glDeleteTextures(1, &resultBufferTex); + glDeleteTextures(numTexPages, resultBufferTex); glDetachShader(shdrID, vs); glDetachShader(shdrID, fs); - glDeleteShader(shdrID); + glDeleteShader(shdrID); //executes but gives INVALID_OPERATION ( ?!?!? ) + + delete [] resultBufferTex; + delete [] resultBufferMRT; } glDeleteTextures(1, &depthBufferTex); @@ -289,10 +307,7 @@ bool AmbientOcclusionPlugin::processGL(AOGLWidget *aogl, MeshModel &m, vcg::Call delete [] occlusion; return true; -} // end processGL - - - +} void AmbientOcclusionPlugin::renderMesh(MeshModel &m) { m.glw.DrawFill(); @@ -300,49 +315,61 @@ void AmbientOcclusionPlugin::renderMesh(MeshModel &m) void AmbientOcclusionPlugin::initTextures(GLenum colorFormat, GLenum depthFormat) { - vertexCoordTex = 0; + unsigned int potTexSize = 0; + + vertexCoordTex = 0; vertexNormalsTex = 0; - resultBufferTex= 0; - glEnable( GL_TEXTURE_2D ); + resultBufferTex = new GLuint[numTexPages]; + + //**** find nearest POT size for numTexPages in order to use it as depth size in 3D Textures ****/ + for (potTexSize=1; potTexSize(&maxTexSize) ); - qDebug("max tex size: %d\n",maxTexSize); - - maxTexSize = std::min(maxTexSize, (unsigned int)AMBOCC_MAX_TEXTURE_SIZE); - - //cb(0, "Initializing: Glew"); - //*******INIT GLEW********/ + //cb(0, "Initializing: Glew"); GLint glewError = glewInit(); if (glewError) { Log(0,(const char*)glewGetErrorString(glewError)); - return false; + errInit = true; + return; } + + //*******QUERY HARDWARE FOR: MAX TEX SIZE********/ + glGetIntegerv(GL_MAX_TEXTURE_SIZE, reinterpret_cast(&maxTexSize) ); + maxTexSize = std::min(maxTexSize, (unsigned int)AMBOCC_MAX_TEXTURE_SIZE); + + //*******QUERY HARDWARE FOR: MAX NUMBER OF MRTs *********/ + unsigned int maxTexPages=1; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, reinterpret_cast(&maxTexPages) ); - //*******CHECK TEX SIZE********/ if (depthTexSize < 16) { Log(0, "Texture size is too small, 16x16 used instead"); @@ -394,9 +422,17 @@ bool AmbientOcclusionPlugin::initGL(vcg::CallBackPos *cb) depthTexSize = maxTexSize; depthTexArea = depthTexSize*depthTexSize; } + if ((maxTexSize*maxTexSize*maxTexPages) < numVertices && useGPU) + { + Log(0, "That's a really huge model, I can't handle it in hardware, sorry.."); + errInit = true; + return; + } //*******SET DEFAULT OPENGL STUFF**********/ glEnable( GL_DEPTH_TEST ); + glEnable( GL_TEXTURE_2D ); + glEnable( GL_TEXTURE_3D_EXT ); //*******CHECK THAT EVERYTHING IS SUPPORTED**********/ @@ -405,28 +441,49 @@ bool AmbientOcclusionPlugin::initGL(vcg::CallBackPos *cb) if ( !GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader ) { Log(0, "Your hardware doesn't support Shaders, which are required for hw occlusion"); - return false; + errInit = true; + return; } if ( !GLEW_EXT_framebuffer_object ) { Log(0, "Your hardware doesn't support FBOs, which are required for hw occlusion"); - return false; + errInit = true; + return; } if ( !GLEW_ARB_texture_float ) { Log(0,"Your hardware doesn't support FP16/32 textures, which are required for hw occlusion"); - return false; + errInit = true; + return; } - //cb(10, "Initializing: Textures"); - //GL_RGBA32/16F_ARB works on nv40+(GeForce6 or newer) and ATI hardware - initTextures(GL_RGBA32F_ARB, GL_DEPTH_COMPONENT); + //*******FIND BEST COMPROMISE BETWEEN TEX SIZE AND MRTs********/ + unsigned int smartTexSize; + for (smartTexSize=64; (smartTexSize*smartTexSize) < (numVertices/maxTexPages); smartTexSize*=2 ); + + if (smartTexSize > maxTexSize) + { + //should ever enter this point, just exit with error + Log(0,"There was an error while determining best texture size, unable to continue"); + errInit = true; + return; + } + + maxTexSize = smartTexSize; + numTexPages = std::min( (numVertices / (smartTexSize*smartTexSize))+1, maxTexPages); + resultBufferTex = new GLuint[numTexPages]; + resultBufferMRT = new GLenum[numTexPages]; + //*******LOAD SHADER*******/ //cb(30, "Initializing: Shaders"); set_shaders("ambient_occlusion",vs,fs,shdrID); + //*******INIT TEXTURES **********/ + //GL_RGBA32/16F_ARB works on nv40+(GeForce6 or newer) and ATI hardware + initTextures(GL_RGBA32F_ARB, GL_DEPTH_COMPONENT); + //*******INIT FBO*********/ //cb(60, "Initializing: FBOs"); @@ -440,7 +497,10 @@ bool AmbientOcclusionPlugin::initGL(vcg::CallBackPos *cb) glReadBuffer(GL_NONE); if (!checkFramebuffer()) - return false; + { + errInit = true; + return; + } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -448,11 +508,19 @@ bool AmbientOcclusionPlugin::initGL(vcg::CallBackPos *cb) fboResult = 0; glGenFramebuffersEXT(1, &fboResult); // FBO for second pass (1 color attachment) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboResult); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resultBufferTex, 0); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + for (unsigned int i=0; i vn; //Copies each vertex's position and normal in new vectors for (int i=0; i < m.cm.vn; ++i) @@ -516,25 +585,23 @@ void AmbientOcclusionPlugin::vertexCoordsToTexture(MeshModel &m) vertexPosition[i*4+3] = 1.0; //Normal vector for each vertex - vcg::Point3 n = m.cm.vert[i].N(); - vertexNormals[i*4+0] = n.X(); - vertexNormals[i*4+1] = n.Y(); - vertexNormals[i*4+2] = n.Z(); + vn = m.cm.vert[i].N(); + vertexNormals[i*4+0] = vn.X(); + vertexNormals[i*4+1] = vn.Y(); + vertexNormals[i*4+2] = vn.Z(); vertexNormals[i*4+3] = 1.0; } - //The aforementioned vectors are used to encode a texture that stores each vertex's position & normal - //Those texture are then used to perform a GPU occlusion test with each view's depth buffer - //Write vertex coordinates - glBindTexture(GL_TEXTURE_2D, vertexCoordTex); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, maxTexSize, maxTexSize, GL_RGBA, GL_FLOAT, vertexPosition); - delete [] vertexPosition; + glBindTexture(GL_TEXTURE_3D_EXT, vertexCoordTex); + glTexSubImage3D(GL_TEXTURE_3D_EXT, 0, 0, 0, 0, maxTexSize, maxTexSize, numTexPages, GL_RGBA, GL_FLOAT, vertexPosition); //Write normal directions - glBindTexture(GL_TEXTURE_2D, vertexNormalsTex); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, maxTexSize, maxTexSize, GL_RGBA, GL_FLOAT, vertexNormals); + glBindTexture(GL_TEXTURE_3D_EXT, vertexNormalsTex); + glTexSubImage3D(GL_TEXTURE_3D_EXT, 0, 0, 0, 0, maxTexSize, maxTexSize, numTexPages, GL_RGBA, GL_FLOAT, vertexNormals); + delete [] vertexNormals; + delete [] vertexPosition; } void AmbientOcclusionPlugin::setCamera(Point3f camDir, Box3f &meshBBox) @@ -590,12 +657,12 @@ void AmbientOcclusionPlugin::generateOcclusionHW() // Set vertex position texture glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, vertexCoordTex); + glBindTexture(GL_TEXTURE_3D_EXT, vertexCoordTex); glUniform1i(glGetUniformLocation(shdrID, "vTexture"), 1); // Set vertex normal texture glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, vertexNormalsTex); + glBindTexture(GL_TEXTURE_3D_EXT, vertexNormalsTex); glUniform1i(glGetUniformLocation(shdrID, "nTexture"), 2); // Set view direction @@ -604,6 +671,9 @@ void AmbientOcclusionPlugin::generateOcclusionHW() // Set ModelView-Projection Matrix glUniformMatrix4fv(glGetUniformLocation(shdrID, "mvprMatrix"), 1, GL_FALSE, (const GLfloat*)mv_pr_Matrix_f); + // Set total number of texture pages + glUniform1i(glGetUniformLocation(shdrID, "numTexPages"), numTexPages); + // Set texture Size glUniform1i(glGetUniformLocation(shdrID, "texSize"), depthTexSize); @@ -650,10 +720,12 @@ void AmbientOcclusionPlugin::generateOcclusionSW(MeshModel &m, GLfloat *occlusio int x = floor(resCoords[0]); int y = floor(resCoords[1]); + + vn = m.cm.vert[i].N(); if (resCoords[2] <= (GLdouble)dFloat[depthTexSize*y+x]) { - vn = m.cm.vert[i].N(); + //vn = m.cm.vert[i].N(); occlusion[i] += max(vn*cameraDir, 0.0f); } } @@ -662,30 +734,45 @@ void AmbientOcclusionPlugin::generateOcclusionSW(MeshModel &m, GLfloat *occlusio } void AmbientOcclusionPlugin::applyOcclusionHW(MeshModel &m) { - GLfloat *result = new GLfloat[maxTexSize*maxTexSize*4]; - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadPixels(0, 0, maxTexSize, maxTexSize, GL_RGBA, GL_FLOAT, result); + const unsigned int maxmax = maxTexSize*maxTexSize; + GLfloat *result = new GLfloat[maxmax*4]; + + unsigned int nVert=0; float maxvalue = 0.0f, minvalue = 100000.0f; - for (int i=0; i < m.cm.vn; i++) - { - if (result[i*4] < minvalue) - minvalue = result[i*4]; - if (result[i*4] > maxvalue) - maxvalue = result[i*4]; + for (unsigned int n=0; n maxvalue) + maxvalue = result[i*4]; + + m.cm.vert[maxmax*n+i].Q() = result[i*4]; + } + } float scale = 255.0f / (maxvalue - minvalue); + char scaledValue = 0; for (int i = 0; i < m.cm.vn; i++) { - m.cm.vert[i].Q() = result[i*4+0]; - m.cm.vert[i].C()[0] = (m.cm.vert[i].Q() - minvalue) * scale; - m.cm.vert[i].C()[1] = (m.cm.vert[i].Q() - minvalue) * scale; - m.cm.vert[i].C()[2] = (m.cm.vert[i].Q() - minvalue) * scale; - } + scaledValue = (char)((m.cm.vert[i].Q() - minvalue) * scale); + m.cm.vert[i].C()[0] = scaledValue; + m.cm.vert[i].C()[1] = scaledValue; + m.cm.vert[i].C()[2] = scaledValue; + } + delete [] result; } @@ -790,7 +877,8 @@ void AmbientOcclusionPlugin::dumpFloatTexture(QString filename, float *texdata, for (int i=0; i(filename.data()) ,"wb+"); + FILE *f; + fopen_s(&f, reinterpret_cast(filename.data()) ,"wb+"); fwrite(cdata,sizeof(unsigned char),elems,f); fclose(f); diff --git a/src/meshlabplugins/filter_ao/filter_ao.h b/src/meshlabplugins/filter_ao/filter_ao.h index bc5a5e4b8..e2872a8e0 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.h +++ b/src/meshlabplugins/filter_ao/filter_ao.h @@ -38,22 +38,27 @@ class AmbientOcclusionPlugin : public QObject, public MeshFilterInterface Q_INTERFACES(MeshFilterInterface) // Attributes -public: +protected: Point3f cameraDir; GLuint fboDepth, fboResult, depthBufferTex, vertexCoordTex, vertexNormalsTex, - resultBufferTex; + *resultBufferTex; + + GLenum *resultBufferMRT; unsigned int numViews, depthTexSize, depthTexArea, - maxTexSize; + numTexPages; bool useGPU, - useVBO; + useVBO, + errInit; +public: + unsigned int maxTexSize; // Methods public: @@ -77,7 +82,8 @@ public: vcg::CallBackPos * cb) ; void initTextures (GLenum colorFormat, GLenum depthFormat); - bool initGL (vcg::CallBackPos *cb); + void initGL (vcg::CallBackPos *cb, + unsigned int numVertices); bool processGL (AOGLWidget *glw, MeshModel &m, vcg::CallBackPos *cb);