In this recipe, we will learn how we can use text as a mask for a movie using a simple shader program.
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.
We will create a sample Cinder application to illustrate the mechanism. Perform the following steps to do so:
#include "cinder/gl/Texture.h" #include "cinder/Text.h" #include "cinder/Font.h" #include "cinder/qtime/QuickTime.h" #include "cinder/gl/GlslProg.h"
qtime::MovieGl mMovie; gl::Texture mFrameTexture, mTextTexture; gl::GlslProg mMaskingShader;
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") );
update
method we have to update our mFrameTexture
where we are keeping the current movie frame.if( mMovie ) mFrameTexture = mMovie.getTexture();
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(); }
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.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; }
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.
3.144.97.187