|
Tutorials > OpenGL ES > Masking
What is Masking?You may find yourself having an OpenGL scene with some background. You may also have some object, text or character which is made up of an image. The problem here is that the object displayed on the screen will have to be a block shape. We can overcome this by applying transparency to our images. One technique for adding transparency to images is known as masking. Masking is achieved by using 2 images. The one image is your main image containing the object that you wish to display. This is the image that you want to display with various parts transparent. The second image consists of only black and white . The pure white areas will appear completely transparent whereas the black areas will be completely opaque. This technique is made possible through the use of blending. Contents of main.cpp : This tutorial will use 3 textures. The zeus.bmp image is used for the background. The checker.bmp image is the image that we want to appear transparent and the rockchecker.bmp image is the mask for that image. GLuint texture[3]; char *bitmaps[] = { "zeus.bmp", "checker.bmp", "rockchecker.bmp" }; We want to display all of our images as a 2x2 square centered on the origin.
float bgVertices[] = {
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
-1.0f, 1.0f
};
The texture coordinates given below will cause the texture to be repeated 3 times.
float bgTexCoords[] = {
3.0f, 0.0f,
3.0f, 3.0f,
0.0f, 0.0f,
0.0f, 3.0f
};
We need to keep separate texture coordinates for the checkered image as we want the checkered image to appear as though it is moving. We do not want to modify the background image.
float checkerCoords[] = {
3.0f, 0.0f,
3.0f, 3.0f,
0.0f, 0.0f,
0.0f, 3.0f
};
A wrap value is used to successfully wrap the texture around to the otherside. This technique works the same way as in the Waving Flag tutorial.
float wrapValue = 0.0f;
Our loadTextures function works in the same way as in previous tutorials except this time, 3 textures are loaded. We get the filename from our bitmaps array created earlier. bool loadTextures() { BITMAPINFOHEADER info; unsigned char *bitmap = NULL; glGenTextures(3, texture); for (int i = 0; i < 3; i++) { memset(&info, 0, sizeof(BITMAPINFOHEADER)); bitmap = loadBMP(bitmaps[i], &info); if (!bitmap) return false; glBindTexture(GL_TEXTURE_2D, texture[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, info.biWidth, info.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); delete[] bitmap; bitmap = NULL; } return true; } Our init function remains almost the same. Except for the initialization of the vertex and texture coordinate arrays. bool init() { if (!loadTextures()) { MessageBox(NULL, L"Error loading textures", L"Error", MB_OK); return false; } glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepthf(1.0f); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); We initialize the vertex pointer with the vertices created above. We do not initialize the texture coordinate pointer as this will be changed every frame for the background and the checker image.
glVertexPointer(2, GL_FLOAT, 0, bgVertices);
The next step is to enable the vertex and texture coordinate array. glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); return true; } The beginning of our display function remains the same. void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); We translate the modelview matrix 2 units away from the user to display the images. glTranslatef(0.0f, 0.0f, -2.0f); We will first be drawing the background texture. It is therefore necessary to assign the texture coordinate pointer to the value of the background texture coordinates.
glTexCoordPointer(2, GL_FLOAT, 0, bgTexCoords);
We then select the background texture and draw the background. glBindTexture(GL_TEXTURE_2D, texture[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); We will now be using blending to achieve transparency. It is therefore necessary to enable blending and disable depth testing. We need to disable depth testing to prevent the background texture from not being displayed. glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); The checker pattern will now be displayed. The line below associates the texture coordinate pointer with the checker texture coordinate array.
glTexCoordPointer(2, GL_FLOAT, 0, checkerCoords);
When adding the mask image, we use the (GL_DST_COLOR, GL_ZERO) blending function. The GL_ZERO specifies that any black areas on the image will appear as black on the screen. The GL_DST_COLOR specifies that any white areas on the image will simply cause only the destination(screen) color to be used. This gives us the transparency effect. If we stop drawing here, you will get a number of black squares moving across the background. glBlendFunc(GL_DST_COLOR, GL_ZERO); glBindTexture(GL_TEXTURE_2D, texture[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); We now need to display our checkered image on the screen. We now switch to the (GL_ONE, GL_ONE) blending function. This adds the color values of the image to the screen values. As black is specified as (0,0,0), any addition of black achieves nothing. This causes the checker texture to be drawn. Any black areas on the image will cause the destination screen to remain the same, resulting in transparency. The rock part is added to the black on the screen to simply show the rock texture. glBlendFunc(GL_ONE, GL_ONE); glBindTexture(GL_TEXTURE_2D, texture[2]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); After rendering the images, we disable blending and enable depth testing again. glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glFlush(); glutSwapBuffers(); } In our idle function, we move the checker texture. We make sure that the texture wraps correctly. We continue to increase the wrapping value until it is greater than 1. We then reset it to 0. This creates a wrapping effect. void idle() { wrapValue += 0.1f; if (wrapValue > 1.0f) wrapValue = 0.0f; The value is then added to the x values of our texture coordinates to make it scroll horizontally over the screen. checkerCoords[0] = 3.0f + wrapValue; checkerCoords[2] = 3.0f + wrapValue; checkerCoords[4] = 0.0f + wrapValue; checkerCoords[6] = 0.0f + wrapValue; glutPostRedisplay(); } Well done. You have now learnt how to achieve transparency through the method of masking. This may come in handy for a number of situations such as animating 2D sprites. Please let me know of any comments you may have : Contact Me
Last Updated : 20 November 2005
All Rights Reserved, © Zeus Communication, Multimedia & Development 2004-2005 Read the Disclaimer |
|