45 #include <ACG/GL/GLFormatInfo.hh> 46 #include <ACG/GL/ShaderCache.hh> 47 #include <ACG/GL/ScreenQuad.hh> 48 #include <ACG/ShaderUtils/GLSLShader.hh> 50 #include <ACG/GL/FBO.hh> 52 #include "FilterKernels.hh" 63 BaseSeparableFilterKernel::BaseSeparableFilterKernel(
int _texWidth,
int _texHeight, GLenum _internalfmt )
64 : texWidth_(_texWidth),
65 texHeight_(_texHeight),
66 internalfmt_(_internalfmt),
67 externalfmt_(_internalfmt),
71 texelSize_ =
ACG::Vec2f(1.0f /
float(_texWidth), 1.0f /
float(_texHeight));
81 bool BaseSeparableFilterKernel::execute( GLuint _srcTexture,
ACG::FBO* _dstFBO, GLuint _dstColorAttachment, GLuint _tempColorAttachment )
85 GLuint tempTexture = 0;
86 if (!_dstFBO || !_tempColorAttachment)
88 tempTexture = tempRT_->getAttachment(GL_COLOR_ATTACHMENT0);
92 tempRT_->attachTexture2D(GL_COLOR_ATTACHMENT0, texWidth_, texHeight_, internalfmt_, externalfmt_, GL_CLAMP, GL_LINEAR, GL_LINEAR);
94 tempTexture = tempRT_->getAttachment(GL_COLOR_ATTACHMENT0);
106 glGetIntegerv(GL_VIEWPORT, vp);
107 glViewport(0, 0, texWidth_, texHeight_);
112 if (_tempColorAttachment && _dstFBO)
115 glDrawBuffer(_tempColorAttachment);
121 glDrawBuffer(GL_COLOR_ATTACHMENT0);
139 if (_dstFBO && _dstColorAttachment)
142 glDrawBuffer(_dstColorAttachment);
152 passShader = setupPass(1, tempTexture);
162 glViewport(vp[0], vp[1], vp[2], vp[3]);
167 void BaseSeparableFilterKernel::resizeInput(
int _texWidth,
int _texHeight )
169 if ( (texWidth_ != _texWidth || texHeight_ != _texHeight) )
171 texWidth_ = _texWidth;
172 texHeight_ = _texHeight;
173 texelSize_ =
ACG::Vec2f(1.0f /
float(_texWidth), 1.0f /
float(_texHeight));
175 if (tempRT_->width())
176 tempRT_->resize(_texWidth, _texHeight);
185 GaussianBlurFilter::GaussianBlurFilter(
int _texWidth,
189 GLenum _internalfmt )
191 radius_(_blurRadius),
204 void GaussianBlurFilter::updateKernel()
215 weights_[radius_] = 1.0f;
217 float weightSum = 1.0f;
220 for (
int i = 0; i < radius_; ++i)
225 offsetsX_[radius_ + i + 1] =
ACG::Vec2f(v[0], 0.0f);
228 offsetsY_[radius_ + i + 1] =
ACG::Vec2f(0.0f, v[1]);
231 float w = expf(-
float((i+1)*(i+1)) / (sigma_ * sigma_));
232 weights_[radius_ + i + 1] = weights_[i] = w;
233 weightSum += 2.0f * w;
239 weights_[i] /= weightSum;
241 QString blurSamplesMacro = QString(
"#define BLUR_SAMPLES %1").arg(samples_);
243 macros_.push_back(blurSamplesMacro);
248 void GaussianBlurFilter::setKernel(
int _blurRadius,
float _blurSigma )
250 radius_ = _blurRadius;
255 GLSL::Program* GaussianBlurFilter::setupPass(
int _pass, GLuint _srcTex)
269 glActiveTexture(GL_TEXTURE0);
270 glBindTexture(GL_TEXTURE_2D, _srcTex);
278 glBindTexture(GL_TEXTURE_2D, _srcTex);
288 BilateralBlurFilter::BilateralBlurFilter(
int _texWidth,
int _texHeight,
294 radius_(_blurRadius),
296 sigma_(_blurSigmaS, _blurSigmaR),
308 void BilateralBlurFilter::updateKernel()
312 sigma2Rcp_ =
ACG::Vec2f(-1.0f / (2.0f * sigma_[0] * sigma_[0]),
313 -1.0f / (2.0f * sigma_[1] * sigma_[1]));
326 spatialKernel_[radius_] = 0.0f;
329 for (
int i = 0; i < radius_; ++i)
334 offsetsX_[radius_ + i + 1] =
ACG::Vec2f(v[0], 0.0f);
337 offsetsY_[radius_ + i + 1] =
ACG::Vec2f(0.0f, v[1]);
340 float r2 = float((i+1)*(i+1));
341 spatialKernel_[radius_ + i + 1] = spatialKernel_[i] = r2 * sigma2Rcp_[0];
347 QString radiusMacro = QString(
"#define BLUR_SAMPLES %1").arg(
samples_);
349 int numChannels =
GLFormatInfo(internalFormat()).channelCount();
350 numChannels = std::max(std::min(numChannels, 4), 1);
352 const char* blurChannels[4] =
361 QString channelMacro = QString(
"#define BLUR_CHANNELS %1").arg(blurChannels[numChannels - 1]);
363 macros_.push_back(radiusMacro);
364 macros_.push_back(channelMacro);
367 void BilateralBlurFilter::setKernel(
int _blurRadius,
float _blurSigmaS,
float _blurSigmaR )
369 radius_ = _blurRadius;
370 sigma_ =
ACG::Vec2f(_blurSigmaS, _blurSigmaR);
374 GLSL::Program* BilateralBlurFilter::setupPass(
int _pass, GLuint _srcTex)
388 blurShader->
setUniform(
"g_BlurSigmaRcp2", sigma2Rcp_[1]);
392 glActiveTexture(GL_TEXTURE1);
393 glBindTexture(GL_TEXTURE_2D, depthTex_);
395 glActiveTexture(GL_TEXTURE0);
396 glBindTexture(GL_TEXTURE_2D, _srcTex);
404 glBindTexture(GL_TEXTURE_2D, _srcTex);
414 RadialBlurFilter::RadialBlurFilter(
int _numSamples )
417 setKernel(_numSamples);
420 bool RadialBlurFilter::execute( GLuint _srcTexture,
float _blurRadius,
float _blurIntensity,
const ACG::Vec2f& _blurCenter )
426 glActiveTexture(GL_TEXTURE0);
427 glBindTexture(GL_TEXTURE_2D, _srcTexture);
433 blurShader->
setUniform(
"g_BlurCenter", _blurCenter);
434 blurShader->
setUniform(
"g_BlurRadiusRcp2", 1.0f / (_blurRadius * _blurRadius));
435 blurShader->
setUniform(
"g_BlurIntensity", _blurIntensity);
445 void RadialBlurFilter::setKernel(
int _numSamples )
451 QString sampleMacro = QString(
"#define BLUR_SAMPLES %1").arg(_numSamples);
452 macros_.push_back(sampleMacro);
458 PoissonBlurFilter::PoissonBlurFilter(
float _radius,
float _sampleDistance,
int _numTris,
bool _disk,
bool _tilingCheck)
459 : radius_(_radius), sampleDistance_(_sampleDistance), numTries_(_numTris), disk_(_disk)
472 float cellSize = _sampleDistance / sqrtf(2.0f);
474 int gridSize = int(2.0f * _radius / cellSize) + 1;
476 std::vector<int> grid(gridSize * gridSize, -1);
487 x0 =
ACG::Vec2f(
float(rand()) /
float(RAND_MAX),
float(rand()) /
float(RAND_MAX));
488 }
while ((x0 * 2.0f -
ACG::Vec2f(1.0f, 1.0f)).sqrnorm() > _radius*_radius);
490 x0 = x0 * 2.0f * _radius;
492 std::list<int> activeList;
496 activeList.push_back(0);
499 ACG::Vec2i gridPos0(
int(x0[0] / cellSize),
int(x0[1] / cellSize));
501 grid[gridPos0[1] * gridSize + gridPos0[0]] = 0;
506 float sampleDistance2 = _sampleDistance * _sampleDistance;
508 while (!activeList.empty())
510 int listSize = activeList.size();
512 int i = int((
float(rand()) /
float(RAND_MAX)) *
float(listSize) + 0.5f);
514 i = std::min(i, listSize - 1);
518 std::list<int>::iterator it_i = activeList.begin();
519 for (
int counter = 0; it_i != activeList.end(); ++it_i, ++counter)
530 ACG::Vec2i gridPos_i(
int(x_i[0] / cellSize),
int(x_i[1] / cellSize));
532 bool foundNextSample_i =
false;
535 for (
int s = 0; s < _numTris; ++s)
537 float u = float(rand()) / float(RAND_MAX);
538 float v = float(rand()) / float(RAND_MAX);
540 float alpha = float(M_PI) * 2.0f * u;
544 x_s *= _sampleDistance + 2.0f * _sampleDistance * v;
549 ACG::Vec2i gridPos_s(
int(x_s[0] / cellSize),
int(x_s[1] / cellSize));
552 if (x_s[0] < 0.0f || x_s[1] < 0.0f || gridPos_s[0] < 0 || gridPos_s[0] >= gridSize || gridPos_s[1] < 0 || gridPos_s[1] >= gridSize)
556 if (_disk && (x_s -
ACG::Vec2f(_radius, _radius)).sqrnorm() > _radius*_radius)
559 else if (!_disk && (x_s[0] > _radius * 2.0f || x_s[1] > _radius * 2.0f))
564 bool tooClose =
false;
566 for (
int x = -1; x <= 1 && !tooClose; ++x)
568 for (
int y = -1; y <= 1 && !tooClose; ++y)
576 if (gridPos_t[0] < 0 || gridPos_t[0] >= gridSize || gridPos_t[1] < 0 || gridPos_t[1] >= gridSize)
582 wrapShift[0] = _radius * 2.0f * float(x);
583 wrapShift[1] = _radius * 2.0f * float(y);
585 for (
int k = 0; k < 2; ++k)
586 gridPos_t[k] = (gridPos_t[k] + gridSize) % gridSize;
592 int gridValue = grid[gridPos_t[1] * gridSize + gridPos_t[0]];
597 float d2 = delta_t | delta_t;
599 if (d2 < sampleDistance2)
608 foundNextSample_i =
true;
610 grid[gridPos_s[1] * gridSize + gridPos_s[0]] = numSamples;
613 activeList.push_back(numSamples);
619 if (!foundNextSample_i)
622 activeList.erase(it_i);
628 for (
int i = 0; i < numSamples; ++i)
634 QString samplesMacro= QString(
"#define BLUR_SAMPLES %1").arg(numSamples);
635 macros_.push_back(samplesMacro);
646 std::fstream f(_filename, std::ios_base::out);
650 for (
size_t i = 0; i <
samples_.size(); ++i)
657 bool PoissonBlurFilter::execute( GLuint _srcTex,
float _kernelScale )
660 int n = numSamples();
661 for (
int i = 0; i < n; ++i)
662 samplesScaled_[i] =
samples_[i] * _kernelScale;
670 blurShader->
setUniform(
"g_SampleOffsets", &samplesScaled_[0], n);
672 glActiveTexture(GL_TEXTURE0);
673 glBindTexture(GL_TEXTURE_2D, _srcTex);
686 const int crossRadius = 2;
690 int w = _image->width(),
691 h = _image->height();
693 _image->fill(qRgb(255,255,255));
699 plotter.begin(_image);
700 plotter.setPen(QPen(qRgb(0, 0, 0)));
701 plotter.drawEllipse(0, 0, _image->width() - 1, _image->height() - 1);
706 for (
int i = 0; i < numSamples(); ++i)
711 s = s * 0.5f +
Vec2f(0.5f, 0.5f);
717 Vec2i pc(s[0] + 0.5f, s[1] + 0.5f);
719 for (
int k = -crossRadius; k <= crossRadius; ++k)
721 for (
int mirror = 0; mirror < 2; ++mirror)
723 Vec2i p = pc +
Vec2i(k * (mirror ? -1 : 1),k);
726 p[0] = std::min(std::max(p[0], 0), w-1);
727 p[1] = std::min(std::max(p[1], 0), h-1);
729 _image->setPixel(p[0], p[1], qRgb(255, 0, 0));
virtual ~BilateralBlurFilter()
Class destructor.
VectorT< signed int, 2 > Vec2i
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
void use()
Enables the program object for using.
VectorT< float, 2 > Vec2f
Namespace providing different geometric functions concerning angles.
void unbind()
unbind fbo, go to normal rendering mode
void plotSamples(QImage *_image)
plot samples on qt image
virtual ~BaseSeparableFilterKernel()
Class destructor.
virtual ~PoissonBlurFilter()
Class destructor.
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
void dumpSamples(const char *_filename)
dump samples as point cloud in obj format
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
bool bind()
bind the fbo and sets it as rendertarget
virtual ~GaussianBlurFilter()
Class destructor.
GLsizei samples_
sample count if multisampling
GLuint getAttachment(GLenum _attachment)
return attached texture id