您的位置:首页 > 运维架构

OpenGL: 模板测试实现半透明多边形运算

2014-02-26 16:20 155 查看

多边形常见操作

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 <Windows.h>
#include <GL/glut.h>

#pragma comment(lib,"glut32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"opengl32.lib")

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <math.h>

const int windowWidth = 256, windowHeight = 256;

typedef void (*opacityLogicRender)(const int, const int);
opacityLogicRender my_opacityLogicRender;

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;
}
void opacitySourceRender(int width, int height)
{
	// one way to solve this in generic OpenGL is to 
	//		fill the frame buffer 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 area
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
	glStencilFunc(GL_ALWAYS, 0, 0xFF);			// 禁模板测试
	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);		// 模板值加1

	glColor4f(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 area
	glColorMask(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 0011
	glStencilOp(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 init()
{
	printf("1. Source Render \n");
	printf("2. Difference Render \n");
	printf("3. Intersect Render \n");
	printf("4. Union Render \n");
	printf("5. Xor Render \n");

	my_opacityLogicRender = opacitySourceRender;
	glClearColor(0.0, 0.0, 0.0, 1.0);	// 指定清理颜色值
	glClearStencil(0x00);				// 指定清理帧缓冲值
	glClearDepth(0.0);					// 指定清理深度缓冲值
	glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);
	glShadeModel(GL_FLAT);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glEnable(GL_POLYGON_MODE);

	// 	glEnable(GL_BLEND);
	// 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void Redraw(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	// 	opacitySourceRender(windowWidth, windowHeight);
	// 	opacityRectDifferenceRender(windowWidth, windowHeight);
	// 	opacityRectIntersectRender(windowWidth, windowHeight);
	// 	opacityRectUnionRender(windowWidth, windowHeight);
	// 	opacityRectXorRender(windowWidth, windowHeight);

	my_opacityLogicRender(windowWidth, windowHeight);

	glutSwapBuffers();
	checkForError("swap");
}
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);
}
void mouse(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)
{
	if ('1' == key)
	{
		printf("1. Source Render \n");
		my_opacityLogicRender = opacitySourceRender;
	}
	else if ('2' == key)
	{
		printf("2. Difference Render \n");
		my_opacityLogicRender = opacityRectDifferenceRender;
	}
	else if ('3' == key)
	{
		printf("3. Intersect Render \n");
		my_opacityLogicRender = opacityRectIntersectRender;
	}
	else if ('4' == key)
	{
		printf("4. Union Render \n");
		my_opacityLogicRender = opacityRectUnionRender;
	}
	else if ('5' == key)
	{
		printf("5. Xor Render \n");
		my_opacityLogicRender = opacityRectXorRender;
	}

	glutPostRedisplay();
}
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 mapping
	// 	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);
	// 
	// 	glClearColor(1.0, 1.0, 1.0, 1.0);
	// 	glutDisplayFunc(Redraw);
	// 	glutReshapeFunc(Reshape);
	// 	glutMouseFunc(Button);
	// 	glutKeyboardFunc(Keyboard);
	// 
	// 	glEnable(GL_CULL_FACE);
	// 
	// 	glutMainLoop();
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(windowWidth, windowHeight);
	glutCreateWindow("Region");
	init();

	glutDisplayFunc(Redraw);
	glutReshapeFunc(Reshape);
	glutMouseFunc(mouse);
	glutKeyboardFunc(Keyboard);
	glutMainLoop();

	return 0;
}

参考

1. opengl 模板测试理论:http://blog.csdn.net/xiajun07061225/article/details/73884172. glStencilFunc函数讲解:http://blog.csdn.net/doing5552/article/details/22972803. opencsg http://www.opencsg.org/
/article/1342249.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: