51 #include <ACG/GL/ShaderCache.hh>
52 #include <ACG/GL/ScreenQuad.hh>
53 #include <ACG/GL/GLFormatInfo.hh>
54 #include <ACG/ShaderUtils/GLSLShader.hh>
56 #include <ACG/GL/FBO.hh>
58 #include "FilterKernels.hh"
69 BaseSeparableFilterKernel::BaseSeparableFilterKernel(
int _texWidth,
int _texHeight, GLenum _internalfmt )
70 : texWidth_(_texWidth),
71 texHeight_(_texHeight),
72 internalfmt_(_internalfmt),
73 externalfmt_(_internalfmt),
77 texelSize_ =
ACG::Vec2f(1.0f /
float(_texWidth), 1.0f /
float(_texHeight));
87 bool BaseSeparableFilterKernel::execute( GLuint _srcTexture,
ACG::FBO* _dstFBO, GLuint _dstColorAttachment, GLuint _tempColorAttachment )
91 GLuint tempTexture = 0;
92 if (!_dstFBO || !_tempColorAttachment)
98 tempRT_->
attachTexture2D(GL_COLOR_ATTACHMENT0, texWidth_, texHeight_, internalfmt_, externalfmt_, GL_CLAMP, GL_LINEAR, GL_LINEAR);
112 glGetIntegerv(GL_VIEWPORT, vp);
113 glViewport(0, 0, texWidth_, texHeight_);
118 if (_tempColorAttachment && _dstFBO)
121 glDrawBuffer(_tempColorAttachment);
127 glDrawBuffer(GL_COLOR_ATTACHMENT0);
145 if (_dstFBO && _dstColorAttachment)
148 glDrawBuffer(_dstColorAttachment);
158 passShader = setupPass(1, tempTexture);
168 glViewport(vp[0], vp[1], vp[2], vp[3]);
173 void BaseSeparableFilterKernel::resizeInput(
int _texWidth,
int _texHeight )
175 if ( (texWidth_ != _texWidth || texHeight_ != _texHeight) )
177 texWidth_ = _texWidth;
178 texHeight_ = _texHeight;
179 texelSize_ =
ACG::Vec2f(1.0f /
float(_texWidth), 1.0f /
float(_texHeight));
181 if (tempRT_->
width())
182 tempRT_->
resize(_texWidth, _texHeight);
191 GaussianBlurFilter::GaussianBlurFilter(
int _texWidth,
195 GLenum _internalfmt )
196 : BaseSeparableFilterKernel(_texWidth, _texHeight, _internalfmt),
197 radius_(_blurRadius),
198 samples_(2 * _blurRadius + 1),
210 void GaussianBlurFilter::updateKernel()
212 samples_ = radius_ * 2 + 1;
215 offsetsY_.resize(samples_);
223 float weightSum = 1.0f;
226 for (
int i = 0; i < radius_; ++i)
234 offsetsY_[radius_ + i + 1] =
ACG::Vec2f(0.0f, v[1]);
237 float w = expf(-
float((i+1)*(i+1)) / (
sigma_ *
sigma_));
239 weightSum += 2.0f * w;
244 for (
int i = 0; i < samples_; ++i)
247 QString blurSamplesMacro;
248 blurSamplesMacro.sprintf(
"#define BLUR_SAMPLES %i", samples_);
250 macros_.push_back(blurSamplesMacro);
255 void GaussianBlurFilter::setKernel(
int _blurRadius,
float _blurSigma )
257 radius_ = _blurRadius;
262 GLSL::Program* GaussianBlurFilter::setupPass(
int _pass, GLuint _srcTex)
276 glActiveTexture(GL_TEXTURE0);
277 glBindTexture(GL_TEXTURE_2D, _srcTex);
283 blurShader->
setUniform(
"g_SampleOffsets", &offsetsY_[0], samples_);
285 glBindTexture(GL_TEXTURE_2D, _srcTex);
295 BilateralBlurFilter::BilateralBlurFilter(
int _texWidth,
int _texHeight,
300 : BaseSeparableFilterKernel(_texWidth, _texHeight, _internalfmt),
301 radius_(_blurRadius),
302 samples_(2 * _blurRadius + 1),
303 sigma_(_blurSigmaS, _blurSigmaR),
315 void BilateralBlurFilter::updateKernel()
317 samples_ = radius_ * 2 + 1;
320 -1.0f / (2.0f * sigma_[1] * sigma_[1]));
326 offsetsY_.resize(samples_);
336 for (
int i = 0; i < radius_; ++i)
344 offsetsY_[radius_ + i + 1] =
ACG::Vec2f(0.0f, v[1]);
347 float r2 = float((i+1)*(i+1));
355 radiusMacro.sprintf(
"#define BLUR_SAMPLES %i", samples_);
358 numChannels = std::max(std::min(numChannels, 4), 1);
360 const char* blurChannels[4] =
368 QString channelMacro;
369 channelMacro.sprintf(
"#define BLUR_CHANNELS %s", blurChannels[numChannels - 1]);
371 macros_.push_back(radiusMacro);
372 macros_.push_back(channelMacro);
375 void BilateralBlurFilter::setKernel(
int _blurRadius,
float _blurSigmaS,
float _blurSigmaR )
377 radius_ = _blurRadius;
378 sigma_ =
ACG::Vec2f(_blurSigmaS, _blurSigmaR);
382 GLSL::Program* BilateralBlurFilter::setupPass(
int _pass, GLuint _srcTex)
400 glActiveTexture(GL_TEXTURE1);
401 glBindTexture(GL_TEXTURE_2D, depthTex_);
403 glActiveTexture(GL_TEXTURE0);
404 glBindTexture(GL_TEXTURE_2D, _srcTex);
410 blurShader->
setUniform(
"g_SampleOffsets", &offsetsY_[0], samples_);
412 glBindTexture(GL_TEXTURE_2D, _srcTex);
422 RadialBlurFilter::RadialBlurFilter(
int _numSamples )
425 setKernel(_numSamples);
428 bool RadialBlurFilter::execute( GLuint _srcTexture,
float _blurRadius,
float _blurIntensity,
const ACG::Vec2f& _blurCenter )
434 glActiveTexture(GL_TEXTURE0);
435 glBindTexture(GL_TEXTURE_2D, _srcTexture);
441 blurShader->
setUniform(
"g_BlurCenter", _blurCenter);
442 blurShader->
setUniform(
"g_BlurRadiusRcp2", 1.0f / (_blurRadius * _blurRadius));
443 blurShader->
setUniform(
"g_BlurIntensity", _blurIntensity);
453 void RadialBlurFilter::setKernel(
int _numSamples )
455 samples_ = _numSamples;
459 sampleMacro.sprintf(
"#define BLUR_SAMPLES %i", _numSamples);
460 macros_.push_back(sampleMacro);
467 PoissonBlurFilter::PoissonBlurFilter(
float _radius,
float _sampleDistance,
int _numTris )
468 : radius_(_radius), sampleDistance_(_sampleDistance), numTries_(_numTris)
481 float cellSize = _sampleDistance / sqrtf(2.0f);
483 int gridSize = int(2.0f * _radius / cellSize) + 1;
485 std::vector<int> grid(gridSize * gridSize, -1);
496 x0 =
ACG::Vec2f(
float(rand()) /
float(RAND_MAX),
float(rand()) /
float(RAND_MAX));
497 }
while ((x0 * 2.0f -
ACG::Vec2f(1.0f, 1.0f)).sqrnorm() > _radius*_radius);
499 x0 = x0 * 2.0f * _radius;
501 std::list<int> activeList;
503 samples_.reserve(32);
504 samples_.push_back(x0);
505 activeList.push_back(0);
508 ACG::Vec2i gridPos0(
int(x0[0] / cellSize),
int(x0[1] / cellSize));
510 grid[gridPos0[1] * gridSize + gridPos0[0]] = 0;
515 float sampleDistance2 = _sampleDistance * _sampleDistance;
517 while (!activeList.empty())
519 int listSize = activeList.size();
521 int i = int((
float(rand()) /
float(RAND_MAX)) *
float(listSize) + 0.5f);
523 i = std::min(i, listSize - 1);
527 std::list<int>::iterator it_i = activeList.begin();
528 for (
int counter = 0; it_i != activeList.end(); ++it_i, ++counter)
539 ACG::Vec2i gridPos_i(
int(x_i[0] / cellSize),
int(x_i[1] / cellSize));
541 bool foundNextSample_i =
false;
544 for (
int s = 0; s < _numTris; ++s)
546 float u = float(rand()) / float(RAND_MAX);
547 float v = float(rand()) / float(RAND_MAX);
549 float alpha = float(M_PI) * 2.0f * u;
553 x_s *= _sampleDistance + 2.0f * _sampleDistance * v;
558 ACG::Vec2i gridPos_s(
int(x_s[0] / cellSize),
int(x_s[1] / cellSize));
561 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)
565 if ( (x_s -
ACG::Vec2f(_radius, _radius)).sqrnorm() > _radius*_radius)
570 bool tooClose =
false;
572 for (
int x = -1; x <= 1 && !tooClose; ++x)
574 for (
int y = -1; y <= 1 && !tooClose; ++y)
579 if (gridPos_t[0] < 0 || gridPos_t[0] >= gridSize || gridPos_t[1] < 0 || gridPos_t[1] >= gridSize)
582 int gridValue = grid[gridPos_t[1] * gridSize + gridPos_t[0]];
586 ACG::Vec2f delta_t = samples_[gridValue] - x_s;
587 float d2 = delta_t | delta_t;
589 if (d2 < sampleDistance2)
598 foundNextSample_i =
true;
600 grid[gridPos_s[1] * gridSize + gridPos_s[0]] = numSamples;
601 samples_.push_back(x_s);
603 activeList.push_back(numSamples);
609 if (!foundNextSample_i)
612 activeList.erase(it_i);
618 for (
int i = 0; i < numSamples; ++i)
619 samples_[i] = samples_[i] -
ACG::Vec2f(_radius, _radius);
621 samplesScaled_ = samples_;
624 QString samplesMacro;
625 samplesMacro.sprintf(
"#define BLUR_SAMPLES %i", numSamples);
626 macros_.push_back(samplesMacro);
637 std::fstream f(_filename, std::ios_base::out);
641 for (
size_t i = 0; i < samples_.size(); ++i)
642 f <<
"v " << samples_[i][0] <<
" " << samples_[i][1] <<
" 0" << std::endl;
648 bool PoissonBlurFilter::execute( GLuint _srcTex,
float _kernelScale )
652 for (
int i = 0; i < n; ++i)
653 samplesScaled_[i] = samples_[i] * _kernelScale;
661 blurShader->
setUniform(
"g_SampleOffsets", &samplesScaled_[0], n);
663 glActiveTexture(GL_TEXTURE0);
664 glBindTexture(GL_TEXTURE_2D, _srcTex);
677 const int crossRadius = 2;
681 int w = _image->width(),
682 h = _image->height();
684 _image->fill(qRgb(255,255,255));
688 plotter.begin(_image);
689 plotter.setPen(QPen(qRgb(0,0,0)));
690 plotter.drawEllipse(0, 0, _image->width()-1, _image->height()-1);
697 Vec2f s = samples_[i];
699 s = s * 0.5f +
Vec2f(0.5f, 0.5f);
705 Vec2i pc(s[0] + 0.5f, s[1] + 0.5f);
707 for (
int k = -crossRadius; k <= crossRadius; ++k)
709 for (
int mirror = 0; mirror < 2; ++mirror)
711 Vec2i p = pc +
Vec2i(k * (mirror ? -1 : 1),k);
714 p[0] = std::min(std::max(p[0], 0), w-1);
715 p[1] = std::min(std::max(p[1], 0), h-1);
717 _image->setPixel(p[0], p[1], qRgb(255, 0, 0));
std::vector< ACG::Vec2f > offsetsX_
filter taps
VectorT< float, 2 > Vec2f
Namespace providing different geometric functions concerning angles.
VectorT< signed int, 2 > Vec2i
const ACG::Vec2f & texelSize() const
texel size in uv space
std::vector< float > spatialKernel_
precomputed sample -r^2 / (2 * sigma_s^2)
void attachTexture2D(GLenum _attachment, GLsizei _width, GLsizei _height, GLuint _internalFmt, GLenum _format, GLint _wrapMode=GL_CLAMP, GLint _minFilter=GL_NEAREST, GLint _magFilter=GL_NEAREST)
function to attach a texture to fbo
GLsizei width() const
get width of fbo texture
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
void plotSamples(QImage *_image)
plot samples on qt image
virtual ~GaussianBlurFilter()
Class destructor.
virtual ~BilateralBlurFilter()
Class destructor.
virtual ~BaseSeparableFilterKernel()
Class destructor.
int numSamples() const
number of samples
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
void use()
Enables the program object for using.
void resize(GLsizei _width, GLsizei _height, bool _forceResize=false)
resize function (if textures created by this class)
GLuint getAttachment(GLenum _attachment)
return attached texture id
QStringList macros_
shader macros
ACG::Vec2f sigma_
(sigmaS, sigmaR)
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
GLenum internalFormat() const
internal format of the input texture
std::vector< float > weights_
kernel weights
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
std::vector< ACG::Vec2f > offsetsX_
filter taps
void unbind()
unbind fbo, go to normal rendering mode
QStringList macros_
shader macros
void dumpSamples(const char *_filename)
dump samples as point cloud in obj format
bool bind()
bind the fbo and sets it as rendertarget
virtual ~PoissonBlurFilter()
Class destructor.
ACG::Vec2f sigma2Rcp_
-1 / (2 * sigma^2)