文章目錄
- 多邊形常見操作
- OpenGL 模板測試實現
- GLUT架構下實現:
- 參考
多邊形常見操作android api sample中的region 操作如:本文基於opengl 的stencil buffer 實現這幾種多邊形運算。OpenGL 模板測試實現如: 如,Source為原始半透明重疊多邊形繪製效果,重疊部分因為融合的緣故 有增強效果。Union
聯合操作,需保證每個像素 若且唯若只屬於一個多邊形,為此通過模板測試實現的具體思路:
- 用0x00 清除樣板緩衝區,開啟模板測試
- 寫樣板緩衝區,同時進行模板測試,同時寫顏色緩衝區:保證只有模板值為0的片源可以通過模板測試,而且通過模板測試後 模板值加1 操作。
Difference
做差操作,是兩個矩形相減效果,順序無關,具體實現:
- 0x00 清除樣板緩衝區
- 禁止顏色緩衝區寫入,禁止模板測試,畫任意一個矩形,將模板值加1 操作。此時末班緩衝區中第一個矩形繪製地區為mask地區,該地區內不能繪圖。
- 開啟模板測試,只能在模板值為0x00的地方繪圖,畫第二個矩形,模板測試通過後模板值加1。
XOr
異或操作,兩個矩形相交的地區不顯示,不相交的地區顯示,具體思路:
- 0x00 清除樣板緩衝區,
- 禁掉模板測試,禁掉顏色緩衝區寫入,將模板值加1操作,繪製兩個矩形,相交地區的模板值為2,其他矩形地區模板值為1。
- 開啟模板測試,允許寫入顏色緩衝區,測試條件為模板值等於1,模板值為8位,此時掩碼為0x01,二進位為00000001。繪製兩個矩形。模板測試通過後將模板值置為0。
Intersection
相交操作,只顯示兩個矩形相交地區,具體思路:
- 0x00 清除樣板緩衝區,
- 禁掉模板測試,禁掉顏色緩衝區寫入,將模板值加1操作,繪製兩個矩形,相交地區的模板值為2,其他矩形地區模板值為1。
- 開啟模板測試,允許寫入顏色緩衝區,測試條件為模板值等於2,模板值為8位,此時掩碼為0x03,二進位為00000011。繪製任意一個矩形。模板測試通過後將模板值置為0。
GLUT架構下實現:
// @module:stencil render// @file:opacityRectRender.cpp// @author:peteryfren// @date:2013/3/28// @version:1.0// @desc:通過樣板緩衝區實現半透明矩形的常見操作。#include <stdio.h>#include <string.h>#include <stdlib.h>#include <assert.h>#include <time.h>#include <math.h>#include <gl/glut.h>const int windowWidth = 256;const int windowHeight = 256;GLenum checkForError(char *loc);void opacitySourceRender(int width, int height);void opacityRectXorRender(int width, int height);void opacityRectUnionRender(int width, int height);void opacityRectIntersectRender(int width, int height);void opacityRectDifferenceRender(int width, int height);void Redraw(void){glCullFace(GL_BACK);float destAlpha = 0.5;glClearColor(0,0,0, 0.5);// 指定清理顏色值glClearStencil(0x00);// 指定清理幀緩衝值glClearDepth(0.0);// 指定清理深度緩衝值glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// glEnable (GL_TEXTURE_2D);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);opacitySourceRender(windowWidth, windowHeight);// opacityRectDifferenceRender(windowWidth, windowHeight);// opacityRectIntersectRender(windowWidth, windowHeight);// opacityRectUnionRender(windowWidth, windowHeight);// opacityRectXorRender(windowWidth, windowHeight);glutSwapBuffers();checkForError("swap");}void opacitySourceRender(int width, int height){// one way to solve this in generic OpenGL is to //fill the framebuffer with your desired alpha channel, // switch the blending mode to glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA)//and draw the rectangles. glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);float tileVertices[] = {0,height/2, width,height/2, width,height*3/4, 0,height*3/4}; glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);float tileVertices1[] = {width/4,0, width/2,0, width/2,height, width/4,height}; glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);}void opacityRectDifferenceRender(int width, int height){glEnable(GL_STENCIL_TEST);// draw mask areaglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);glStencilFunc(GL_ALWAYS, 0, 0xFF);// 禁模板測試glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);// 模板值加1glColor4f(1, 0, 0, 0.1);float tileVertices[] = {0,height/2, width,height/2, width,height*3/4, 0,height*3/4};glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//static unsigned char data[windowWidth*windowHeight];//glReadPixels(0, 0, windowWidth, windowHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, data);//SaveFileGrayBMP("stencil.bmp", data, windowWidth, windowHeight);// draw main areaglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);glStencilFunc(GL_EQUAL, 0x00, 0x01);// 只能在模板為0的地方繪圖glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);glColor4f(1, 0, 0, 0.5);float tileVertices1[] = {width/4,0, width/2,0, width/2,height, width/4,height}; glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);glDisable(GL_STENCIL_TEST);}void opacityRectXorRender(int width, int height){glEnable(GL_STENCIL_TEST);glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);// draw mask area glStencilOp(GL_INCR, GL_INCR, GL_INCR);glStencilFunc(GL_ALWAYS, 0x00, 0xFF);// 禁用模板float tileVertices[] = {0,height/2, width,height/2, width,height*3/4, 0,height*3/4};glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 0, 0, 0.5);float tileVertices1[] = {width/4,0, width/2,0, width/2,height, width/4,height}; glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);//static unsigned char data[windowWidth*windowHeight];//glReadPixels(0, 0, windowWidth, windowHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, data);//SaveFileGrayBMP("stencil.bmp", data, windowWidth, windowHeight);glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);glStencilFunc(GL_EQUAL, 0x01, 0x01);// 模板值為1的地區才繪製glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);// 用0替換當前值glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);glDisable(GL_STENCIL_TEST);}void opacityRectIntersectRender(int width, int height){glEnable(GL_STENCIL_TEST);glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);// draw mask area glStencilOp(GL_INCR, GL_INCR, GL_INCR);glStencilFunc(GL_ALWAYS, 0x00, 0xFF);// 禁用模板float tileVertices[] = {0,height/2, width,height/2, width,height*3/4, 0,height*3/4};glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 0, 0, 0.5);float tileVertices1[] = {width/4,0, width/2,0, width/2,height, width/4,height}; glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);//static unsigned char data[windowWidth*windowHeight];//glReadPixels(0, 0, windowWidth, windowHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, data);//SaveFileGrayBMP("stencil.bmp", data, windowWidth, windowHeight);glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);glStencilFunc(GL_EQUAL, 0x02, 0x03);// 模板值為2的地區才繪製 掩碼0000 0011glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices1);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);glDisable(GL_STENCIL_TEST);}void opacityRectUnionRender(int width, int height){// 樣板緩衝區就一個位元組glEnable (GL_STENCIL_TEST);// glStencilFunc(GL_ALWAYS,0,0xFF);// 禁用模板測試glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);// 開啟寫入顏色緩衝區// fail = KEEP 模版測試失敗後保持樣板緩衝區中值 不變// zfail = KEEP 深度測試失敗後保持模版緩衝區中值 不變// zpass = INCR 深度測試通過後對模版緩衝區中值 加1操作glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);// glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);// func = EQUAL 只有與參考值相等才能通過模版測試// ref = 0x00參考值// mask = 0x01隻比較最低位glStencilFunc(GL_EQUAL, 0x0, 0x1);// 開啟模板測試glEnable (GL_BLEND);// 開啟混合glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// sfactor = 1 - dstA// dfactor = dstA// glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);float tileVertices[] = {0,height/2, width,height/2, width,height*3/4, 0,height*3/4};glColor4f(1, 0, 0, 0.5);glVertexPointer(2, GL_FLOAT, 0, tileVertices);glEnableClientState(GL_VERTEX_ARRAY);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 0, 0, 0.5);float tileVertices1[] = {width/4,0, width/2,0, width/2,height, width/4,height}; glVertexPointer(2, GL_FLOAT, 0, tileVertices1); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glColor4f(1, 1, 1, 1);//static unsigned char data[windowWidth*windowHeight];//glReadPixels(0, 0, windowWidth, windowHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, data);//SaveFileGrayBMP("stencil.bmp", data, windowWidth, windowHeight);glDisable (GL_STENCIL_TEST);}void Button(int button, int state, int x, int y){if (state != GLUT_UP)return;switch (button) {case GLUT_LEFT_BUTTON:glutPostRedisplay();break;case GLUT_RIGHT_BUTTON:glutPostRedisplay();break;}}void Keyboard(unsigned char key, int x, int y){glutPostRedisplay();}void Reshape(int width, int height){glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(0.0f, (GLfloat) windowWidth, 0.0f, (GLfloat) windowHeight, -1.0f, 1.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glViewport(0, 0, windowWidth, windowHeight);}int main(int argc, char *argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH|GLUT_STENCIL);glutInitWindowSize(windowWidth, windowHeight);glutCreateWindow("Region");// set up world space to screen mappingglMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(0.0f, (GLfloat) windowWidth, 0.0f, (GLfloat) windowHeight, -1.0f, 1.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glViewport(0, 0, windowWidth, windowHeight);glClearColor(1.0, 1.0, 1.0, 1.0);glutDisplayFunc(Redraw);glutReshapeFunc(Reshape);glutMouseFunc(Button);glutKeyboardFunc(Keyboard);glEnable(GL_CULL_FACE);glutMainLoop();return 0;}GLenum checkForError(char *loc){GLenum errCode;const GLubyte *errString;if ((errCode = glGetError()) != GL_NO_ERROR){errString = gluErrorString(errCode);printf("OpenGL error: %s",errString);if (loc != NULL)printf("(%s)",loc);printf("\n");}return errCode;}參考1. opengl 模板測試理論:http://blog.csdn.net/xiajun07061225/article/details/73884172. glStencilFunc函數講解:http://blog.csdn.net/doing5552/article/details/22972803. opencsg http://www.opencsg.org/