OpenGL(十三) Alpha测试、剪裁测试
Alpha測(cè)試測(cè)試就是測(cè)試每一個(gè)像素的Alpha值是否滿足某一個(gè)特定的條件,如果滿足,則該像素會(huì)被繪制,如果不滿足則不繪制,跟深度測(cè)試的機(jī)制是一樣的,只不過(guò)深度測(cè)試考察的是像素的“深度”屬性,Alpha測(cè)試考察的是像素的“Alpha”屬性。
利用Alpha測(cè)試的這一特性,可以模擬兩幅圖像疊加,但是又要求前景圖像有一部分是透明的場(chǎng)景,這時(shí)候可以把要求透明的區(qū)域內(nèi)的每一個(gè)像素的Alpha值設(shè)置為0,在之后的Alpha測(cè)試的通過(guò)條件設(shè)置為大于0.5才通過(guò),這樣Alpha值為0的像素就不會(huì)被繪制,達(dá)到透明的效果。
通過(guò)glEnable(GL_ALPHA_TEST)啟用Alpha測(cè)試,通過(guò)GLDisable(GL_ALPHA_TEST)禁用Alpha測(cè)試。
設(shè)置Alpha測(cè)試的通過(guò)條件的函數(shù)是glAlphaFunc(GLenum_func,GLclampf ref),func是參數(shù)的比較方式,ref是參數(shù),可以取的參數(shù)以及含義如下:
- GL_ALWAYS(始終通過(guò))
- GL_NEVER(始終不通過(guò))
- GL_LESS(小于則通過(guò))
- GL_LEQUAL(小于等于則通過(guò))
- GL_EQUAL(等于則通過(guò))
- GL_GEQUAL(大于等于則通過(guò))
- GL_NOTEQUAL(不等于則通過(guò))
例如有如下兩幅圖像需要疊加,第一個(gè)是前景圖像,第二個(gè)是背景圖像,場(chǎng)景要求是疊加之后的效果是從窗戶里看過(guò)去的效果。
背景:
前景:
可以利用Alpha測(cè)試,設(shè)置前景圖像中白色部分的Alpah值為0,其他部分的Alpha值為1,在測(cè)試條件中選用GL_GREATER(大于則通過(guò)):
#define WindowWidth 400 #define WindowHeight 400 #define WindowTitle "OpenGLAlpha測(cè)試" #define BMP_Header_Length 54 #include <gl/glut.h> #include <stdio.h> #include <stdlib.h>GLuint texGround; GLuint texWall; int power_of_two(int n) {if( n <= 0 )return 0;return (n & (n-1)) == 0; } /* 函數(shù)load_texture * 讀取一個(gè)BMP文件作為紋理 * 如果失敗,返回0,如果成功,返回紋理編號(hào) */ GLuint load_texture(const char* file_name) {GLint width, height, total_bytes;GLubyte* pixels = 0;GLint last_texture_ID;GLuint texture_ID = 0;// 打開(kāi)文件,如果失敗,返回FILE* pFile = fopen(file_name, "rb");if( pFile == 0 )return 0;// 讀取文件中圖象的寬度和高度f(wàn)seek(pFile, 0x0012, SEEK_SET);fread(&width, 4, 1, pFile);fread(&height, 4, 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET);// 計(jì)算每行像素所占字節(jié)數(shù),并根據(jù)此數(shù)據(jù)計(jì)算總像素字節(jié)數(shù){GLint line_bytes = width * 3;while( line_bytes % 4 != 0 )++line_bytes;total_bytes = line_bytes * height;}// 根據(jù)總像素字節(jié)數(shù)分配內(nèi)存pixels = (GLubyte*)malloc(total_bytes);if( pixels == 0 ){fclose(pFile);return 0;}// 讀取像素?cái)?shù)據(jù)if( fread(pixels, total_bytes, 1, pFile) <= 0 ){free(pixels);fclose(pFile);return 0;} {GLint max;glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);if( !power_of_two(width)|| !power_of_two(height)|| width > max|| height > max ){const GLint new_width = 1024; //修改為2的整數(shù)次冪const GLint new_height = 1024; // 規(guī)定縮放后新的大小為邊長(zhǎng)的正方形GLint new_line_bytes, new_total_bytes;GLubyte* new_pixels = 0;// 計(jì)算每行需要的字節(jié)數(shù)和總字節(jié)數(shù)new_line_bytes = new_width * 3;while( new_line_bytes % 4 != 0 )++new_line_bytes;new_total_bytes = new_line_bytes * new_height;// 分配內(nèi)存new_pixels = (GLubyte*)malloc(new_total_bytes);if( new_pixels == 0 ){free(pixels);fclose(pFile);return 0;}// 進(jìn)行像素縮放gluScaleImage(GL_RGB,width, height, GL_UNSIGNED_BYTE, pixels,new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);// 釋放原來(lái)的像素?cái)?shù)據(jù),把pixels指向新的像素?cái)?shù)據(jù),并重新設(shè)置width和heightfree(pixels);pixels = new_pixels;width = new_width;height = new_height;}}// 分配一個(gè)新的紋理編號(hào)glGenTextures(1, &texture_ID);if( texture_ID == 0 ){free(pixels);fclose(pFile);return 0;}// 綁定新的紋理,載入紋理并設(shè)置紋理參數(shù)// 在綁定前,先獲得原來(lái)綁定的紋理編號(hào),以便在最后進(jìn)行恢復(fù)glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);glBindTexture(GL_TEXTURE_2D, texture_ID);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);glBindTexture(GL_TEXTURE_2D, last_texture_ID);// 之前為pixels分配的內(nèi)存可在使用glTexImage2D以后釋放// 因?yàn)榇藭r(shí)像素?cái)?shù)據(jù)已經(jīng)被OpenGL另行保存了一份(可能被保存到專門(mén)的圖形硬件中)free(pixels);return texture_ID; } void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte absolute) {GLint width, height;GLubyte* pixels = 0;// 獲得紋理的大小信息glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);// 分配空間并獲得紋理像素pixels = (GLubyte*)malloc(width*height*4);if( pixels == 0 )return;glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);// 修改像素中的Alpha值// 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2], pixels[i*4+3]// 分別表示第i個(gè)像素的藍(lán)、綠、紅、Alpha四種分量,0表示最小,255表示最大{GLint i;GLint count = width * height;for(i=0; i<count; ++i){if( abs(pixels[i*4] - b) <= absolute&& abs(pixels[i*4+1] - g) <= absolute&& abs(pixels[i*4+2] - r) <= absolute )pixels[i*4+3] = 0;elsepixels[i*4+3] = 255;}}// 將修改后的像素重新設(shè)置到紋理中,釋放內(nèi)存glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);free(pixels); } void display(void) {static int initialized = 0;static GLuint texWindow = 0;static GLuint texPicture = 0;// 執(zhí)行初始化操作,包括:讀取背景,讀取前景,將相框由BGR顏色轉(zhuǎn)換為BGRA,啟用二維紋理if( !initialized ){texPicture = load_texture("backImage.bmp");texWindow = load_texture("frontImage.bmp");glBindTexture(GL_TEXTURE_2D, texWindow);texture_colorkey(255, 255, 255, 10);glEnable(GL_TEXTURE_2D);initialized = 1;}// 清除屏幕glClear(GL_COLOR_BUFFER_BIT);// 繪制背景,此時(shí)不需要進(jìn)行Alpha測(cè)試,所有的像素都進(jìn)行繪制glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(65,1,2,50); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,4.5,0,0,0,0,1,0); glBindTexture(GL_TEXTURE_2D, texPicture);glDisable(GL_ALPHA_TEST);glBegin(GL_QUADS);glTexCoord2f(0, 0); glVertex3f(-6.0f, -6.0f,-3);glTexCoord2f(0, 1); glVertex3f(-6.0f, 6.0f,-3);glTexCoord2f(1, 1); glVertex3f( 6.0f, 6.0f,-3);glTexCoord2f(1, 0); glVertex3f( 6.0f, -6.0f,-3);glEnd();// 繪制前景,此時(shí)進(jìn)行Alpha測(cè)試,只繪制不透明部分的像素glBindTexture(GL_TEXTURE_2D, texWindow);glEnable(GL_ALPHA_TEST);glAlphaFunc(GL_GREATER, 0.5f);glBegin(GL_QUADS);glTexCoord2f(0, 0); glVertex3f(-3.0f, -3.0f,0);glTexCoord2f(0, 1); glVertex3f(-3.0f, 3.0f,0);glTexCoord2f(1, 1); glVertex3f( 3.0f, 3.0f,0);glTexCoord2f(1, 0); glVertex3f( 3.0f, -3.0f,0);glEnd();// 交換緩沖glutSwapBuffers(); } int main(int argc, char* argv[]) {// GLUT初始化glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(WindowWidth, WindowHeight);glutCreateWindow(WindowTitle);glutDisplayFunc(&display);// 開(kāi)始顯示glutMainLoop();return 0; }
實(shí)現(xiàn)效果,左側(cè)視角:
正視視角:
右側(cè)視角:
剪裁測(cè)試:
所謂剪裁測(cè)試就是限定一個(gè)矩形繪制窗口,只有在這個(gè)窗口范圍內(nèi)的像素才會(huì)被繪制,窗口外的像素被忽略。使用glEnable(GL_SCISSOR_TEST)開(kāi)啟剪裁測(cè)試,使用GLDisable(GL_SCISSOR_TEST)關(guān)閉。使用
glScissor (GLint x, GLint y, GLsizei width, GLsizei height)設(shè)定剪裁窗口。
在上例代碼的基礎(chǔ)上,只需要在顯示部分函數(shù)display清屏之后,加入以下兩句:
glEnable(GL_SCISSOR_TEST);glScissor(0,0,300,300);
就可以實(shí)現(xiàn)把顯示畫(huà)面劃定在以左下角為起點(diǎn)的300*300的剪裁窗口中,顯示效果如下:
總結(jié)
以上是生活随笔為你收集整理的OpenGL(十三) Alpha测试、剪裁测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: https的安全密钥
- 下一篇: 几种直播流媒体协议