OpenGL(十三) Alpha测试、剪裁测试
Alpha測試測試就是測試每一個像素的Alpha值是否滿足某一個特定的條件,如果滿足,則該像素會被繪制,如果不滿足則不繪制,跟深度測試的機制是一樣的,只不過深度測試考察的是像素的“深度”屬性,Alpha測試考察的是像素的“Alpha”屬性。
利用Alpha測試的這一特性,可以模擬兩幅圖像疊加,但是又要求前景圖像有一部分是透明的場景,這時候可以把要求透明的區域內的每一個像素的Alpha值設置為0,在之后的Alpha測試的通過條件設置為大于0.5才通過,這樣Alpha值為0的像素就不會被繪制,達到透明的效果。
通過glEnable(GL_ALPHA_TEST)啟用Alpha測試,通過GLDisable(GL_ALPHA_TEST)禁用Alpha測試。
設置Alpha測試的通過條件的函數是glAlphaFunc(GLenum_func,GLclampf ref),func是參數的比較方式,ref是參數,可以取的參數以及含義如下:
- GL_ALWAYS(始終通過)
- GL_NEVER(始終不通過)
- GL_LESS(小于則通過)
- GL_LEQUAL(小于等于則通過)
- GL_EQUAL(等于則通過)
- GL_GEQUAL(大于等于則通過)
- GL_NOTEQUAL(不等于則通過)
例如有如下兩幅圖像需要疊加,第一個是前景圖像,第二個是背景圖像,場景要求是疊加之后的效果是從窗戶里看過去的效果。
背景:
前景:
可以利用Alpha測試,設置前景圖像中白色部分的Alpah值為0,其他部分的Alpha值為1,在測試條件中選用GL_GREATER(大于則通過):
#define WindowWidth 400 #define WindowHeight 400 #define WindowTitle "OpenGLAlpha測試" #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; } /* 函數load_texture * 讀取一個BMP文件作為紋理 * 如果失敗,返回0,如果成功,返回紋理編號 */ GLuint load_texture(const char* file_name) {GLint width, height, total_bytes;GLubyte* pixels = 0;GLint last_texture_ID;GLuint texture_ID = 0;// 打開文件,如果失敗,返回FILE* pFile = fopen(file_name, "rb");if( pFile == 0 )return 0;// 讀取文件中圖象的寬度和高度fseek(pFile, 0x0012, SEEK_SET);fread(&width, 4, 1, pFile);fread(&height, 4, 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET);// 計算每行像素所占字節數,并根據此數據計算總像素字節數{GLint line_bytes = width * 3;while( line_bytes % 4 != 0 )++line_bytes;total_bytes = line_bytes * height;}// 根據總像素字節數分配內存pixels = (GLubyte*)malloc(total_bytes);if( pixels == 0 ){fclose(pFile);return 0;}// 讀取像素數據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的整數次冪const GLint new_height = 1024; // 規定縮放后新的大小為邊長的正方形GLint new_line_bytes, new_total_bytes;GLubyte* new_pixels = 0;// 計算每行需要的字節數和總字節數new_line_bytes = new_width * 3;while( new_line_bytes % 4 != 0 )++new_line_bytes;new_total_bytes = new_line_bytes * new_height;// 分配內存new_pixels = (GLubyte*)malloc(new_total_bytes);if( new_pixels == 0 ){free(pixels);fclose(pFile);return 0;}// 進行像素縮放gluScaleImage(GL_RGB,width, height, GL_UNSIGNED_BYTE, pixels,new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);// 釋放原來的像素數據,把pixels指向新的像素數據,并重新設置width和heightfree(pixels);pixels = new_pixels;width = new_width;height = new_height;}}// 分配一個新的紋理編號glGenTextures(1, &texture_ID);if( texture_ID == 0 ){free(pixels);fclose(pFile);return 0;}// 綁定新的紋理,載入紋理并設置紋理參數// 在綁定前,先獲得原來綁定的紋理編號,以便在最后進行恢復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分配的內存可在使用glTexImage2D以后釋放// 因為此時像素數據已經被OpenGL另行保存了一份(可能被保存到專門的圖形硬件中)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個像素的藍、綠、紅、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;}}// 將修改后的像素重新設置到紋理中,釋放內存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;// 執行初始化操作,包括:讀取背景,讀取前景,將相框由BGR顏色轉換為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);// 繪制背景,此時不需要進行Alpha測試,所有的像素都進行繪制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();// 繪制前景,此時進行Alpha測試,只繪制不透明部分的像素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);// 開始顯示glutMainLoop();return 0; }
實現效果,左側視角:
正視視角:
右側視角:
剪裁測試:
所謂剪裁測試就是限定一個矩形繪制窗口,只有在這個窗口范圍內的像素才會被繪制,窗口外的像素被忽略。使用glEnable(GL_SCISSOR_TEST)開啟剪裁測試,使用GLDisable(GL_SCISSOR_TEST)關閉。使用
glScissor (GLint x, GLint y, GLsizei width, GLsizei height)設定剪裁窗口。
在上例代碼的基礎上,只需要在顯示部分函數display清屏之后,加入以下兩句:
glEnable(GL_SCISSOR_TEST);glScissor(0,0,300,300);
就可以實現把顯示畫面劃定在以左下角為起點的300*300的剪裁窗口中,顯示效果如下:
總結
以上是生活随笔為你收集整理的OpenGL(十三) Alpha测试、剪裁测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: https的安全密钥
- 下一篇: 几种直播流媒体协议