/ofxFX

Unlocking the GPU Power on openFrameworks with this add-on for that make easy to use GLSL Shaders

Primary LanguageC++OtherNOASSERTION

ofxFlocking ofxFluid ofxGlow ofxGrayScott ofxWater

This addon begins while I was working on Efecto Mariposa when I was to adapting different well know GLSL Shaders Algorithms for making fast simulations and organic effects. After that project I decide to make an addon that allow easy implementation of different effects that could be render super fast on the GPU. All of this effect heritage from ofxFXObject. Making easy to combine them and create new ones.

ofxFXObject

It´s the parent class of all the other effect. If you want to make a new filter you may want to start looking at the ofxFXObject.h .

The structure it´s easy.

  1. Constructor: here it´s necessary to set three vital variables:

    • int passes: the number of passes or itineration of the main ping pong betweens FBO´s
    • int internalFormat: if it use GL_RGB, GL_RGBA, GL_RGB16f, GL_RGBA16f, GL_RGB32f, GL_RGBA32f, etc...
    • string fragShader: it´s the code of the shader. Note that some changes have to be made in order to fill everything on a string
  2. allocate(width,height,GL_RGBA): This usually it´s no need to bee re-define. It´s basically allocate the FBO´s and loads the shader by using injectShader();

  3. setCode(string fragContent): here is where the shaders are loaded. See the example bellow.

  4. begin(int texN) and end(int texN): remember nTextures variable? you can passthrough information to it by using this end() and begin() and giving the argument the number of texture you want to open. This texture can be access from the shader by the uniform sample2DRect tex0 or tex1 or tex2 and so on. Also you can access to the previous FBO of the ping pong by calling uniform sample2DRect backbuffer.

  5. update(): this is the core of the class, where the magic happens. If you check for the ofxFXObject::update() you will see how the tex´s, the backbuffer and other default uniforms variables (time, mouse, resolution) are loaded.

  6. draw(x,y,w,h): after all you definitely want to look at it.

An example of an implementation of an ofxFXObject could be:

On setup:

ofxFXObject fxObject = ofxFXObject();

fxObject.allocate(800,600); // At this point it will load a default timer shader

//Let´s play a little injecting a new one
fxObject.setCode("#version 120\n\
                    \
                    uniform sampler2DRect backbuffer;\
                    uniform sampler2DRect tex0;\
                    uniform sampler2DRect tex1;\
                    uniform sampler2DRect tex2;\
                    \
                    uniform float time; \
                    uniform vec2 mouse;\
                    uniform vec2 resolution;\
                    \
                    void main( void ) {\
                        \
                        ... \
                        \
                        gl_FragColor = ... ;\
                    }"); 

On update:

fxObject.begin();   // for tex0 you don´t need to pass the 0 as an argument 
    //What ever you want to render to tex0
fxObject.end();

fxObject.begin(1);
    //What ever you want to render to tex1
fxObject.end(1);

fxObject.setTexture(image.getTextureReference(),2); // For object that have ofTexture you could just pass the ofTexture reference 


fxObject.update();

On draw:

fxObject.draw();

Copy, Inject & Share

If you are curious and want to learn the best way it´s to see and edit code. You could go to Ricardo Caballero´s webGL Sandbox or Inigo Quilez´s ShaderToy to found some inspiration. Explore. Make changes. Inject. Compile. May be it´s the case things not compile as you spect. Some times (most of them when you are dealing with other textures) you will need to make some changes. As far as I know openGL and GPU hardware it´s makes lot´s of changes and improves year after year. So lot´s of problems related to compatibility will happened. Also openFrameworks works fine with openGL 1.2 and it use by default the ARB Rect Textures.

Having that in mind the process of adapting code it´s a matter of searching on google. Fortunately you can see the ones I already implement and make them work.

General tips:

  • Casting: openGL it will not cast for you. So if you assign an int to a float it will not compile properly.
float f = 1;    // FAIL 
float f = 1.0;  // GOOD
  • Norm coordinates: as far as I know there are two types of textures sample2D and sample2DRect. The first ones have the same length in both sides while the second one not. When you are using texture2D( tex, pos) the position have to be normalized while on texture2DRect(tex, pos) it´s not normalized.

Mix them all

ofxFXObject have some handy operators that let you combine them really easily. At the Mix´s Example you will find how to do it. Basicaly it´s somethin like this

ofxFXObject objA;
ofxGrayScott objB;
ofxBlur     blur;

objA.allocate(width, height);
objB.allocate(width, height);
blur.allocate(width, height);

...

objA >> objB >> blur;

objA.update();
objB.update();
blur.update();

...

blur.draw();

ofxFXObject subclasses

If you are thinking on making your own filter or generative shader. You may want to look at the ofxFXObject parent class. There you will find some handy function that could help you.

  • renderFrame(width,height) makes a frame where the textures could be draw;

  • initFbo(ofxFbo, width, height, internalFormat ): it takes the work of allocating and cleaning an FBO.

  • ofxSwapBuffer.h: this is actually a class for making easy dealing with ping-pongs.

In the src/ directory of the addon you will find lot´s of subClasses that inherit from ofxFXObject. They are decided in difference categories.

Interactive

First case, the ones that in some point breaks the structure of ofxFXObject with some extra tweaks. Like the way the pingPong works. The number of shaders need and how they pass the data to each other. Or if the implement vertex or Geometry shader as well. That´s the case of:

Filters

The second case, are the ones could be use as filters. That means, they could be use for many things. Giving lot of flexibility and freedom when you use it on your project. Like using the blur and the glow combined with mask and things like that.

filter0 filter1 filter2 filter3

Composition Shaders

Generative

Other Examples

On this addon you will find examples of the classes I just describe. Some of them are combined together in order to show clearly how to use them. Other examples shows new ways of making new shaders by injecting code or extending classes as the following ones: