Implementing 2D metaballs

In this recipe, we will learn how we can implement organic looking objects called metaballs.

Getting ready

In this recipe, we are going to use the code base from the Applying repulsion and attraction forces recipe in Chapter 5, Building Particle Systems.

How to do it…

We will implement the metaballs' rendering using a shader program. Perform the following steps to do so:

  1. Create a file inside the assets folder with a name, passThru_vert.glsl, and put the following code snippet inside it:
    void main()
    {
      gl_Position = ftransform();
      gl_TexCoord[0] = gl_MultiTexCoord0;
      gl_FrontColor = gl_Color; 
    }
  2. Create a file inside the assets folder with a name, mb_frag.glsl, and put the following code snippet inside it:
    #version 120
    
    uniform vec2 size;
    uniform int num;
    uniform vec2 positions[100];
    uniform float radius[100];
    
    void main(void)
    {
    
      // Get coordinates
      vec 2 texCoord = gl_TexCoord[0].st;
      
      vec4 color = vec4(1.0,1.0,1.0, 0.0);
      float a = 0.0;
      
      int i;  
      for(i = 0; i<num; i++) {
        color.a += (radius[i] / sqrt( ((texCoord.x*size.x)-
        positions[i].x)*((texCoord.x*size.x)-positions[i].x) + 
        ((texCoord.y*size.y)-
        positions[i].y)*((texCoord.y*size.y)-positions[i].y) ) 
        ); 
        }
    
      // Set color
      gl_FragColor = color;
    }
  3. Add the necessary header files.
    #include "cinder/Utilities.h"
    #include "cinder/gl/GlslProg.h"
  4. Add a property to your application's main class, which is the GlslProg object for our GLSL shader program.
    gl::GlslProg  mMetaballsShader;
  5. In the setup method, change the values of repulsionFactor and numParticle.
    repulsionFactor = -40.f;
    int numParticle = 10;
  6. At the end of the setup method, load our GLSL shader program, as follows:
    mMetaballsShader = gl::GlslProg( loadAsset("passThru_vert.glsl"), loadAsset("mb_frag.glsl") );
  7. The last major change is in the draw method, which looks like the following code snippet:
    void MainApp::draw()
    {
      gl::enableAlphaBlending();
      gl::clear( Color::black() );
    
      int particleNum = mParticleSystem.particles.size();
    
      mMetaballsShader.bind();
      mMetaballsShader.uniform( "size", Vec2f(getWindowSize()) );
      mMetaballsShader.uniform( "num", particleNum );
    
      for (int i = 0; i<particleNum; i++) {
      mMetaballsShader.uniform( "positions[" + toString(i) + 
      "]", mParticleSystem.particles[i]->position );
      mMetaballsShader.uniform( "radius[" + toString(i) + 
        "]", mParticleSystem.particles[i]->radius );
      }
    
      gl::color(Color::white());
      gl::drawSolidRect( getWindowBounds() );
      mMetaballsShader.unbind();
    }

How it works…

The most important part of this recipe is the fragment shader program mentioned in step 2. The shader generates texture with rendered metaballs based on the positions and radius passed to the shader from our particle system. In step 7, you can find out how to pass information to the shader program. We are using setMatricesWindow and setViewport to set OpenGL for drawing.

How it works…

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.79.147