Animating text – text as a mask for a movie

In this recipe, we will learn how we can use text as a mask for a movie using a simple shader program.

Getting ready

In this example, we are using one of the amazing videos provided by NASA taken by an ISS crew that you can find at http://eol.jsc.nasa.gov/. Please download oneand save it as video.mov inside the assets folder.

How to do it…

We will create a sample Cinder application to illustrate the mechanism. Perform the following steps to do so:

  1. Include the necessary header files.
    #include "cinder/gl/Texture.h"
    #include "cinder/Text.h"
    #include "cinder/Font.h"
    #include "cinder/qtime/QuickTime.h"
    #include "cinder/gl/GlslProg.h"
  2. Declare the member variables.
    qtime::MovieGl mMovie;
    gl::Texture     mFrameTexture, mTextTexture;
    gl::GlslProg  mMaskingShader;
  3. Implement the setup method, as follows:
    setWindowSize(854, 480);
    
    TextLayout layout;
    layout.clear( ColorA(0.f,0.f,0.f, 0.f) );
    layout.setFont( Font("Arial Black", 96 ) );
    layout.setColor( Color( 1, 1, 1 ) );
    layout.addLine( "SPACE" );
    Surface8u rendered = layout.render( true );
    
    gl::Texture::Format format;
    format.setTargetRect();
    mTextTexture = gl::Texture( rendered, format );
    
    try {
      mMovie = qtime::MovieGl( getAssetPath("video.mov") );
      mMovie.setLoop();
      mMovie.play();
    } catch( ... ) {
      console() <<"Unable to load the movie."<<endl;
      mMovie.reset();
    }
    
    mMaskingShader = gl::GlslProg( loadAsset("passThru_vert.glsl"), loadAsset("masking_frag.glsl") );
  4. Inside the update method we have to update our mFrameTexture where we are keeping the current movie frame.
    if( mMovie ) mFrameTexture = mMovie.getTexture();
  5. The draw method will look like the following code snippet:
    gl::enableAlphaBlending();
    gl::clear( Color::gray(0.05f) );
    gl::setViewport(getWindowBounds());
    gl::setMatricesWindow(getWindowSize());
    
    gl::color(ColorA::white());
    if(mFrameTexture) {
     Vec2f maskOffset = (mFrameTexture.getSize() 
      - mTextTexture.getSize() ) * 0.5f;
     mFrameTexture.bind(0);
     mTextTexture.bind(1);
     mMaskingShader.bind();
     mMaskingShader.uniform("sourceTexture", 0);
     mMaskingShader.uniform("maskTexture", 1);
     mMaskingShader.uniform("maskOffset", maskOffset);
     gl::pushMatrices();
     gl::translate(getWindowCenter()-mTextTexture.getSize()*0.5f);
     gl::drawSolidRect( mTextTexture.getBounds(), true );
     gl::popMatrices();
     mMaskingShader.unbind();
    }
  6. As you can see in the setup method we are loading a shader to do the masking. We have to pass through vertex shader inside the assets folder in a file named passThru_vert.glsl. You can find this in the Implementing 2D metaballs recipe in Chapter 7, Using 2D Graphics.
  7. Finally, the fragment shader program code will look like the following code snippet, and should also be inside the assets folder under the name masking_frag.glsl.
    #extension GL_ARB_texture_rectangle : require
    
    uniform sampler2DRect sourceTexture;
    uniform sampler2DRect maskTexture;
    uniform vec2 maskOffset;
    
    void main() 
    { 
      vec2 texCoord = gl_TexCoord[0].st;  
        
      vec4 sourceColor = texture2DRect( sourceTexture, texCoord+maskOffset );   
      vec4 maskColor = texture2DRect( maskTexture, texCoord ); 
      
      vec4 color = sourceColor * maskColor;
      
      gl_FragColor = color;
    }

How it works…

Inside the setup method in step 3 we are rendering our text as Surface and then converting it to gl::Texture that we will use later as a masking texture. It is important here to set a rectangle format for masking texture while we are using it as a mask for a movie, because qtime::MovieGl is creating a texture with a frame that is rectangular. To do that we are defining the gl::Texture::Format object named format and invoking the setTargetRect method on it. While creating gl::Texture we have to pass format to the constructor as a second parameter.

To draw a movie frame we are using our masking shader program applied on the rectangle in step 5. We have to pass three parameters, which are the movie frame as sourceTexture, mask texture with text as maskTexture, and the position of the mask as maskOffset.

In step 7 you can see the fragment shader code, which simply multiplies the colors of the corresponding pixels from sourceTexture and maskTexture. Please notice that we are using sampler2DRect and texture2DRect to handle rectangular textures.

How it works…
..................Content has been hidden....................

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