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;
242 blurSamplesMacro.sprintf(
"#define BLUR_SAMPLES %i", samples_);
244 macros_.push_back(blurSamplesMacro);
249 void GaussianBlurFilter::setKernel(
int _blurRadius,
float _blurSigma )
251 radius_ = _blurRadius;
256 GLSL::Program* GaussianBlurFilter::setupPass(
int _pass, GLuint _srcTex)
270 glActiveTexture(GL_TEXTURE0);
271 glBindTexture(GL_TEXTURE_2D, _srcTex);
279 glBindTexture(GL_TEXTURE_2D, _srcTex);
289 BilateralBlurFilter::BilateralBlurFilter(
int _texWidth,
int _texHeight,
295 radius_(_blurRadius),
297 sigma_(_blurSigmaS, _blurSigmaR),
309 void BilateralBlurFilter::updateKernel()
313 sigma2Rcp_ =
ACG::Vec2f(-1.0f / (2.0f * sigma_[0] * sigma_[0]),
314 -1.0f / (2.0f * sigma_[1] * sigma_[1]));
327 spatialKernel_[radius_] = 0.0f;
330 for (
int i = 0; i < radius_; ++i)
335 offsetsX_[radius_ + i + 1] =
ACG::Vec2f(v[0], 0.0f);
338 offsetsY_[radius_ + i + 1] =
ACG::Vec2f(0.0f, v[1]);
341 float r2 = float((i+1)*(i+1));
342 spatialKernel_[radius_ + i + 1] = spatialKernel_[i] = r2 * sigma2Rcp_[0];
349 radiusMacro.sprintf(
"#define BLUR_SAMPLES %i",
samples_);
351 int numChannels =
GLFormatInfo(internalFormat()).channelCount();
352 numChannels = std::max(std::min(numChannels, 4), 1);
354 const char* blurChannels[4] =
362 QString channelMacro;
363 channelMacro.sprintf(
"#define BLUR_CHANNELS %s", blurChannels[numChannels - 1]);
365 macros_.push_back(radiusMacro);
366 macros_.push_back(channelMacro);
369 void BilateralBlurFilter::setKernel(
int _blurRadius,
float _blurSigmaS,
float _blurSigmaR )
371 radius_ = _blurRadius;
372 sigma_ =
ACG::Vec2f(_blurSigmaS, _blurSigmaR);
376 GLSL::Program* BilateralBlurFilter::setupPass(
int _pass, GLuint _srcTex)
390 blurShader->
setUniform(
"g_BlurSigmaRcp2", sigma2Rcp_[1]);
394 glActiveTexture(GL_TEXTURE1);
395 glBindTexture(GL_TEXTURE_2D, depthTex_);
397 glActiveTexture(GL_TEXTURE0);
398 glBindTexture(GL_TEXTURE_2D, _srcTex);
406 glBindTexture(GL_TEXTURE_2D, _srcTex);
416 RadialBlurFilter::RadialBlurFilter(
int _numSamples )
419 setKernel(_numSamples);
422 bool RadialBlurFilter::execute( GLuint _srcTexture,
float _blurRadius,
float _blurIntensity,
const ACG::Vec2f& _blurCenter )
428 glActiveTexture(GL_TEXTURE0);
429 glBindTexture(GL_TEXTURE_2D, _srcTexture);
435 blurShader->
setUniform(
"g_BlurCenter", _blurCenter);
436 blurShader->
setUniform(
"g_BlurRadiusRcp2", 1.0f / (_blurRadius * _blurRadius));
437 blurShader->
setUniform(
"g_BlurIntensity", _blurIntensity);
447 void RadialBlurFilter::setKernel(
int _numSamples )
453 sampleMacro.sprintf(
"#define BLUR_SAMPLES %i", _numSamples);
454 macros_.push_back(sampleMacro);
460 PoissonBlurFilter::PoissonBlurFilter(
float _radius,
float _sampleDistance,
int _numTris,
bool _disk,
bool _tilingCheck)
461 : radius_(_radius), sampleDistance_(_sampleDistance), numTries_(_numTris), disk_(_disk)
474 float cellSize = _sampleDistance / sqrtf(2.0f);
476 int gridSize = int(2.0f * _radius / cellSize) + 1;
478 std::vector<int> grid(gridSize * gridSize, -1);
489 x0 =
ACG::Vec2f(
float(rand()) /
float(RAND_MAX),
float(rand()) /
float(RAND_MAX));
490 }
while ((x0 * 2.0f -
ACG::Vec2f(1.0f, 1.0f)).sqrnorm() > _radius*_radius);
492 x0 = x0 * 2.0f * _radius;
494 std::list<int> activeList;
498 activeList.push_back(0);
501 ACG::Vec2i gridPos0(
int(x0[0] / cellSize),
int(x0[1] / cellSize));
503 grid[gridPos0[1] * gridSize + gridPos0[0]] = 0;
508 float sampleDistance2 = _sampleDistance * _sampleDistance;
510 while (!activeList.empty())
512 int listSize = activeList.size();
514 int i = int((
float(rand()) /
float(RAND_MAX)) *
float(listSize) + 0.5f);
516 i = std::min(i, listSize - 1);
520 std::list<int>::iterator it_i = activeList.begin();
521 for (
int counter = 0; it_i != activeList.end(); ++it_i, ++counter)
532 ACG::Vec2i gridPos_i(
int(x_i[0] / cellSize),
int(x_i[1] / cellSize));
534 bool foundNextSample_i =
false;
537 for (
int s = 0; s < _numTris; ++s)
539 float u = float(rand()) / float(RAND_MAX);
540 float v = float(rand()) / float(RAND_MAX);
542 float alpha = float(M_PI) * 2.0f * u;
546 x_s *= _sampleDistance + 2.0f * _sampleDistance * v;
551 ACG::Vec2i gridPos_s(
int(x_s[0] / cellSize),
int(x_s[1] / cellSize));
554 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)
558 if (_disk && (x_s -
ACG::Vec2f(_radius, _radius)).sqrnorm() > _radius*_radius)
561 else if (!_disk && (x_s[0] > _radius * 2.0f || x_s[1] > _radius * 2.0f))
566 bool tooClose =
false;
568 for (
int x = -1; x <= 1 && !tooClose; ++x)
570 for (
int y = -1; y <= 1 && !tooClose; ++y)
578 if (gridPos_t[0] < 0 || gridPos_t[0] >= gridSize || gridPos_t[1] < 0 || gridPos_t[1] >= gridSize)
584 wrapShift[0] = _radius * 2.0f * float(x);
585 wrapShift[1] = _radius * 2.0f * float(y);
587 for (
int k = 0; k < 2; ++k)
588 gridPos_t[k] = (gridPos_t[k] + gridSize) % gridSize;
594 int gridValue = grid[gridPos_t[1] * gridSize + gridPos_t[0]];
599 float d2 = delta_t | delta_t;
601 if (d2 < sampleDistance2)
610 foundNextSample_i =
true;
612 grid[gridPos_s[1] * gridSize + gridPos_s[0]] = numSamples;
615 activeList.push_back(numSamples);
621 if (!foundNextSample_i)
624 activeList.erase(it_i);
630 for (
int i = 0; i < numSamples; ++i)
636 QString samplesMacro;
637 samplesMacro.sprintf(
"#define BLUR_SAMPLES %i", numSamples);
638 macros_.push_back(samplesMacro);
649 std::fstream f(_filename, std::ios_base::out);
653 for (
size_t i = 0; i <
samples_.size(); ++i)
660 bool PoissonBlurFilter::execute( GLuint _srcTex,
float _kernelScale )
663 int n = numSamples();
664 for (
int i = 0; i < n; ++i)
665 samplesScaled_[i] =
samples_[i] * _kernelScale;
673 blurShader->
setUniform(
"g_SampleOffsets", &samplesScaled_[0], n);
675 glActiveTexture(GL_TEXTURE0);
676 glBindTexture(GL_TEXTURE_2D, _srcTex);
689 const int crossRadius = 2;
693 int w = _image->width(),
694 h = _image->height();
696 _image->fill(qRgb(255,255,255));
702 plotter.begin(_image);
703 plotter.setPen(QPen(qRgb(0, 0, 0)));
704 plotter.drawEllipse(0, 0, _image->width() - 1, _image->height() - 1);
709 for (
int i = 0; i < numSamples(); ++i)
714 s = s * 0.5f +
Vec2f(0.5f, 0.5f);
720 Vec2i pc(s[0] + 0.5f, s[1] + 0.5f);
722 for (
int k = -crossRadius; k <= crossRadius; ++k)
724 for (
int mirror = 0; mirror < 2; ++mirror)
726 Vec2i p = pc +
Vec2i(k * (mirror ? -1 : 1),k);
729 p[0] = std::min(std::max(p[0], 0), w-1);
730 p[1] = std::min(std::max(p[1], 0), h-1);
732 _image->setPixel(p[0], p[1], qRgb(255, 0, 0));
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Namespace providing different geometric functions concerning angles.
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
virtual ~PoissonBlurFilter()
Class destructor.
void plotSamples(QImage *_image)
plot samples on qt image
VectorT< signed int, 2 > Vec2i
virtual ~GaussianBlurFilter()
Class destructor.
bool bind()
bind the fbo and sets it as rendertarget
VectorT< float, 2 > Vec2f
virtual ~BaseSeparableFilterKernel()
Class destructor.
void unbind()
unbind fbo, go to normal rendering mode
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
GLsizei samples_
sample count if multisampling
void dumpSamples(const char *_filename)
dump samples as point cloud in obj format
GLuint getAttachment(GLenum _attachment)
return attached texture id
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
virtual ~BilateralBlurFilter()
Class destructor.
void use()
Enables the program object for using.