From 5d7e49581cdc0de8976c7e88fc1960cbd61ffe14 Mon Sep 17 00:00:00 2001 From: Andrea Baldacci baldacci Date: Fri, 29 Jul 2011 17:15:16 +0000 Subject: [PATCH] Outliers removal has been simplified. No more ray tracing is done (too much slow) but just a super-sampling of the depth buffer. For each ray that we trace, we take multiple depth values near the point of intersection and we output only the median of these values. This description is also included in the SDF help. --- src/fgt/filter_sdfgpu/filter_sdfgpu.cpp | 40 ++--- src/fgt/filter_sdfgpu/filter_sdfgpu.h | 4 - .../filter_sdfgpu/shaders/calculateSdf.frag | 138 ++++++------------ 3 files changed, 55 insertions(+), 127 deletions(-) diff --git a/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp b/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp index d4d26d6ef..e1a28f282 100644 --- a/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp +++ b/src/fgt/filter_sdfgpu/filter_sdfgpu.cpp @@ -14,7 +14,7 @@ using namespace vcg; #define SDF_MAX_TEXTURE_SIZE 1024 #define PI 3.14159265358979323846264; -#define USEVBO_BY_DEFAULT false +#define USEVBO_BY_DEFAULT true #define PIXEL_COUNT_THRESHOLD 100 SdfGpuPlugin::SdfGpuPlugin() @@ -80,14 +80,16 @@ void SdfGpuPlugin::initParameterSet(QAction *action, MeshModel &m, RichParameter if(mAction == SDF_SDF) { - par.addParam(new RichBool("removeFalse",false,"Remove false intersections","For each" + par.addParam(new RichBool("removeFalse",true,"Remove false intersections","For each" "ray we check the normal at the point of intersection," "and ignore intersections where the normal at the intersection" "points is in the same direction as the point-of-origin" "(the same direction is defined as an angle difference less" "than 90) ")); - par.addParam(new RichBool("removeOutliers",false,"Remove outliers","Remove outliers")); + par.addParam(new RichBool("removeOutliers",false,"Remove outliers","The outliers removal is made on the fly with a supersampling of the depth buffer. " + "For each ray that we trace, we take multiple depth values near the point of intersection and we output only the median of these values. " + "Some mesh can benefit from this additional calculation. ")); } } @@ -95,9 +97,9 @@ QString SdfGpuPlugin::filterName(FilterIDType filterId) const { switch(filterId) { - case SDF_SDF : return QString("Shape diameter function"); + case SDF_SDF : return QString("Shape Diameter Function"); case SDF_DEPTH_COMPLEXITY : return QString("Depth complexity"); - case SDF_OBSCURANCE : return QString("Ambient obscurance"); + case SDF_OBSCURANCE : return QString("Volumetric obscurance"); default : assert(0); } @@ -166,26 +168,7 @@ bool SdfGpuPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterS mRemoveFalse = pars.getBool("removeFalse"); mRemoveOutliers = pars.getBool("removeOutliers"); - if(mRemoveOutliers) - { - //Uniform sampling of cone for GPU outliers removal - GenNormal::UniformCone(EXTRA_RAYS_REQUESTED, coneDirVec, math::ToRad(45.0), Point3f(0.0,0.0,1.0)); - - - for(int i = 0; i < EXTRA_RAYS_RESULTED; i++) - { - coneDirVec[i].Normalize(); - mConeRays[i] = coneDirVec[i].X(); - mConeRays[i+1] = coneDirVec[i].Y(); - mConeRays[i+2] = coneDirVec[i].Z(); - - Log(0, "Ray%i %f %f %f. Angle: %f", i,coneDirVec[i].X(), - coneDirVec[i].Y(), - coneDirVec[i].Z(), - math::ToDeg(vcg::Angle(coneDirVec[i],Point3f(0.0,0.0,1.0)))); - } - } } //MESH CLEAN UP setupMesh( md, mOnPrimitive ); @@ -324,6 +307,11 @@ bool SdfGpuPlugin::initGL(MeshModel& mm) return false; } + GLint maxColorAttachments; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments); + + + //INIT FBOs AND TEXs for(int i = 0; i < 3; i++) { @@ -358,6 +346,7 @@ bool SdfGpuPlugin::initGL(MeshModel& mm) mResultTexture = new FloatTexture2D( TextureFormat( GL_TEXTURE_2D, mResTextureDim, mResTextureDim, GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT ), TextureParams( GL_NEAREST, GL_NEAREST ) ); mDirsResultTexture = new FloatTexture2D( TextureFormat( GL_TEXTURE_2D, mResTextureDim, mResTextureDim, GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT ), TextureParams( GL_NEAREST, GL_NEAREST ) ); + mFboResult->attachTexture( mResultTexture->format().target(), mResultTexture->id(), GL_COLOR_ATTACHMENT0_EXT ); mFboResult->attachTexture( mDirsResultTexture->format().target(), mDirsResultTexture->id(), GL_COLOR_ATTACHMENT1_EXT ); @@ -743,10 +732,7 @@ void SdfGpuPlugin::calculateSdfHW(FramebufferObject* fboFront, FramebufferObject mSDFProgram->setUniform1i("removeFalse",0); if(mRemoveOutliers) - { mSDFProgram->setUniform1i("removeOutliers",1); - mSDFProgram->setUniform3fv("coneRays", mConeRays, EXTRA_RAYS_RESULTED); - } else mSDFProgram->setUniform1i("removeOutliers",0); diff --git a/src/fgt/filter_sdfgpu/filter_sdfgpu.h b/src/fgt/filter_sdfgpu/filter_sdfgpu.h index 84648095b..aece9a350 100644 --- a/src/fgt/filter_sdfgpu/filter_sdfgpu.h +++ b/src/fgt/filter_sdfgpu/filter_sdfgpu.h @@ -9,9 +9,6 @@ #include #include -#define EXTRA_RAYS_REQUESTED 10 -#define EXTRA_RAYS_RESULTED 40 //must match value in sdf shader - enum ONPRIMITIVE{ON_VERTICES=0, ON_FACES=1}; class SdfGpuPlugin : public QObject, public MeshFilterInterface @@ -119,7 +116,6 @@ public: GPUProgram* mObscuranceProgram; bool mRemoveFalse; bool mRemoveOutliers; - float mConeRays[EXTRA_RAYS_RESULTED*3]; GLuint mOcclusionQuery; GLuint mPixelCount; unsigned int mTempDepthComplexity; diff --git a/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag b/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag index c9cce9c5a..64a60350d 100644 --- a/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag +++ b/src/fgt/filter_sdfgpu/shaders/calculateSdf.frag @@ -25,7 +25,9 @@ Author: Andrea Baldacci baldacci85@hotmail.it */ -#define EXTRA_RAYS 40 + +#define MEDIAN_SEARCH_ITERATIONS 64 +#define EXTRA_VALS 81 uniform sampler2D vTexture; uniform sampler2D nTexture; @@ -42,8 +44,7 @@ uniform int firstRendering; uniform mat4 mvprMatrixINV; uniform int removeFalse; uniform int removeOutliers; -uniform vec3 coneRays[EXTRA_RAYS]; -float _vals[EXTRA_RAYS]; +float extraVals[EXTRA_VALS]; @@ -73,84 +74,13 @@ bool isFalseIntersection(vec3 P, vec3 objSpaceNormal) return false; } -//Based on the paper "Dynamic Parallax Occlusion Mapping with Approximate Soft Shadows" Natalya Tatarchuk ATI Research, Inc. -float TraceRay(vec2 P, vec3 dir, float sourceHeight) -{ - - int LinearSearchSteps = 256; - - float StepSize = 1.0/256.0; - float Depth = sourceHeight; //Initial depth is that of front vertex - int StepIndex = 0; - - float CurrD = 0.0; - float PrevD = sourceHeight; - - vec2 p1 = vec2(0.0); - vec2 p2 = vec2(0.0); - // Compute max displacement: - vec2 V = dir.xy*1.41422; - - // - float cotan = sqrt(length(dir)*length(dir) - dir.z*dir.z) / (dir.z); - - float coordStepSize = StepSize * cotan; - - vec2 coordOffset = vec2(0.0,0.0); - - - while(StepIndex < LinearSearchSteps) - { - Depth += StepSize; - coordOffset += V.xy * coordStepSize; - - vec2 tc = P + coordOffset; - - CurrD = texture2D( depthTextureBack, tc).r; - - if(CurrD < Depth) - { - p1 = vec2(Depth, CurrD); - p2 = vec2(Depth - StepSize, PrevD); - StepIndex = LinearSearchSteps; - } - else - { - - //no intersections found, the height map values along the edges is below one. - //In this case the parallax vector near the edges crosses the texture boundary without hitting any features - if(tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0) return 0.0; - - StepIndex++; - PrevD = CurrD; - } - } - - - //Linear approximation using current and last step - float d2 = p2.x - p2.y; - float d1 = p1.x - p1.y; - - float fDenominator = d2 - d1; - - if(fDenominator == 0.0) - { - - return 0.0; - } - //y=m0*x+b0 and y=m1*x+b1 intersection - float destHeight = (p1.x * d2 - p2.x * d1) / fDenominator; - - float sdf = sqrt((destHeight - sourceHeight)* (destHeight - sourceHeight) + length(coordOffset)*length(coordOffset)); - - return sdf; - -} float calculateSdf(vec3 P, vec3 objSpacePos, vec3 objSpaceNormal) { - + + + float sdf = 0.0; float zFront = texture2D(depthTextureFront, P.xy).r; @@ -172,46 +102,62 @@ float calculateSdf(vec3 P, vec3 objSpacePos, vec3 objSpaceNormal) else if ( zPrevBack <= P.z && P.z <= zBack ) sdf = max(0.0,(zBack-zFront) ) ; - if(removeFalse==1) - if( isFalseIntersection(P,objSpaceNormal) ) return 0.0; + + if(removeFalse==1) + if( isFalseIntersection(P,objSpaceNormal) ) return 0.0; + if( sdf != 0.0 && removeOutliers == 1) { - - - int i = 0; - + float mean = 0.0; float min_val = 100000.0; float max_val = 0.0; - for( ; i < EXTRA_RAYS ; i++ ) + int index = 0; + + for( float j = -4.0; j <= 4.0; j += 1.0 ) { - _vals[i] = TraceRay( P.xy, coneRays[i] , zFront ); + for( float i = -4.0; i <= 4.0 ; i += 1.0 ) + { + if(index >= EXTRA_VALS) return 0.0; + + + float s = texture2D(depthTextureBack, P.xy + vec2(j/texSize,i/texSize)).r; + + if(s == 1.0) break; + + extraVals[index] = s; - mean += _vals[i]; - min_val = min(_vals[i],min_val); - max_val = max(_vals[i], max_val); + mean += extraVals[index]; + min_val = min(extraVals[index],min_val); + max_val = max(extraVals[index], max_val); + + index++; + + } + } - - float trialMedian = mean/40.0; + index += 1; + + float trialMedian = mean/float(index); int counter = 0; - for(int n = 0; n < 10; n++) + for(int n = 0; n < MEDIAN_SEARCH_ITERATIONS; n++) { - for(int j = 0; j < EXTRA_RAYS ; j++ ) - if(_vals[j]>trialMedian ) counter++; + for(int j = 0; j < index; j++ ) + if( extraVals[j] > trialMedian ) counter++; - if(counter>20) + if( counter > (index/2) ) { trialMedian += (max_val - trialMedian)/2.0; min_val = trialMedian; } - else if(counter < 20) + else if( counter < (index/2) ) { trialMedian -= (trialMedian - min_val)/2.0; max_val = trialMedian; @@ -224,7 +170,7 @@ float calculateSdf(vec3 P, vec3 objSpacePos, vec3 objSpaceNormal) } - sdf = trialMedian; + sdf = max(0.0, trialMedian - zFront); }