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.

This commit is contained in:
Andrea Baldacci baldacci 2011-07-29 17:15:16 +00:00
parent adc5b82092
commit 5d7e49581c
3 changed files with 55 additions and 127 deletions

View File

@ -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<float>::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);

View File

@ -9,9 +9,6 @@
#include <framebufferObject.h>
#include <texture2D.h>
#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;

View File

@ -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);
}