【OpenGL】(NeHe教程学习)掩模(Masking)

有的时候我们需要达到这样一种效果:透过一个某种形状的物体去看一个场景,被物体遮挡住的部分看不见,其他的则可以看见。这时候就需要用到掩模技术

掩模需要两个步骤。第一,我们把一幅黑白图像放在场景前面,白色代表纹理的透明部分,而黑色则代表纹理的实心部分。我们采用一种混合方式,使得只有黑色纹理部分才能显示在屏幕上。白色部分则看见背景。接着我们切换混合方式,再加载对应的彩色纹理图像,由于我们使用的混合方式,只有位于刚才的那幅黑白纹理图像的黑色部分上方的部分才能显示于屏幕上。

具体步骤:

(1)生成背景。

绘制一个正方形,然后进行纹理贴图。注意贴图的时候指定纹理坐标的方式。当纹理坐标大于1的时候,OpenGL自动循环到另一侧。这样我们看起来就是墙面的砖块效果。我们在程序中定义了一个全局变量roll,通过把它作为纹理坐标的参数,可以获得纹理滑动的效果。

在此程序中,从磁盘上加载bmp图像生成纹理依然采用得是glaux库。

(2)启用混合方式,禁用深度测试。

注意:禁用深度测试是必要的,否则看不到效果。

(3)如果启用了掩模功能,加载黑白掩模图像。

我们同样是绘制一个正方形,进行纹理贴图。

采用的混合方式是:glBlendFunc(GL_DST_COLOR,GL_ZERO);即只采用目标颜色。这样,掩模图像黑色部分对应的背景完全被遮挡住,而白色部分对应的则可以看见。

(4)加载黑白掩模图像对应的彩色图。

这时采用的混合方式是:glBlendFunc(GL_ONE,GL_ONE);最终颜色实际是源颜色和目标颜色相加而成的。


完整OpenGL程序:

