From d749cc951d65e46e798c8fd979249218e48056ea Mon Sep 17 00:00:00 2001 From: Andrea Baldacci baldacci Date: Mon, 28 Mar 2011 20:49:20 +0000 Subject: [PATCH] The plugin interface has been refactored to include more filters. Added obscurance filtrer (not functional yet) and one for thin parts correction. --- src/fgt/filter_sdfgpu/filter_sdfgpu.cpp | 281 +++++++++++++++--- src/fgt/filter_sdfgpu/filter_sdfgpu.h | 37 ++- src/fgt/filter_sdfgpu/filter_sdfgpu.qrc | 1 + .../filter_sdfgpu/shaders/calculateSdf.frag | 2 +- .../filter_sdfgpu/shaders/obscurances.frag | 77 +++++ 5 files changed, 352 insertions(+), 46 deletions(-) create mode 100644 src/fgt/filter_sdfgpu/shaders/obscurances.frag diff --git a/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp b/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp index d684f34bb..90a406bc4 100644 --- a/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp +++ b/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp @@ -19,59 +19,114 @@ using namespace std; using namespace vcg; - #define SDF_MAX_TEXTURE_SIZE 1024 SdfGpuPlugin::SdfGpuPlugin() -: SingleMeshFilterInterface("Compute SDF GPU"), - mPeelingTextureSize(256) +: mPeelingTextureSize(256) { + typeList + << SDF_SDF + << SDF_CORRECTION_THIN_PARTS + << SDF_OBSCURANCE; + + foreach(FilterIDType tt , types()) + actionList << new QAction(filterName(tt), this); } -void SdfGpuPlugin::initParameterSet(MeshDocument&, RichParameterSet& par) +void SdfGpuPlugin::initParameterSet(QAction *action, MeshModel &m, RichParameterSet &par) { - qDebug() << "called here!"; - QStringList onPrimitive; onPrimitive.push_back("On vertices"); onPrimitive.push_back("On Faces"); - par.addParam( new RichEnum("onPrimitive", 0, onPrimitive, "Metric:", - "Choose whether to trace rays from faces or from vertices. " - "Recall that tracing from vertices will use vertex normal " - "estimation.")); - par.addParam( new RichInt("numberRays", 128, "Number of rays: ", - "The standard deviation of the rays that will be casted around " - "the anti-normals. Remember that most sampled directions are " - "expected to fall within 3x this value.")); - /* par.addParam(new RichFloat("lowQuantile", .1, "Bottom quantile", - "We will throw away the set of ray distances for each cone which distance " - "value falls under this quantile. Value in between [0,1]. 0 Implies all " - "values are kept")); - par.addParam(new RichFloat("hiQuantile", .9, "Top quantile", - "We will throw away the set of ray distances for each cone which distance " - "value falls under this quantile. Value in between [0,1]. 1 Implies all " - "values are kept"));*/ + qDebug() << "called here!"; + QStringList onPrimitive; onPrimitive.push_back("On vertices"); onPrimitive.push_back("On Faces"); + par.addParam( new RichEnum("onPrimitive", 0, onPrimitive, "Metric:", + "Choose whether to trace rays from faces or from vertices. " + "Recall that tracing from vertices will use vertex normal " + "estimation.")); + par.addParam( new RichInt("numberRays", 128, "Number of rays: ", + "The standard deviation of the rays that will be casted around " + "the anti-normals. Remember that most sampled directions are " + "expected to fall within 3x this value.")); + /* par.addParam(new RichFloat("lowQuantile", .1, "Bottom quantile", + "We will throw away the set of ray distances for each cone which distance " + "value falls under this quantile. Value in between [0,1]. 0 Implies all " + "values are kept")); + par.addParam(new RichFloat("hiQuantile", .9, "Top quantile", + "We will throw away the set of ray distances for each cone which distance " + "value falls under this quantile. Value in between [0,1]. 1 Implies all " + "values are kept"));*/ + par.addParam(new RichInt("DepthTextureSize", 512, "Depth texture size", + "Size of the depth texture for depth peeling")); + par.addParam(new RichInt("peelingIteration", 2, "Peeling Iteration", + "Number of depth peeling iteration")); + par.addParam(new RichFloat("peelingTolerance", 0.00005f, "Peeling Tolerance", + "We will throw away the set of ray distances for each cone which distance " )); + par.addParam(new RichFloat("depthTolerance", 0.0001f, "Depth tolerance", + "A small delta that is the minimal distance in depth between two vertex" )); + par.addParam(new RichFloat("minCos", 0.7f, "Min cosine", + "Min accepteded cosine of the angle between rays and vertex normals" )); + par.addParam(new RichFloat("maxCos", 1.0f, "Max cosine", + "Max accepteded cosine of the angle between rays and vertex normals" )); - par.addParam(new RichInt("DepthTextureSize", 512, "Depth texture size", - "Size of the depth texture for depth peeling")); + switch(mAction = ID(action)) + { + case SDF_CORRECTION_THIN_PARTS: + par.addParam(new RichFloat("minDist", 1.0f, "Min distance", + "Min distance to check too thin part of the mesh" )); + break; - par.addParam(new RichInt("peelingIteration", 2, "Peeling Iteration", - "Number of depth peeling iteration")); + case SDF_OBSCURANCE: + par.addParam(new RichFloat("obscuranceExponent", 1.0f, "Obscurance Exponent", + "Parameter that increase or decrease the exponential rise in obscurance function" )); + break; - par.addParam(new RichFloat("peelingTolerance", 0.00005f, "Peeling Tolerance", - "We will throw away the set of ray distances for each cone which distance " )); - par.addParam(new RichFloat("depthTolerance", 0.0001f, "Depth tolerance", - "A small delta that is the minimal distance in depth between two vertex" )); + default: + { - par.addParam(new RichFloat("minCos", 0.7f, "Min cosine", - "Min accepteded cosine of the angle between rays and vertex normals" )); - par.addParam(new RichFloat("maxCos", 1.0f, "Max cosine", - "Max accepteded cosine of the angle between rays and vertex normals" )); + break; + } + } + } -bool SdfGpuPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::CallBackPos* cb) +QString SdfGpuPlugin::filterName(FilterIDType filterId) const +{ + switch(filterId) + { + case SDF_SDF : return QString("Shape diamter function"); + case SDF_CORRECTION_THIN_PARTS : return QString("Correction of thin parts"); + case SDF_OBSCURANCE: return QString("Ambient obscurance"); + + default : assert(0); + } + + return QString(""); +} + + +QString SdfGpuPlugin::filterInfo(FilterIDType filterId) const +{ + switch(filterId) + { + case SDF_SDF : return QString("Calculate the shape diameter function on the mesh, you can visualize the result colorizing the mesh"); + case SDF_CORRECTION_THIN_PARTS : return QString("Checks and corrects too thin parts of the model"); + case SDF_OBSCURANCE : return QString("Generates environment obscurances values for the loaded mesh"); + default : assert(0); + } + + return QString(""); +} + +int SdfGpuPlugin::getRequirements(QAction *action) +{ + //no requirements needed + return 0; +} + +bool SdfGpuPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & pars, vcg::CallBackPos *cb) { MeshModel* mm = md.mm(); CMeshO& cm = mm->cm; @@ -87,6 +142,12 @@ bool SdfGpuPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::Ca mMaxCos = pars.getFloat("maxCos"); assert( onPrimitive==ON_VERTICES && "Face mode not supported yet" ); + if(mAction == SDF_OBSCURANCE) + mTau = pars.getFloat("obscuranceExponent"); + else if(mAction == SDF_CORRECTION_THIN_PARTS) + mMinDist = pars.getFloat("minDist"); + + //******* GL & MESH INIT **********/ setupMesh( md, onPrimitive ); initGL(cm.vn); @@ -96,14 +157,20 @@ bool SdfGpuPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::Ca std::vector unifDirVec; GenNormal::Uniform(numViews,unifDirVec); + Log(0, "Number of rays: %i ", unifDirVec.size() ); + for(vector::iterator vi = unifDirVec.begin(); vi != unifDirVec.end(); vi++) { (*vi).Normalize(); TraceRays(peel, mTolerance, *vi, md.mm()); } - applySdfHW(*mm,unifDirVec.size()); + if(mAction == SDF_SDF || mAction == SDF_CORRECTION_THIN_PARTS) + applySdfHW(*mm,unifDirVec.size()); + else + applyObscurance(*mm,unifDirVec.size()); + mm->glw.Update(); //******* CLEAN AND EXIT *************/ releaseGL(); @@ -190,8 +257,27 @@ bool SdfGpuPlugin::initGL(unsigned int numVertices) mSDFProgram->addUniform("mvprMatrix"); mSDFProgram->addUniform("viewpSize"); mSDFProgram->addUniform("texSize"); + mSDFProgram->addUniform("minCos"); + mSDFProgram->addUniform("maxCos"); mSDFProgram->disable(); + mObscuranceProgram = new GPUProgram("",":/SdfGpu/shaders/obscurances.frag",""); + mObscuranceProgram->enable(); + mObscuranceProgram->addUniform("vTexture"); + mObscuranceProgram->addUniform("nTexture"); + mObscuranceProgram->addUniform("depthTextureFront"); + mObscuranceProgram->addUniform("depthTextureBack"); + mObscuranceProgram->addUniform("viewDirection"); + mObscuranceProgram->addUniform("mvprMatrix"); + mObscuranceProgram->addUniform("viewpSize"); + mObscuranceProgram->addUniform("texSize"); + mObscuranceProgram->addUniform("minCos"); + mObscuranceProgram->addUniform("maxCos"); + mObscuranceProgram->addUniform("tau"); + mObscuranceProgram->addUniform("firstRendering"); + mObscuranceProgram->disable(); + + assert(mFboResult->isValid()); assert(mFboA->isValid()); assert(mFboB->isValid()); @@ -305,6 +391,11 @@ void SdfGpuPlugin::setupMesh(MeshDocument& md, ONPRIMITIVE onPrimitive ) break; } + if(mAction == SDF_OBSCURANCE) + { + mm->updateDataMask(MeshModel::MM_VERTCOLOR); + tri::UpdateColor::VertexConstant(m); + } //--- Use VBO // mm->glw.SetHint(vcg::GLW::HNUseVBO); mm->glw.Update(); @@ -399,9 +490,9 @@ void SdfGpuPlugin::calculateSdfHW(FramebufferObject& fboFront, FramebufferObject mSDFProgram->setUniform1f("depthTolerance", mDepthTolerance); -// mSDFProgram->setUniform1f("minCos", 0.7); + mSDFProgram->setUniform1f("minCos", mMinCos); -// mSDFProgram->setUniform1f("maxCos", 1.0); + mSDFProgram->setUniform1f("maxCos", mMaxCos); // Screen-aligned Quad @@ -439,6 +530,107 @@ void SdfGpuPlugin::applySdfHW(MeshModel &m, float numberOfRays) delete [] result; } +void SdfGpuPlugin::calculateObscurance(FramebufferObject& fboFront, FramebufferObject& fboBack, const Point3f& cameraDir, int first) +{ + mFboResult->bind(); + glViewport(0, 0, mResTextureDim, mResTextureDim); + GLfloat mv_pr_Matrix_f[16]; // modelview-projection matrix + + glGetFloatv(GL_MODELVIEW_MATRIX, mv_pr_Matrix_f); + glMatrixMode(GL_PROJECTION); + glMultMatrixf(mv_pr_Matrix_f); + glGetFloatv(GL_PROJECTION_MATRIX, mv_pr_Matrix_f); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Need to clear the depthBuffer if we don't + // want a mesh-shaped hole in the middle of the S.A.Q. :) + // glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glBlendEquation(GL_FUNC_ADD); + + glUseProgram(mObscuranceProgram->id()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, fboFront.getAttachedId(GL_DEPTH_ATTACHMENT)); + mObscuranceProgram->setUniform1i("depthTextureFront",0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, fboBack.getAttachedId(GL_DEPTH_ATTACHMENT)); + mObscuranceProgram->setUniform1i("depthTextureBack",1); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, mVertexCoordsTexture->id()); + mObscuranceProgram->setUniform1i("vTexture",2); + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, mVertexNormalsTexture->id()); + mObscuranceProgram->setUniform1i("nTexture",3); + + // Set view direction + mObscuranceProgram->setUniform3f("viewDirection", cameraDir.X(), cameraDir.Y(), cameraDir.Z()); + + // Set ModelView-Projection Matrix + mObscuranceProgram->setUniformMatrix4fv( "mvprMatrix", mv_pr_Matrix_f, 1, GL_FALSE ); + + // Set texture Size + mObscuranceProgram->setUniform1f("texSize", mPeelingTextureSize); + + // Set viewport Size + mObscuranceProgram->setUniform1f("viewpSize", mResTextureDim ); + + mObscuranceProgram->setUniform1f("depthTolerance", mDepthTolerance); + + mObscuranceProgram->setUniform1f("minCos", 0.7); + + mObscuranceProgram->setUniform1f("maxCos", 1.0); + + mObscuranceProgram->setUniform1f("tau", mTau); + + mObscuranceProgram->setUniform1i("firstRendering",first); + + // Screen-aligned Quad + glBegin(GL_QUADS); + glVertex3f(-1.0f, -1.0f, 0.0f); //L-L + glVertex3f( 1.0f, -1.0f, 0.0f); //L-R + glVertex3f( 1.0f, 1.0f, 0.0f); //U-R + glVertex3f(-1.0f, 1.0f, 0.0f); //U-L + glEnd(); + + mFboResult->unbind(); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); +} + +void SdfGpuPlugin::applyObscurance(MeshModel &m, float numberOfRays) +{ + const unsigned int texelNum = mResTextureDim*mResTextureDim; + + GLfloat *result = new GLfloat[texelNum*4]; + + mFboResult->bind(); + + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glReadPixels(0, 0, mResTextureDim, mResTextureDim, GL_RGBA, GL_FLOAT, result); + + for (int i=0; i < m.cm.vn; ++i) + { + m.cm.vert[i].Q() = result[i*4]; + m.cm.vert[i].C().Import(Color4f(result[i*4],result[i*4],result[i*4],1.0f)); + } + + mFboResult->unbind(); + + delete [] result; +} void SdfGpuPlugin::TraceRays(int peelingIteration, float tolerance, const Point3f& dir, MeshModel* mm ) { @@ -459,10 +651,17 @@ void SdfGpuPlugin::TraceRays(int peelingIteration, float tolerance, const Point3 mFboA->unbind(); //glDisable(GL_POLYGON_OFFSET_FILL); - if(i%2) - calculateSdfHW(*mFboB,*mFboA,dir); - + switch(mAction) + { + case SDF_SDF: + case SDF_CORRECTION_THIN_PARTS: + if(i%2) calculateSdfHW(*mFboB,*mFboA,dir); + break; + case SDF_OBSCURANCE: + if(!i%2) calculateObscurance(*mFboA,*mFboB,dir, i) ; + break; + } std::swap(mFboA,mFboB); } diff --git a/src/fgt/filter_sdfgpu/filter_sdfgpu.h b/src/fgt/filter_sdfgpu/filter_sdfgpu.h index c29f34cfc..0409054fb 100644 --- a/src/fgt/filter_sdfgpu/filter_sdfgpu.h +++ b/src/fgt/filter_sdfgpu/filter_sdfgpu.h @@ -1,7 +1,9 @@ #ifndef FILTER_SDFGPU_H #define FILTER_SDFGPU_H -#include +#include + +#include #include #include @@ -10,16 +12,33 @@ enum ONPRIMITIVE{ON_VERTICES, ON_FACES}; -class SdfGpuPlugin : public SingleMeshFilterInterface{ +class SdfGpuPlugin : public QObject, public MeshFilterInterface +{ Q_OBJECT Q_INTERFACES(MeshFilterInterface) + public: + + enum{ SDF_SDF, SDF_CORRECTION_THIN_PARTS, SDF_OBSCURANCE }; + SdfGpuPlugin(); + + QString filterName(FilterIDType filterId) const; + + QString filterInfo(FilterIDType filterId) const; + + int getRequirements(QAction *action); + + virtual FilterClass getClass(){ + return MeshFilterInterface::Generic; + } + + //main plugin function - bool applyFilter(MeshDocument&, RichParameterSet&, vcg::CallBackPos*); + bool applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb); //parameters init for user interface - virtual void initParameterSet(MeshDocument&, RichParameterSet &); + virtual void initParameterSet(QAction *action, MeshModel &m, RichParameterSet &parlst); //draw the mesh void fillFrameBuffer(bool front, MeshModel* mm); //mesh setup @@ -41,8 +60,13 @@ public: void applySdfHW(MeshModel &m, float numberOfRays); + void calculateObscurance(FramebufferObject& fboFront, FramebufferObject& fboBack, const vcg::Point3f& cameraDir, int first); + + void applyObscurance(MeshModel &m, float numberOfRays); + protected: + FilterIDType mAction; unsigned int mResTextureDim; FloatTexture2D* mResultTexture; FloatTexture2D* mVertexCoordsTexture; @@ -59,8 +83,13 @@ protected: float mDepthTolerance; float mMinCos; float mMaxCos; + //obscurance exponent + float mTau; + //min dist between vertices to check too thin parts + float mMinDist; GPUProgram* mDeepthPeelingProgram; GPUProgram* mSDFProgram; + GPUProgram* mObscuranceProgram; }; #endif // FILTER_SDFGPU_H diff --git a/src/fgt/filter_sdfgpu/filter_sdfgpu.qrc b/src/fgt/filter_sdfgpu/filter_sdfgpu.qrc index 515377d42..bb095e530 100644 --- a/src/fgt/filter_sdfgpu/filter_sdfgpu.qrc +++ b/src/fgt/filter_sdfgpu/filter_sdfgpu.qrc @@ -2,5 +2,6 @@ shaders/shaderDepthPeeling.fs shaders/calculateSdf.frag + shaders/obscurances.frag diff --git a/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag b/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag index 911a5e485..439f472ff 100644 --- a/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag +++ b/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag @@ -62,7 +62,7 @@ void main(void) float cosAngle = max(0.0,dot(N.xyz, viewDirection)); - if ( (zFront-depthTolerance) <= P.z && P.z <= (zFront+depthTolerance) && cosAngle >= 0.7 && cosAngle <= 1.0) + if ( (zFront-depthTolerance) <= P.z && P.z <= (zFront+depthTolerance) && cosAngle >= minCos && cosAngle <= maxCos) { sdf = max(0.0,(zBack-zFront) * cosAngle) ; diff --git a/src/fgt/filter_sdfgpu/shaders/obscurances.frag b/src/fgt/filter_sdfgpu/shaders/obscurances.frag new file mode 100644 index 000000000..8fea9ecc5 --- /dev/null +++ b/src/fgt/filter_sdfgpu/shaders/obscurances.frag @@ -0,0 +1,77 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#version 110 + +uniform sampler2D vTexture; +uniform sampler2D nTexture; +uniform sampler2D depthTextureFront; +uniform sampler2D depthTextureBack; +uniform vec3 viewDirection; +uniform mat4 mvprMatrix; +uniform float viewpSize; +uniform float texSize; +uniform float depthTolerance; +uniform float minCos; +uniform float maxCos; +uniform float tau; +uniform int firstRendering; + +vec4 project(vec4 coords) +{ + coords = mvprMatrix * coords; // clip space [-1 .. 1] + return vec4(coords.xyz * 0.5+0.5, coords.w); +} + + +void main(void) +{ + + float obscurance = 0.0; + // float PI = 3.14159265358979323846264; + vec2 coords = vec2(gl_FragCoord.xy/viewpSize); + vec4 V = texture2D(vTexture, coords); + vec4 N = texture2D(nTexture, coords); + + N = normalize(N); + + vec4 P = project(V); //* (viewpSize/texSize); + + + float zFront = texture2D(depthTextureFront, P.xy).r; + float zBack = texture2D(depthTextureBack, P.xy).r; + float cosAngle = max(0.0,dot(N.xyz, viewDirection)); + + + if ( (zFront-depthTolerance) <= P.z && P.z <= (zFront+depthTolerance) && cosAngle > 0.0) + { + + if(firstRendering != 0) + obscurance = (1.0 - exp(-tau*max(0.0,(zFront-zBack))))*cosAngle; + + else obscurance = cosAngle; + } + + + gl_FragColor = vec4( obscurance , obscurance , obscurance , 1.0); +} \ No newline at end of file