mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 02:40:00 +01:00
Original implementation of Blur Image Filters
With Gaussian, fast Gaussian, Hashed and morphological (opening and closing) methods. Remembering shader code for other fast methods.
This commit is contained in:
@@ -567,6 +567,9 @@ set(VMIX_RSC_FILES
|
||||
./rsc/shaders/filters/blur_1.glsl
|
||||
./rsc/shaders/filters/blur_2.glsl
|
||||
./rsc/shaders/filters/hashedblur.glsl
|
||||
./rsc/shaders/filters/circularblur.glsl
|
||||
./rsc/shaders/filters/hashederosion.glsl
|
||||
./rsc/shaders/filters/hasheddilation.glsl
|
||||
./rsc/shaders/filters/sharp.glsl
|
||||
./rsc/shaders/filters/sharpen.glsl
|
||||
./rsc/shaders/filters/sharpen_1.glsl
|
||||
|
||||
@@ -147,6 +147,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
|
||||
case FrameBufferFilter::FILTER_DELAY:
|
||||
filter_ = new DelayFilter;
|
||||
break;
|
||||
case FrameBufferFilter::FILTER_BLUR:
|
||||
filter_ = new BlurFilter;
|
||||
break;
|
||||
case FrameBufferFilter::FILTER_IMAGE:
|
||||
filter_ = new ImageFilter;
|
||||
break;
|
||||
@@ -157,7 +160,7 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
|
||||
}
|
||||
|
||||
|
||||
// TODO : resampling of renderbuffer
|
||||
// TODO : resampling of renderbuffer ?
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -81,8 +81,6 @@ FrameBuffer::FrameBuffer(glm::vec3 resolution, FrameBufferFlags flags): flags_(f
|
||||
attrib_.viewport = glm::ivec2(resolution);
|
||||
setProjectionArea(glm::vec2(1.f, 1.f));
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, 0.f);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[i] = 0;
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(uint width, uint height, FrameBufferFlags flags): flags_(flags),
|
||||
@@ -91,8 +89,6 @@ FrameBuffer::FrameBuffer(uint width, uint height, FrameBufferFlags flags): flags
|
||||
attrib_.viewport = glm::ivec2(width, height);
|
||||
setProjectionArea(glm::vec2(1.f, 1.f));
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, 0.f);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[i] = 0;
|
||||
}
|
||||
|
||||
void FrameBuffer::init()
|
||||
@@ -107,24 +103,16 @@ void FrameBuffer::init()
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
glTexStorage2D(GL_TEXTURE_2D, MIPMAP_LEVEL + 1, (flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
// calculate GPU memory usage
|
||||
int width = attrib_.viewport.x;
|
||||
int height = attrib_.viewport.y;
|
||||
for(int i=0; i < MIPMAP_LEVEL; ++i) {
|
||||
mem_usage_ += ( width * height * (flags_ & FrameBuffer_alpha?4:3) ) / 1024;
|
||||
width = MAX(1, (width / 2));
|
||||
height = MAX(1, (height / 2));
|
||||
}
|
||||
}
|
||||
// default : create simple texture for RGB(A)
|
||||
else {
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, (flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// calculate GPU memory usage
|
||||
mem_usage_ += ( attrib_.viewport.x * attrib_.viewport.y * (flags_ & FrameBuffer_alpha?4:3) ) / 1024;
|
||||
}
|
||||
|
||||
// calculate GPU memory usage (for debug only)
|
||||
mem_usage_ += ( attrib_.viewport.x * attrib_.viewport.y * (flags_ & FrameBuffer_alpha?4:3) ) / 1024;
|
||||
|
||||
// common texture parameters
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
@@ -179,12 +167,14 @@ void FrameBuffer::init()
|
||||
// attach multiple FBOs to the mipmaped texture
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
|
||||
glGenFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
for(int i=0; i < MIPMAP_LEVEL; ++i) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, i + 1);
|
||||
// calculate GPU memory usage
|
||||
int width = attrib_.viewport.x;
|
||||
int height = attrib_.viewport.y;
|
||||
for(int i=1; i < MIPMAP_LEVEL; ++i) {
|
||||
width = MAX(1, (width / 2));
|
||||
height = MAX(1, (height / 2));
|
||||
mem_usage_ += ( width * height * (flags_ & FrameBuffer_alpha?4:3) ) / 1024;
|
||||
}
|
||||
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
g_printerr("mipmap (%d) - ", MIPMAP_LEVEL);
|
||||
#endif
|
||||
@@ -208,8 +198,6 @@ FrameBuffer::~FrameBuffer()
|
||||
glDeleteFramebuffers(1, &framebufferid_);
|
||||
if (multisampling_framebufferid_)
|
||||
glDeleteFramebuffers(1, &multisampling_framebufferid_);
|
||||
if (mipmap_framebufferid_[0])
|
||||
glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
if (textureid_)
|
||||
glDeleteTextures(1, &textureid_);
|
||||
if (multisampling_textureid_)
|
||||
@@ -260,11 +248,6 @@ void FrameBuffer::resize(int width, int height)
|
||||
glDeleteFramebuffers(1, &multisampling_framebufferid_);
|
||||
multisampling_framebufferid_ = 0;
|
||||
|
||||
if (mipmap_framebufferid_[0])
|
||||
glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[i] = 0;
|
||||
|
||||
if (textureid_)
|
||||
glDeleteTextures(1, &textureid_);
|
||||
textureid_ = 0;
|
||||
@@ -305,28 +288,14 @@ void FrameBuffer::end()
|
||||
0, 0, attrib_.viewport.x, attrib_.viewport.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
// if mipmapped texture, fill FBOs
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
// First read full-size framebuffer
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
int width = attrib_.viewport.x;
|
||||
int height = attrib_.viewport.y;
|
||||
// iterate over all levels of mipmaps
|
||||
for(int i=0; i < MIPMAP_LEVEL; ++i) {
|
||||
// draw on Mipmap level i
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
// blit into half-sized mipmap i (with linear nearest color)
|
||||
glBlitFramebuffer(0, 0, width, height,
|
||||
0, 0, width / 2, height / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
// next iteration (i+1), read half-size mipmap level i
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
width = MAX(1, (width / 2));
|
||||
height = MAX(1, (height / 2));
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer::release();
|
||||
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
glBindTexture(GL_TEXTURE_2D, textureid_);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
Rendering::manager().popAttrib();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "RenderingManager.h"
|
||||
|
||||
#define FBI_JPEG_QUALITY 90
|
||||
#define MIPMAP_LEVEL 6
|
||||
#define MIPMAP_LEVEL 7
|
||||
|
||||
/**
|
||||
* @brief The FrameBufferImage class stores an RGB image in RAM
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
glm::mat4 projection_;
|
||||
glm::vec2 projection_area_;
|
||||
uint textureid_, multisampling_textureid_;
|
||||
uint framebufferid_, multisampling_framebufferid_, mipmap_framebufferid_[MIPMAP_LEVEL] = {};
|
||||
uint framebufferid_, multisampling_framebufferid_;
|
||||
uint mem_usage_;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "FrameBufferFilter.h"
|
||||
|
||||
const char* FrameBufferFilter::type_label[FrameBufferFilter::FILTER_INVALID] = {
|
||||
"None", "Delay", "Shader code"
|
||||
"None", "Delay", "Blur", "Shader code"
|
||||
};
|
||||
|
||||
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
typedef enum {
|
||||
FILTER_PASSTHROUGH = 0,
|
||||
FILTER_DELAY,
|
||||
FILTER_BLUR,
|
||||
FILTER_IMAGE,
|
||||
FILTER_INVALID
|
||||
} Type;
|
||||
|
||||
@@ -772,6 +772,52 @@ void ImGuiVisitor::visit (DelayFilter& f)
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (BlurFilter& f)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Blur ";
|
||||
|
||||
// Method selection
|
||||
if (ImGuiToolkit::IconButton(7, 16)) {
|
||||
f.setMethod( 0 );
|
||||
oss << BlurFilter::method_label[0];
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
int m = (int) f.method();
|
||||
if (ImGui::Combo("Method", &m, BlurFilter::method_label, IM_ARRAYSIZE(BlurFilter::method_label) )) {
|
||||
f.setMethod( m );
|
||||
oss << BlurFilter::method_label[m];
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
|
||||
|
||||
// List of parameters
|
||||
std::map<std::string, float> filter_parameters = f.program().parameters();
|
||||
for (auto param = filter_parameters.begin(); param != filter_parameters.end(); ++param)
|
||||
{
|
||||
ImGui::PushID( param->first.c_str() );
|
||||
float v = param->second;
|
||||
if (ImGuiToolkit::IconButton(13, 14)) {
|
||||
v = 0.f;
|
||||
f.setProgramParameter(param->first, v);
|
||||
}
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::SliderFloat( param->first.c_str(), &v, 0.f, 1.f, "%.2f")) {
|
||||
f.setProgramParameter(param->first, v);
|
||||
}
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
oss << BlurFilter::method_label[ f.method() ];
|
||||
oss << " : " << param->first << " " << std::setprecision(3) <<param->second;
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (ImageFilter& f)
|
||||
{
|
||||
// Selection of Algorithm
|
||||
@@ -781,7 +827,7 @@ void ImGuiVisitor::visit (ImageFilter& f)
|
||||
}
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::BeginCombo("##Filters", f.program().name().c_str()) )
|
||||
if (ImGui::BeginCombo("Algorithm", f.program().name().c_str()) )
|
||||
{
|
||||
for (auto p = FilteringProgram::presets.begin(); p != FilteringProgram::presets.end(); ++p){
|
||||
if (ImGui::Selectable( p->name().c_str() )) {
|
||||
@@ -791,26 +837,21 @@ void ImGuiVisitor::visit (ImageFilter& f)
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::Text("Algorithm");
|
||||
|
||||
// List of parameters
|
||||
std::map<std::string, float> filter_parameters = f.program().parameters();
|
||||
FilteringProgram target = f.program();
|
||||
for (auto param = filter_parameters.begin(); param != filter_parameters.end(); ++param)
|
||||
{
|
||||
ImGui::PushID( param->first.c_str() );
|
||||
float v = param->second;
|
||||
if (ImGuiToolkit::IconButton(11, 11)) {
|
||||
if (ImGuiToolkit::IconButton(13, 14)) {
|
||||
v = 0.f;
|
||||
target.setParameter(param->first, v);
|
||||
f.setProgram( target );
|
||||
f.setProgramParameter(param->first, v);
|
||||
}
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::SliderFloat( param->first.c_str(), &v, 0.f, 1.f, "%.2f")) {
|
||||
target.setParameter(param->first, v);
|
||||
f.setProgram( target );
|
||||
f.setProgramParameter(param->first, v);
|
||||
}
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
// TODO UNDO
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
void visit (FrameBufferFilter&) override;
|
||||
void visit (PassthroughFilter&) override;
|
||||
void visit (DelayFilter&) override;
|
||||
void visit (BlurFilter&) override;
|
||||
void visit (ImageFilter&) override;
|
||||
};
|
||||
|
||||
|
||||
167
ImageFilter.cpp
167
ImageFilter.cpp
@@ -128,6 +128,12 @@ std::string FilteringProgram::getFilterCodeDefault()
|
||||
return filterDefault;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
//// PROGRAM DEFINING A FILTER ///
|
||||
/// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
FilteringProgram::FilteringProgram() : name_("None"), code_({"shaders/filters/default.glsl",""}), two_pass_filter_(false)
|
||||
{
|
||||
|
||||
@@ -181,6 +187,12 @@ bool FilteringProgram::operator!= (const FilteringProgram& other) const
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
//// IMAGE SHADER FOR FILTERS ///
|
||||
/// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
class ImageFilteringShader : public ImageShader
|
||||
{
|
||||
// GLSL Program
|
||||
@@ -309,6 +321,12 @@ void ImageFilteringShader::copy(ImageFilteringShader const& S)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
//// GENERIC IMAGE FILTER ///
|
||||
/// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
ImageFilter::ImageFilter (): FrameBufferFilter(), buffers_({nullptr, nullptr})
|
||||
{
|
||||
// surface and shader for first pass
|
||||
@@ -374,7 +392,7 @@ void ImageFilter::draw (FrameBuffer *input)
|
||||
// (re)create framebuffer for result of first-pass
|
||||
if (buffers_.first != nullptr)
|
||||
delete buffers_.first;
|
||||
// FBO with mipmapping
|
||||
// FBO
|
||||
buffers_.first = new FrameBuffer( input_->resolution(), input_->flags() );
|
||||
// enforce framebuffer if first-pass is created now, filled with input framebuffer
|
||||
input_->blit( buffers_.first );
|
||||
@@ -422,25 +440,152 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string
|
||||
// always keep local copy
|
||||
program_ = f;
|
||||
|
||||
// // force disable when using default filter
|
||||
// setEnabled( program_ != FilteringProgram::presets.front() );
|
||||
|
||||
// change code
|
||||
std::pair<std::string, std::string> codes = program_.code();
|
||||
|
||||
// FIRST PASS
|
||||
// set code to the shader for first-pass
|
||||
shaders_.first->setCode( codes.first, ret );
|
||||
|
||||
// SECOND PASS
|
||||
if ( program_.isTwoPass() )
|
||||
// set the code to the shader for second-pass
|
||||
shaders_.second->setCode( codes.second );
|
||||
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
void ImageFilter::updateParameters()
|
||||
{
|
||||
// change uniforms
|
||||
shaders_.first->uniforms_ = program_.parameters();
|
||||
|
||||
// SECOND PASS
|
||||
if ( program_.isTwoPass() ) {
|
||||
// set the code to the shader for second-pass
|
||||
shaders_.second->setCode( codes.second );
|
||||
// change uniforms
|
||||
if ( program_.isTwoPass() )
|
||||
shaders_.second->uniforms_ = program_.parameters();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImageFilter::setProgramParameters(const std::map< std::string, float > ¶meters)
|
||||
{
|
||||
program_.setParameters(parameters);
|
||||
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
void ImageFilter::setProgramParameter(const std::string &p, float value)
|
||||
{
|
||||
program_.setParameter(p, value);
|
||||
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
//// BLURING FILTERS ///
|
||||
/// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
const char* BlurFilter::method_label[BlurFilter::BLUR_INVALID] = {
|
||||
"Gaussian", "Hash", "Openning", "Closing", "Fast 2x2"
|
||||
};
|
||||
|
||||
std::vector< FilteringProgram > BlurFilter::programs_ = {
|
||||
FilteringProgram("Gaussian", "shaders/filters/blur_1.glsl", "shaders/filters/blur_2.glsl", { { "Radius", 0.5} }),
|
||||
FilteringProgram("Hashed", "shaders/filters/hashedblur.glsl", "", { { "Iterations", 0.5 }, { "Radius", 0.5} }),
|
||||
FilteringProgram("Openning", "shaders/filters/hashederosion.glsl", "shaders/filters/hasheddilation.glsl", { { "Radius", 0.5} }),
|
||||
FilteringProgram("Closing", "shaders/filters/hasheddilation.glsl", "shaders/filters/hashederosion.glsl", { { "Radius", 0.5} }),
|
||||
FilteringProgram("Fast 2x2", "shaders/filters/blur.glsl", "", { })
|
||||
};
|
||||
|
||||
BlurFilter::BlurFilter (): ImageFilter(), method_(BLUR_INVALID), mipmap_buffer_(nullptr)
|
||||
{
|
||||
mipmap_surface_ = new Surface;
|
||||
}
|
||||
|
||||
BlurFilter::~BlurFilter ()
|
||||
{
|
||||
delete mipmap_surface_;
|
||||
if ( mipmap_buffer_!= nullptr )
|
||||
delete mipmap_buffer_;
|
||||
}
|
||||
|
||||
void BlurFilter::setMethod(int method)
|
||||
{
|
||||
method_ = (BlurMethod) CLAMP(method, BLUR_GAUSSIAN, BLUR_INVALID-1);
|
||||
|
||||
setProgram( programs_[ (int) method_] );
|
||||
}
|
||||
|
||||
void BlurFilter::draw (FrameBuffer *input)
|
||||
{
|
||||
// Default to Gaussian blur
|
||||
if (method_ == BLUR_INVALID)
|
||||
setMethod( BLUR_GAUSSIAN );
|
||||
|
||||
// if input changed (typically on first draw)
|
||||
if (input_ != input) {
|
||||
// keep reference to input framebuffer
|
||||
input_ = input;
|
||||
|
||||
// create zero-pass surface taking as texture the input framebuffer
|
||||
mipmap_surface_->setTextureIndex( input_->texture() );
|
||||
|
||||
// FBO with mipmapping
|
||||
// (re)create framebuffer for mipmapped input
|
||||
if ( mipmap_buffer_!= nullptr )
|
||||
delete mipmap_buffer_;
|
||||
FrameBuffer::FrameBufferFlags f = input_->flags();
|
||||
mipmap_buffer_ = new FrameBuffer( input_->resolution(), f | FrameBuffer::FrameBuffer_mipmap );
|
||||
// enforce framebuffer created now, filled with input framebuffer
|
||||
input_->blit( mipmap_buffer_ );
|
||||
|
||||
// create first-pass surface and shader, taking as texture the input framebuffer
|
||||
surfaces_.first->setTextureIndex( mipmap_buffer_->texture() );
|
||||
shaders_.first->mask_texture = input_->texture();
|
||||
// (re)create framebuffer for result of first-pass
|
||||
if (buffers_.first != nullptr)
|
||||
delete buffers_.first;
|
||||
buffers_.first = new FrameBuffer( input_->resolution(), f | FrameBuffer::FrameBuffer_mipmap );
|
||||
// enforce framebuffer of first-pass is created now, filled with input framebuffer
|
||||
mipmap_buffer_->blit( buffers_.first );
|
||||
|
||||
// create second-pass surface and shader, taking as texture the first-pass framebuffer
|
||||
surfaces_.second->setTextureIndex( buffers_.first->texture() );
|
||||
shaders_.second->mask_texture = input_->texture();
|
||||
// (re)create framebuffer for result of second-pass
|
||||
if (buffers_.second != nullptr)
|
||||
delete buffers_.second;
|
||||
buffers_.second = new FrameBuffer( input_->resolution(), f );
|
||||
}
|
||||
|
||||
if ( enabled() )
|
||||
{
|
||||
// ZERO PASS
|
||||
// render input surface into frame buffer with Mipmapping (Levels of Details)
|
||||
mipmap_buffer_->begin();
|
||||
mipmap_surface_->draw(glm::identity<glm::mat4>(), mipmap_buffer_->projection());
|
||||
mipmap_buffer_->end();
|
||||
|
||||
// FIRST PASS
|
||||
// render mipmapped texture into frame buffer
|
||||
buffers_.first->begin();
|
||||
surfaces_.first->draw(glm::identity<glm::mat4>(), buffers_.first->projection());
|
||||
buffers_.first->end();
|
||||
|
||||
// SECOND PASS
|
||||
if ( program().isTwoPass() ) {
|
||||
// render filtered surface from first pass into frame buffer
|
||||
buffers_.second->begin();
|
||||
surfaces_.second->draw(glm::identity<glm::mat4>(), buffers_.second->projection());
|
||||
buffers_.second->end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlurFilter::accept (Visitor& v)
|
||||
{
|
||||
FrameBufferFilter::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
@@ -69,22 +70,21 @@ class ImageFilter : public FrameBufferFilter
|
||||
{
|
||||
FilteringProgram program_;
|
||||
|
||||
std::pair< Surface *, Surface *> surfaces_;
|
||||
std::pair< FrameBuffer *, FrameBuffer * > buffers_;
|
||||
std::pair< ImageFilteringShader *, ImageFilteringShader *> shaders_;
|
||||
|
||||
public:
|
||||
|
||||
// instanciate an image filter at given resolution
|
||||
ImageFilter();
|
||||
~ImageFilter();
|
||||
virtual ~ImageFilter();
|
||||
|
||||
// set the program
|
||||
void setProgram(const FilteringProgram &f, std::promise<std::string> *ret = nullptr);
|
||||
|
||||
// get copy of the program
|
||||
FilteringProgram program() const;
|
||||
|
||||
// update parameters of program
|
||||
void setProgramParameters(const std::map< std::string, float > ¶meters);
|
||||
void setProgramParameter(const std::string &p, float value);
|
||||
|
||||
// implementation of FrameBufferFilter
|
||||
Type type() const override { return FrameBufferFilter::FILTER_IMAGE; }
|
||||
uint texture () const override;
|
||||
@@ -92,7 +92,51 @@ public:
|
||||
void update (float dt) override;
|
||||
void draw (FrameBuffer *input) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
protected:
|
||||
|
||||
std::pair< Surface *, Surface *> surfaces_;
|
||||
std::pair< FrameBuffer *, FrameBuffer * > buffers_;
|
||||
std::pair< ImageFilteringShader *, ImageFilteringShader *> shaders_;
|
||||
void updateParameters();
|
||||
};
|
||||
|
||||
|
||||
class BlurFilter : public ImageFilter
|
||||
{
|
||||
public:
|
||||
|
||||
BlurFilter();
|
||||
virtual ~BlurFilter();
|
||||
|
||||
// Algorithms used for blur
|
||||
typedef enum {
|
||||
BLUR_GAUSSIAN = 0,
|
||||
BLUR_HASH,
|
||||
BLUR_OPENNING,
|
||||
BLUR_CLOSING,
|
||||
BLUR_FAST,
|
||||
BLUR_INVALID
|
||||
} BlurMethod;
|
||||
static const char* method_label[BLUR_INVALID];
|
||||
BlurMethod method () const { return method_; }
|
||||
void setMethod(int method);
|
||||
|
||||
// implementation of FrameBufferFilter
|
||||
Type type() const override { return FrameBufferFilter::FILTER_BLUR; }
|
||||
|
||||
void draw (FrameBuffer *input) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
private:
|
||||
BlurMethod method_;
|
||||
static std::vector< FilteringProgram > programs_;
|
||||
|
||||
Surface *mipmap_surface_;
|
||||
FrameBuffer *mipmap_buffer_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // IMAGEFILTER_H
|
||||
|
||||
@@ -1225,6 +1225,30 @@ void SessionLoader::visit (DelayFilter& f)
|
||||
f.setDelay(d);
|
||||
}
|
||||
|
||||
void SessionLoader::visit (BlurFilter& f)
|
||||
{
|
||||
int m = 0;
|
||||
xmlCurrent_->QueryIntAttribute("method", &m);
|
||||
f.setMethod(m);
|
||||
|
||||
std::map< std::string, float > filter_params;
|
||||
XMLElement* parameters = xmlCurrent_->FirstChildElement("parameters");
|
||||
if (parameters) {
|
||||
XMLElement* param = parameters->FirstChildElement("uniform");
|
||||
for( ; param ; param = param->NextSiblingElement())
|
||||
{
|
||||
float val = 0.f;
|
||||
param->QueryFloatAttribute("value", &val);
|
||||
const char * name;
|
||||
param->QueryStringAttribute("name", &name);
|
||||
if (name)
|
||||
filter_params[name] = val;
|
||||
}
|
||||
}
|
||||
|
||||
f.setProgramParameters(filter_params);
|
||||
}
|
||||
|
||||
void SessionLoader::visit (ImageFilter& f)
|
||||
{
|
||||
const char * filter_name;
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
void visit (CloneSource& s) override;
|
||||
void visit (FrameBufferFilter&) override;
|
||||
void visit (DelayFilter&) override;
|
||||
void visit (BlurFilter&) override;
|
||||
void visit (ImageFilter&) override;
|
||||
|
||||
// callbacks
|
||||
|
||||
@@ -694,6 +694,22 @@ void SessionVisitor::visit (DelayFilter& f)
|
||||
xmlCurrent_->SetAttribute("delay", f.delay());
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (BlurFilter& f)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("method", (int) f.method());
|
||||
|
||||
std::map< std::string, float > filter_params = f.program().parameters();
|
||||
XMLElement *parameters = xmlDoc_->NewElement( "parameters" );
|
||||
xmlCurrent_->InsertEndChild(parameters);
|
||||
for (auto p = filter_params.begin(); p != filter_params.end(); ++p)
|
||||
{
|
||||
XMLElement *param = xmlDoc_->NewElement( "uniform" );
|
||||
param->SetAttribute("name", p->first.c_str() );
|
||||
param->SetAttribute("value", p->second );
|
||||
parameters->InsertEndChild(param);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (ImageFilter& f)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
void visit (CloneSource& s) override;
|
||||
void visit (FrameBufferFilter&) override;
|
||||
void visit (DelayFilter&) override;
|
||||
void visit (BlurFilter&) override;
|
||||
void visit (ImageFilter&) override;
|
||||
|
||||
// callbacks
|
||||
|
||||
@@ -44,6 +44,7 @@ class MultiFileSource;
|
||||
class FrameBufferFilter;
|
||||
class PassthroughFilter;
|
||||
class DelayFilter;
|
||||
class BlurFilter;
|
||||
class ImageFilter;
|
||||
|
||||
class SourceCallback;
|
||||
@@ -104,6 +105,7 @@ public:
|
||||
virtual void visit (FrameBufferFilter&) {}
|
||||
virtual void visit (PassthroughFilter&) {}
|
||||
virtual void visit (DelayFilter&) {}
|
||||
virtual void visit (BlurFilter&) {}
|
||||
virtual void visit (ImageFilter&) {}
|
||||
|
||||
virtual void visit (SourceCallback&) {}
|
||||
|
||||
Binary file not shown.
@@ -1,27 +1,29 @@
|
||||
// 16x acceleration of https://www.shadertoy.com/view/4tSyzy
|
||||
// by applying gaussian at intermediate MIPmap level.
|
||||
|
||||
vec3 texSample(const int x, const int y, in vec2 fragCoord)
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy * iChannelResolution[0].xy;
|
||||
uv = (uv + vec2(x, y)) / iChannelResolution[0].xy;
|
||||
return texture(iChannel0, uv).xyz;
|
||||
const int samples = 25,
|
||||
LOD = 2, // gaussian done on MIPmap at scale LOD
|
||||
sLOD = 1 << LOD; // tile size = 2^LOD
|
||||
const float sigma = float(samples) * .25;
|
||||
|
||||
float gaussian(vec2 i) {
|
||||
return exp( -.5* dot(i/=sigma,i) ) / ( 6.28 * sigma*sigma );
|
||||
}
|
||||
|
||||
void blur( out vec3 rgb, in vec2 fragCoord )
|
||||
{
|
||||
vec3 tot = vec3(0.0);
|
||||
vec4 blur(sampler2D sp, vec2 U, vec2 scale) {
|
||||
vec4 O = vec4(0);
|
||||
int s = samples/sLOD;
|
||||
float t = 0., g;
|
||||
|
||||
for( int j=0; j<9; j++ )
|
||||
for( int i=0; i<9; i++ )
|
||||
tot += pow( texSample(i-4, j-4, fragCoord), vec3(2.2));
|
||||
for ( int i = 0; i < s*s; i++ ) {
|
||||
vec2 d = vec2(i%s, i/s)*float(sLOD) - float(samples)/2.;
|
||||
t += g = gaussian(d);
|
||||
O += g * textureLod( sp, U + scale * d , float(LOD) );
|
||||
}
|
||||
|
||||
rgb = pow(tot/81.0,vec3(1.0/2.2));
|
||||
return O / t;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec3 b;
|
||||
blur(b, fragCoord);
|
||||
fragColor = vec4( b, 1.0);
|
||||
void mainImage(out vec4 O, vec2 U) {
|
||||
O = blur( iChannel0, U/iResolution.xy, 1./iChannelResolution[0].xy );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,34 +1,26 @@
|
||||
#define RADIUS 0.2
|
||||
// Gaussian blur with mipmapping
|
||||
// Bruno Herbelin
|
||||
// Following tutorial https://www.shadertoy.com/view/WtKfD3
|
||||
|
||||
uniform float Amount;
|
||||
#define N 13
|
||||
|
||||
float SCurve (float x) {
|
||||
x = x * 2.0 - 1.0;
|
||||
return -x * abs(x) * 0.5 + x + 0.5;
|
||||
}
|
||||
uniform float Radius;
|
||||
|
||||
vec3 BlurV (sampler2D source, vec2 uv, float step, float radius) {
|
||||
vec3 C = vec3(0.0);
|
||||
float divisor = 0.0;
|
||||
float weight = 0.0;
|
||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
||||
|
||||
// loop on pixels in Y to apply vertical blur
|
||||
for (float y = -radius; y <= radius; y++) {
|
||||
weight = SCurve(1.0 - (abs(y) * radiusMultiplier));
|
||||
C += texture(source, uv + vec2(0.0, y * step)).rgb * weight;
|
||||
divisor += weight;
|
||||
vec4 blur1D(vec2 U, vec2 D, float rad)
|
||||
{
|
||||
float w = rad * iResolution.y;
|
||||
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
|
||||
vec4 O = vec4(0);
|
||||
float r = float(N-1)/2., g, t=0., x;
|
||||
for( int k=0; k<N; k++ ) {
|
||||
x = float(k)/r -1.;
|
||||
t += g = exp(-2.*x*x );
|
||||
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
|
||||
}
|
||||
|
||||
return C / divisor;
|
||||
return O/t;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// downsample the image to benefit from (free) linear subsampling of colors
|
||||
float subsampling = 1.0 - ( Amount * 0.9 );
|
||||
vec2 uv = fragCoord.xy / ( iResolution.xy * subsampling );
|
||||
|
||||
// Apply vertical blur on downsampled image (allows to use smaller radius)
|
||||
fragColor = vec4( BlurV(iChannel0, uv, 1.0 / (iResolution.y * subsampling), RADIUS * iResolution.y * Amount * subsampling), 1.0);
|
||||
fragColor = blur1D( fragCoord, vec2(1,0), Radius * 0.5 );
|
||||
}
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
#define RADIUS 0.2
|
||||
// Following tutorial https://www.shadertoy.com/view/WtKfD3
|
||||
|
||||
uniform float Amount;
|
||||
#define N 13
|
||||
|
||||
float SCurve (float x) {
|
||||
x = x * 2.0 - 1.0;
|
||||
return -x * abs(x) * 0.5 + x + 0.5;
|
||||
}
|
||||
uniform float Radius;
|
||||
|
||||
vec3 BlurH (sampler2D source, vec2 uv, float step, float radius) {
|
||||
vec3 C = vec3(0.0);
|
||||
float divisor = 0.0;
|
||||
float weight = 0.0;
|
||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
||||
|
||||
// loop on pixels in X to apply horizontal blur: note optimization of +2 increment
|
||||
for (float x = -radius; x <= radius; x+=2.0) {
|
||||
weight = SCurve(1.0 - (abs(x) * radiusMultiplier));
|
||||
C += texture(source, uv + vec2(x * step, 0.0)).rgb * weight;
|
||||
divisor += weight;
|
||||
vec4 blur1D(vec2 U, vec2 D, float rad)
|
||||
{
|
||||
float w = rad * iResolution.y;
|
||||
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
|
||||
vec4 O = vec4(0);
|
||||
float r = float(N-1)/2., g, t=0., x;
|
||||
for( int k=0; k<N; k++ ) {
|
||||
x = float(k)/r -1.;
|
||||
t += g = exp(-2.*x*x );
|
||||
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
|
||||
}
|
||||
|
||||
return C / divisor;
|
||||
return O/t;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// upsample the image from blur_1
|
||||
float upsampling = 1.0 - ( Amount * 0.9 );
|
||||
vec2 uv = (fragCoord.xy * upsampling) / iResolution.xy;
|
||||
|
||||
// Apply horizontal blur on restored resolution image
|
||||
fragColor = vec4( BlurH(iChannel0, uv, upsampling / iResolution.x, RADIUS * iResolution.y * Amount), 1.0);
|
||||
fragColor = blur1D( fragCoord, vec2(0,1), Radius * 0.5 );
|
||||
}
|
||||
|
||||
24
rsc/shaders/filters/circularblur.glsl
Normal file
24
rsc/shaders/filters/circularblur.glsl
Normal file
@@ -0,0 +1,24 @@
|
||||
#define TWOPI 6.28318530718
|
||||
|
||||
uniform float Radius;
|
||||
uniform float Iterations;
|
||||
|
||||
float hash(vec2 co){
|
||||
return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
float R = 0.25 * Radius * iResolution.y / iResolution.x ;
|
||||
|
||||
vec4 O = vec4(0.);
|
||||
float N = ( Iterations * 39.0 + 10.0 ); // between 10 and 50
|
||||
for (float i = 0.; i < N; i++) {
|
||||
vec2 q = vec2(cos(TWOPI*i/N), sin(TWOPI*i/N)) * hash(vec2(i, uv.x + uv.y));
|
||||
O += pow( texture(iChannel0, uv + q*R), vec4(2.2) );
|
||||
q = vec2(cos(TWOPI*((i+.5)/N)), sin(TWOPI*(i+.5)/N)) * hash(vec2(i + 2., uv.x * uv.y + 24.));
|
||||
O += pow( texture(iChannel0, uv + q*R), vec4(2.2) );
|
||||
}
|
||||
fragColor = pow( O/(2.*N), vec4(1.0/2.2) );
|
||||
}
|
||||
25
rsc/shaders/filters/hash.glsl
Normal file
25
rsc/shaders/filters/hash.glsl
Normal file
@@ -0,0 +1,25 @@
|
||||
#define SEED uvec4(0x5C995C6Du, 0x6A3C6A57u, 0xC65536CBu, 0x3563995Fu)
|
||||
const uint lcgM = 2891336453u;// ideal for 32 bits with odd c
|
||||
uint asuint2(float x) { return x == 0.0 ? 0u : floatBitsToUint(x); }
|
||||
uvec2 asuint2(vec2 x) { return uvec2(asuint2(x.x ), asuint2(x.y)); }
|
||||
uvec3 asuint2(vec3 x) { return uvec3(asuint2(x.xy), asuint2(x.z)); }
|
||||
uvec3 pcg3Mix(uvec3 h) {
|
||||
h.x += h.y * h.z;
|
||||
h.y += h.z * h.x;
|
||||
h.z += h.x * h.y;
|
||||
return h;
|
||||
}
|
||||
uvec3 pcg3Permute(uvec3 h) {
|
||||
h = pcg3Mix(h);
|
||||
h ^= h >> 16u;
|
||||
return pcg3Mix(h);
|
||||
}
|
||||
uvec3 pcg3(uvec3 h, uint seed) {
|
||||
uvec3 c = (seed << 1u) ^ SEED.xyz;
|
||||
|
||||
return pcg3Permute(h * lcgM + c);
|
||||
}
|
||||
float Float11(uint x) { return float(int(x)) * (1.0 / 2147483648.0); }
|
||||
float Hash11(vec2 v, uint seed) { return Float11(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
float Float01(uint x) { return float( x ) * (1.0 / 4294967296.0); }
|
||||
float Hash01(vec2 v, uint seed) { return Float01(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
@@ -25,18 +25,18 @@ vec2 Hash22(vec2 p)
|
||||
return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));
|
||||
}
|
||||
|
||||
vec3 Blur(vec2 uv, float radius)
|
||||
vec4 Blur(vec2 uv, float radius)
|
||||
{
|
||||
radius = radius * .04;
|
||||
vec2 circle = vec2(radius) * vec2((iResolution.y / iResolution.x), 1.0);
|
||||
vec2 random = Hash22( uv + TIME );
|
||||
|
||||
// Do the blur here...
|
||||
vec3 acc = vec3(0.0);
|
||||
int max = int( Iterations * 49.0 + 1.0 ); // between 1 and 50
|
||||
vec4 acc = vec4(0.0);
|
||||
int max = int( Iterations * 29.0 + 1.0 ); // between 1 and 30
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
acc += texture(iChannel0, uv + circle * Sample(random), radius*10.0).xyz;
|
||||
acc += textureLod(iChannel0, uv + circle * Sample(random), radius*10.0);
|
||||
}
|
||||
return acc / float(max);
|
||||
}
|
||||
@@ -45,8 +45,8 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
|
||||
float radius = Radius * 0.005 * iResolution.y;
|
||||
float radius = Radius * 0.01 * iResolution.y;
|
||||
radius = pow(radius, 2.0);
|
||||
|
||||
fragColor = vec4(Blur(uv * vec2(1.0, -1.0), radius), 1.0);
|
||||
fragColor = Blur(uv * vec2(1.0, -1.0), radius);
|
||||
}
|
||||
|
||||
48
rsc/shaders/filters/hasheddilation.glsl
Normal file
48
rsc/shaders/filters/hasheddilation.glsl
Normal file
@@ -0,0 +1,48 @@
|
||||
#define TWOPI 6.28318530718
|
||||
|
||||
uniform float Radius;
|
||||
|
||||
// float hash(vec2 co){
|
||||
// return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
|
||||
// }
|
||||
|
||||
#define SEED uvec4(0x5C995C6Du, 0x6A3C6A57u, 0xC65536CBu, 0x3563995Fu)
|
||||
const uint lcgM = 2891336453u;// ideal for 32 bits with odd c
|
||||
uint asuint2(float x) { return x == 0.0 ? 0u : floatBitsToUint(x); }
|
||||
uvec2 asuint2(vec2 x) { return uvec2(asuint2(x.x ), asuint2(x.y)); }
|
||||
uvec3 asuint2(vec3 x) { return uvec3(asuint2(x.xy), asuint2(x.z)); }
|
||||
uvec3 pcg3Mix(uvec3 h) {
|
||||
h.x += h.y * h.z;
|
||||
h.y += h.z * h.x;
|
||||
h.z += h.x * h.y;
|
||||
return h;
|
||||
}
|
||||
uvec3 pcg3Permute(uvec3 h) {
|
||||
h = pcg3Mix(h);
|
||||
h ^= h >> 16u;
|
||||
return pcg3Mix(h);
|
||||
}
|
||||
uvec3 pcg3(uvec3 h, uint seed) {
|
||||
uvec3 c = (seed << 1u) ^ SEED.xyz;
|
||||
return pcg3Permute(h * lcgM + c);
|
||||
}
|
||||
// float Float11(uint x) { return float(int(x)) * (1.0 / 2147483648.0); }
|
||||
// float Hash11(vec2 v, uint seed) { return Float11(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
float Float01(uint x) { return float( x ) * (1.0 / 4294967296.0); }
|
||||
float Hash01(vec2 v, uint seed) { return Float01(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
float ar = iResolution.y / iResolution.x ;
|
||||
float R = 0.25 * Radius ;
|
||||
|
||||
vec4 O = vec4(1.);
|
||||
float N = 17;
|
||||
for (float i = 0.; i < N; i++) {
|
||||
vec2 q = vec2(cos(TWOPI*((i+.5)/N)) * ar, sin(TWOPI*(i+.5)/N)) * Hash01(uv, floatBitsToUint(i));
|
||||
// vec2 q = vec2(cos(TWOPI*((i+.5)/N)) * ar, sin(TWOPI*(i+.5)/N)) * hash(vec2(i + 12., uv.x * uv.y + 24.));
|
||||
O = min( texture(iChannel0, uv + q*R), O );
|
||||
}
|
||||
fragColor = O;
|
||||
}
|
||||
49
rsc/shaders/filters/hashederosion.glsl
Normal file
49
rsc/shaders/filters/hashederosion.glsl
Normal file
@@ -0,0 +1,49 @@
|
||||
#define TWOPI 6.28318530718
|
||||
|
||||
uniform float Radius;
|
||||
|
||||
// float hash(vec2 co){
|
||||
// return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
|
||||
// }
|
||||
|
||||
#define SEED uvec4(0x5C995C6Du, 0x6A3C6A57u, 0xC65536CBu, 0x3563995Fu)
|
||||
const uint lcgM = 2891336453u;// ideal for 32 bits with odd c
|
||||
uint asuint2(float x) { return x == 0.0 ? 0u : floatBitsToUint(x); }
|
||||
uvec2 asuint2(vec2 x) { return uvec2(asuint2(x.x ), asuint2(x.y)); }
|
||||
uvec3 asuint2(vec3 x) { return uvec3(asuint2(x.xy), asuint2(x.z)); }
|
||||
uvec3 pcg3Mix(uvec3 h) {
|
||||
h.x += h.y * h.z;
|
||||
h.y += h.z * h.x;
|
||||
h.z += h.x * h.y;
|
||||
return h;
|
||||
}
|
||||
uvec3 pcg3Permute(uvec3 h) {
|
||||
h = pcg3Mix(h);
|
||||
h ^= h >> 16u;
|
||||
return pcg3Mix(h);
|
||||
}
|
||||
uvec3 pcg3(uvec3 h, uint seed) {
|
||||
uvec3 c = (seed << 1u) ^ SEED.xyz;
|
||||
|
||||
return pcg3Permute(h * lcgM + c);
|
||||
}
|
||||
// float Float11(uint x) { return float(int(x)) * (1.0 / 2147483648.0); }
|
||||
// float Hash11(vec2 v, uint seed) { return Float11(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
float Float01(uint x) { return float( x ) * (1.0 / 4294967296.0); }
|
||||
float Hash01(vec2 v, uint seed) { return Float01(pcg3(asuint2(vec3(v, 0.0)), seed).x); }
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
float ar = iResolution.y / iResolution.x ;
|
||||
float R = 0.25 * Radius ;
|
||||
|
||||
vec4 O = vec4(0.);
|
||||
float N = 17;
|
||||
for (float i = 0.; i < N; i++) {
|
||||
vec2 q = vec2(cos(TWOPI*i/N) * ar, sin(TWOPI*i/N)) * Hash01(uv, floatBitsToUint(i) );
|
||||
// vec2 q = vec2(cos(TWOPI*i/N) * ar, sin(TWOPI*i/N)) * hash(vec2(i, uv.x + uv.y));
|
||||
O = max( texture(iChannel0, uv + q*R), O );
|
||||
}
|
||||
fragColor = O;
|
||||
}
|
||||
24
rsc/shaders/filters/mipmapblur.glsl
Normal file
24
rsc/shaders/filters/mipmapblur.glsl
Normal file
@@ -0,0 +1,24 @@
|
||||
#define N 13
|
||||
|
||||
uniform float Radius;
|
||||
|
||||
vec4 blur2D(vec2 U, float rad)
|
||||
{
|
||||
float w = rad * iResolution.y;
|
||||
float z = ceil(max(0.,log2(w/float(N))));
|
||||
vec4 O = vec4(0);
|
||||
float r = float(N-1)/2., g, t=0.;
|
||||
for( int k=0; k<N*N; k++ ) {
|
||||
vec2 P = vec2(k%N, k/N) / r - 1.;
|
||||
if ( dot(P,P) < 1.0 ) {
|
||||
t += g = exp(-2.*dot(P,P) );
|
||||
O += g * textureLod(iChannel0, (U + w*P) / iResolution.xy, z );
|
||||
}
|
||||
}
|
||||
return O/t;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
fragColor = blur2D( fragCoord, Radius * 0.25 );
|
||||
}
|
||||
34
rsc/shaders/filters/sigmoid_1.glsl
Normal file
34
rsc/shaders/filters/sigmoid_1.glsl
Normal file
@@ -0,0 +1,34 @@
|
||||
#define RADIUS 0.2
|
||||
|
||||
uniform float Amount;
|
||||
|
||||
float SCurve (float x) {
|
||||
x = x * 2.0 - 1.0;
|
||||
return -x * abs(x) * 0.5 + x + 0.5;
|
||||
}
|
||||
|
||||
vec3 BlurV (sampler2D source, vec2 uv, float step, float radius) {
|
||||
vec3 C = vec3(0.0);
|
||||
float divisor = 0.0;
|
||||
float weight = 0.0;
|
||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
||||
|
||||
// loop on pixels in Y to apply vertical blur
|
||||
for (float y = -radius; y <= radius; y++) {
|
||||
weight = SCurve(1.0 - (abs(y) * radiusMultiplier));
|
||||
C += texture(source, uv + vec2(0.0, y * step)).rgb * weight;
|
||||
divisor += weight;
|
||||
}
|
||||
|
||||
return C / divisor;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// downsample the image to benefit from (free) linear subsampling of colors
|
||||
float subsampling = 1.0 - ( Amount * 0.9 );
|
||||
vec2 uv = fragCoord.xy / ( iResolution.xy * subsampling );
|
||||
|
||||
// Apply vertical blur on downsampled image (allows to use smaller radius)
|
||||
fragColor = vec4( BlurV(iChannel0, uv, 1.0 / (iResolution.y * subsampling), RADIUS * iResolution.y * Amount * subsampling), 1.0);
|
||||
}
|
||||
34
rsc/shaders/filters/sigmoid_2.glsl
Normal file
34
rsc/shaders/filters/sigmoid_2.glsl
Normal file
@@ -0,0 +1,34 @@
|
||||
#define RADIUS 0.2
|
||||
|
||||
uniform float Amount;
|
||||
|
||||
float SCurve (float x) {
|
||||
x = x * 2.0 - 1.0;
|
||||
return -x * abs(x) * 0.5 + x + 0.5;
|
||||
}
|
||||
|
||||
vec3 BlurH (sampler2D source, vec2 uv, float step, float radius) {
|
||||
vec3 C = vec3(0.0);
|
||||
float divisor = 0.0;
|
||||
float weight = 0.0;
|
||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
||||
|
||||
// loop on pixels in X to apply horizontal blur: note optimization of +2 increment
|
||||
for (float x = -radius; x <= radius; x+=2.0) {
|
||||
weight = SCurve(1.0 - (abs(x) * radiusMultiplier));
|
||||
C += texture(source, uv + vec2(x * step, 0.0)).rgb * weight;
|
||||
divisor += weight;
|
||||
}
|
||||
|
||||
return C / divisor;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// upsample the image from blur_1
|
||||
float upsampling = 1.0 - ( Amount * 0.9 );
|
||||
vec2 uv = (fragCoord.xy * upsampling) / iResolution.xy;
|
||||
|
||||
// Apply horizontal blur on restored resolution image
|
||||
fragColor = vec4( BlurH(iChannel0, uv, upsampling / iResolution.x, RADIUS * iResolution.y * Amount), 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user