diff --git a/CMakeLists.txt b/CMakeLists.txt index cc0aec9..565d6cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/CloneSource.cpp b/CloneSource.cpp index be22f95..2a63827 100644 --- a/CloneSource.cpp +++ b/CloneSource.cpp @@ -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 ? } diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp index 2c19882..707b1b5 100644 --- a/FrameBuffer.cpp +++ b/FrameBuffer.cpp @@ -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 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) <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 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 diff --git a/ImGuiVisitor.h b/ImGuiVisitor.h index 3f94481..f127167 100644 --- a/ImGuiVisitor.h +++ b/ImGuiVisitor.h @@ -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; }; diff --git a/ImageFilter.cpp b/ImageFilter.cpp index d5a18a8..9aad120 100644 --- a/ImageFilter.cpp +++ b/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 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(), mipmap_buffer_->projection()); + mipmap_buffer_->end(); + + // FIRST PASS + // render mipmapped texture into frame buffer + buffers_.first->begin(); + surfaces_.first->draw(glm::identity(), 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(), buffers_.second->projection()); + buffers_.second->end(); + } + } +} + +void BlurFilter::accept (Visitor& v) +{ + FrameBufferFilter::accept(v); + v.visit(*this); +} + + + diff --git a/ImageFilter.h b/ImageFilter.h index f7b83c3..7d1068c 100644 --- a/ImageFilter.h +++ b/ImageFilter.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -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 *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 diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 524b1af..0be6ff4 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -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; diff --git a/SessionCreator.h b/SessionCreator.h index 1703c55..dd4475b 100644 --- a/SessionCreator.h +++ b/SessionCreator.h @@ -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 diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 0968526..232feb1 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -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() ); diff --git a/SessionVisitor.h b/SessionVisitor.h index e6fa10d..1fb974f 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -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 diff --git a/Visitor.h b/Visitor.h index 14f019b..7b5b6be 100644 --- a/Visitor.h +++ b/Visitor.h @@ -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&) {} diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index d7bfd28..cf10a2a 100644 Binary files a/rsc/images/icons.dds and b/rsc/images/icons.dds differ diff --git a/rsc/shaders/filters/blur.glsl b/rsc/shaders/filters/blur.glsl index f04b099..48d302c 100644 --- a/rsc/shaders/filters/blur.glsl +++ b/rsc/shaders/filters/blur.glsl @@ -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; -void blur( out vec3 rgb, in vec2 fragCoord ) -{ - vec3 tot = vec3(0.0); - - 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)); - - rgb = pow(tot/81.0,vec3(1.0/2.2)); +float gaussian(vec2 i) { + return exp( -.5* dot(i/=sigma,i) ) / ( 6.28 * sigma*sigma ); } -void mainImage( out vec4 fragColor, in vec2 fragCoord ) -{ - vec3 b; - blur(b, fragCoord); - fragColor = vec4( b, 1.0); +vec4 blur(sampler2D sp, vec2 U, vec2 scale) { + vec4 O = vec4(0); + int s = samples/sLOD; + float t = 0., g; + + 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) ); + } + + return O / t; } - +void mainImage(out vec4 O, vec2 U) { + O = blur( iChannel0, U/iResolution.xy, 1./iChannelResolution[0].xy ); +} diff --git a/rsc/shaders/filters/blur_1.glsl b/rsc/shaders/filters/blur_1.glsl index 0fbd96a..fd208de 100644 --- a/rsc/shaders/filters/blur_1.glsl +++ b/rsc/shaders/filters/blur_1.glsl @@ -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; - } - - return C / divisor; +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> 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); } \ No newline at end of file diff --git a/rsc/shaders/filters/hashedblur.glsl b/rsc/shaders/filters/hashedblur.glsl index d94ec64..d02a07e 100644 --- a/rsc/shaders/filters/hashedblur.glsl +++ b/rsc/shaders/filters/hashedblur.glsl @@ -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); } diff --git a/rsc/shaders/filters/hasheddilation.glsl b/rsc/shaders/filters/hasheddilation.glsl new file mode 100644 index 0000000..df7cef5 --- /dev/null +++ b/rsc/shaders/filters/hasheddilation.glsl @@ -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; +} diff --git a/rsc/shaders/filters/hashederosion.glsl b/rsc/shaders/filters/hashederosion.glsl new file mode 100644 index 0000000..0d0592c --- /dev/null +++ b/rsc/shaders/filters/hashederosion.glsl @@ -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; +} diff --git a/rsc/shaders/filters/mipmapblur.glsl b/rsc/shaders/filters/mipmapblur.glsl new file mode 100644 index 0000000..7cab2e8 --- /dev/null +++ b/rsc/shaders/filters/mipmapblur.glsl @@ -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