#pragma comment(lib,"GLAUX.LIB") #include <GL/glut.h> #include <GL/glaux.h> #include <iostream> using namespace std; bool masking = true;//masking on or off bool mp,sp;//'m'、spacebar pressed or not bool scene = false;//draw the first or second scene GLuint texture[5];//for textures ID GLuint loop; GLfloat roll;//rolling textures //names of bitmaps for textures const char *bmpFile[5] = {"Data/GSK.bmp", "Data/mask1.bmp", "Data/image1.bmp", "Data/mask2.bmp", "Data/image2.bmp"}; //read bmp image file AUX_RGBImageRec *LoadBMP(const char *FileName) { FILE *File = NULL; if(!FileName) return NULL; File = fopen(FileName,"r"); if (File) { fclose(File); return auxDIBImageLoad(FileName); } return NULL; } //load the bitmap and convert it into a texture int LoadGLTextures() { int Status = FALSE; //AUX_RGBImageRec *TextureImage[6] = new AUX_RGBImageRec[6];//create storage for the texture AUX_RGBImageRec *TextureImage[6] = {NULL,NULL,NULL,NULL,NULL,NULL}; for(int i = 0;i < 5;i++) { //memset(TextureImage[i],0,sizeof(void*) * 1);//set the point to NULL if (TextureImage[i] = LoadBMP(bmpFile[i])) { Status = TRUE; glGenTextures(1,&texture[i]);//命名纹理对象 glBindTexture(GL_TEXTURE_2D,texture[i]);//绑定纹理 glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage[i]->sizeX, TextureImage[i]->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE, TextureImage[i]->data);//指定纹理 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//指定过滤模式 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); } if (TextureImage[i]) { if (TextureImage[i]->data) free(TextureImage[i]->data); free(TextureImage[i]); } } return Status; } void reshape(int w,int h) { if (0 == h) h = 1; glViewport(0,0,(GLsizei)w,(GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f,(GLfloat)w / (GLfloat)h,1,100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int init() { if (!LoadGLTextures()) { return 0; } glClearColor(0.0f,0.0f,0.0f,0.0f); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glEnable(GL_TEXTURE_2D); if (!scene) { cout << "scene 1 is drawing" << endl; } else { cout << "scene 2 is drawing" << endl; } if (masking) { cout << "masking on" << endl; } else { cout << "masking off" << endl; } return 1; } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0,0,-2.0); //load background glBindTexture(GL_TEXTURE_2D,texture[0]); glBegin(GL_QUADS); glTexCoord2f(0.0f,-roll + 0.0f); glVertex3f(-1.1f,-1.1f,0.0f); glTexCoord2f(3.0f,-roll + 0.0f); glVertex3f(1.1f,-1.1f,0.0f); glTexCoord2f(3.0f,-roll + 3.0f); glVertex3f(1.1f,1.1f,0.0f); glTexCoord2f(0.0f,-roll + 3.0f); glVertex3f(-1.1f,1.1f,0.0f); glEnd(); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST);//necessary if (masking)//masking enabled { glBlendFunc(GL_DST_COLOR,GL_ZERO); } if (scene)//are we draw the second scene? { glTranslatef(0,0,-1); glRotatef(roll * 360,0,0,1); if (masking) { //load mask 2 image glBindTexture(GL_TEXTURE_2D,texture[3]); glBegin(GL_QUADS); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.1f,-1.1f,0.0f); glTexCoord2f(1.0f,0.0f); glVertex3f(1.1f,-1.1f,0.0f); glTexCoord2f(1.0f,1.0f); glVertex3f(1.1f,1.1f,0.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.1f,1.1f,0.0f); glEnd(); } glBlendFunc(GL_ONE,GL_ONE); //load the colored images mask 2 based on glBindTexture(GL_TEXTURE_2D,texture[4]); glBegin(GL_QUADS); //all the same as mask 2 image glTexCoord2f(0.0f,0.0f); glVertex3f(-1.1f,-1.1f,0.0f); glTexCoord2f(1.0f,0.0f); glVertex3f(1.1f,-1.1f,0.0f); glTexCoord2f(1.0f,1.0f); glVertex3f(1.1f,1.1f,0.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.1f,1.1f,0.0f); glEnd(); } else//draw the first scene { if (masking) { glBindTexture(GL_TEXTURE_2D,texture[1]); glBegin(GL_QUADS); glTexCoord2f(roll + .0f,0.0f); glVertex3f(-1.1f,-1.1f,0.0f); glTexCoord2f(roll + 4.0f,0.0f); glVertex3f(1.1f,-1.1f,0.0f); glTexCoord2f(roll + 4.0f,4.0f); glVertex3f(1.1f,1.1f,0.0f); glTexCoord2f(roll + 0.0f,4.0f); glVertex3f(-1.1f,1.1f,0.0f); glEnd(); } glBlendFunc(GL_ONE,GL_ONE); //load the colored images second mask based on glBindTexture(GL_TEXTURE_2D,texture[2]); glBegin(GL_QUADS); glTexCoord2f(roll + .0f,0.0f); glVertex3f(-1.1f,-1.1f,0.0f); glTexCoord2f(roll + 4.0f,0.0f); glVertex3f(1.1f,-1.1f,0.0f); glTexCoord2f(roll + 4.0f,4.0f); glVertex3f(1.1f,1.1f,0.0f); glTexCoord2f(roll + 0.0f,4.0f); glVertex3f(-1.1f,1.1f,0.0f); glEnd(); } glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); glutSwapBuffers(); } void idle() { roll += 0.002f;//move the texture if (roll > 1.0f) { roll -= 1.0f; } glutPostRedisplay(); } void keyboard(unsigned char key,int x,int y) { switch(key) { case 's'://toggle from one scene to the other scene = !scene; if (!scene) { cout << "scene 1 is drawing" << endl; } else { cout << "scene 2 is drawing" << endl; } if (masking) { cout << "masking on" << endl; } else { cout << "masking off" << endl; } glutPostRedisplay(); break; case 'm'://toggle masking from on to off masking = !masking; if (!scene) { cout << "scene 1 is drawing" << endl; } else { cout << "scene 2 is drawing" << endl; } if (masking) { cout << "masking on" << endl; } else { cout << "masking off" << endl; } glutPostRedisplay(); break; } } int main(int argc,char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(100,100); glutCreateWindow("Masking"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutIdleFunc(idle); glutMainLoop(); return 0; } 运行结果:

(注意:按下s键可以在两个场景中切换,按下m键可以切换是否开启掩模)

场景1,开启掩模:


场景2,开启掩模:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值