OpenGL实战教程(11) -- 第十站:像素深度测试

绘制每一个像素,只有通过测试的像素才会被绘制,没有通过测试的像素则不进行绘制。如像在绘制物体时,远处被遮挡的物体不绘制,只有可见的物体被绘制一样。这就与绘制的函数调用先后顺序无关。如果没有像素的测试,在相同区域,后调用绘制函数的绘制结果,就会把先调用绘制函数的结果遮盖着。

OpenGL中有剪裁测试、 深度测试、Alpha 测试和模板测试。

1、剪裁测试

剪裁测试用于限制绘制区域。指定一个矩形的剪裁窗口,当启用剪裁测试后,只有在这个窗口之内的像素才能被绘制,其它像素则会被丢弃。无论怎么绘制,剪裁窗口以外的像素将不会被修改。

需要使用剪裁测试功能时,先调用函数开启它。

glEnable(GL_SCISSOR_TEST); // 启用剪裁测试
glDisable(GL_SCISSOR_TEST); // 禁用剪裁测试

指定剪裁区域

glScissor(x, y, width, height);

位置在(x, y),宽度为 width,高度为 height 的剪裁窗口。
OpenGL 窗口坐标是以左下角为(0, 0),右上角为(width, height)的,这与 Windows 系统窗口不同。

2、 Alpha 测试

RGBA模式的像素由R、G、B、Alpha 分量构成,其中的 Alpha 值用于混合操作。Alpha 值另一个用途,这就是 Alpha 测试。当每个像素即将绘制时,当启动了 Alpha 测试功能, 有 Alpha 值满足条件的像素才会进行绘制。这个条件有可以是:
(1)始终通过(默认情况)
(2)始终不通过
(3)大于设定值通过
(4)小于设定值通过
(5)等于设定值通过
(6)大于等于设定值通过
(7)小于等于设定值通过
(8)不等于设定值通过。

启用或禁用 Alpha 测试:

glEnable(GL_ALPHA_TEST); // 打开Alpha 测试
glDisable(GL_ALPHA_TEST); // 关闭 Alpha 测试

条件设定函数:
void glAlphaFunc (GLenum func, GLclampf ref);
GLenum func:功能号

GL_ALWAYS(始终通过)
GL_NEVER(始终不通过)
GL_LESS(小于则通过)
GL_LEQUAL(小于等于则通过)
GL_EQUAL(等于则通过)
GL_GEQUAL(大于等于则通过)
GL_NOTEQUAL(不等于则通过)

GLclampf ref:参考值

3、模板测试

模板测试需要一个模板缓冲区,模板缓冲区是在初始化 OpenGL 时创建。

(1)初始化GLUT_STENCIL功能

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);

(2)启用或禁用模板测试

glEnable(GL_STENCIL_TEST); // 打开模板测试
glDisable(GL_STENCIL_TEST); // 停止模板测试

(3)模板设定函数:

void glStencilFunc (GLenum func, GLint ref, GLuint mask);
GLenum func:功能号,与glAlphaFunc 相同
GLint ref:参考值,与glAlphaFunc 类同
GLuint mask:掩码,则只比较 mask 中二进制为 1 的位。
例如:glStencilFunc(GL_LESS, 3, mask);
某个像素值为 5(二进制 101),而 mask 的二进制值为 00000011,因为只比较最后两位, 5 的最后两位为 01,满足条件会通过测试。

(4)模板测试后的动作设定函数:

glStencilOp(fail, zfail, zpass);
fail:模板测试未通过时的像素处理
zfail:模板测试通过,但深度测试未通过时的像素处理
zpass:模板测试和深度测试均通过时的像素处理

fail, zfail, zpass可以取以下值:

GL_KEEP(不改变,这也是默认值),
GL_ZERO(回零),
GL_REPLACE(使用测试条件中的设定值来代替当前模板值)
GL_INCR(增加 1,但如果已经是最大值,则保持不变)
GL_INCR_WRAP(增加 1,但如果已经是最大值,则从零重新开始)
GL_DECR(减少 1,但如果已经是零,则保持不变)
GL_DECR_WRAP(减少 1,但如果已经是零,则重新设置为最大值)
GL_INVERT(按位取反)。

4、深度测试

深度是指该像素点在3D世界中距离摄像机位置的Z值。有一个缓冲区存放每个像素点深度值,即深度缓冲区。深度越大Z值越大。在不使用深度测试的时候,假如我们先绘制一个近距离的物体,在绘制一个远距离的物体,远距离物体因为后绘制,就会把近距离的物体覆盖掉。

开启深度测试的时候,首先要将表面对应的像素的深入值和当前深度缓冲区中的值进行比较,如果大于深入缓冲区中的值,则丢弃这部分,否者就利用该像素对应的深度值和颜色值分别更新深度缓冲区和颜色缓冲区。这个过程就是深度测试。

(1)深度测试的开启:

glEnable(GL_DEPTH_TEST); // 打开深度测试
glDisable(GL_DEPTH_TEST);// 关闭深度测试

(2)清除深度缓冲区:

glClear(GL_DEPTH_BUFFER_BIT);

(3)深度测试函数:

void glDepthFunc (GLenum func);
GL_NEVER:永不绘制
GL_LESS:如果目标像素z值<当前像素z值,则绘制目标像素
GL_EQUAL:如果目标像素z值=当前像素z值,则绘制目标像素
GL_LEQUAL:如果目标像素z值<=当前像素z值,则绘制目标像素
GL_GREATER :如果目标像素z值>当前像素z值,则绘制目标像素
GL_NOTEQUAL:如果目标像素z值<>当前像素z值,则绘制目标像素
GL_GEQUAL:如果目标像素z值>=当前像素z值,则绘制目标像素GL_ALWAYS:总是绘制

4、源代码

(1)调用glDisable(GL_DEPTH_TEST),去掉深度测试功能,看看效果。


void Step10_DeepthTest(void)
{
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	const GLfloat light_position[] = { 1.0f, 0.0f, -1.0f, 1.0f };
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	const GLfloat light_ambient[] = { 1.0f, 1.0f, 0.0f, 1.0f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);

	glDisable(GL_DEPTH_TEST); <------

	// 先画立方体
	glLoadIdentity();  //加载单位矩阵   
	glTranslatef(0, 0.2, -1.0);  // 移动位置
	glRotatef(60, 0.0, 1.0, 0);  // 沿Y轴旋转60度(以弧度值为单位),
	glutSolidCube(0.4);// 画一个立方体

	// 先画立方体
	glLoadIdentity();  //加载单位矩阵,下面绘制的在原点,清除原有的平移和旋转操作。
	glutSolidTeapot(0.3);// 画一个茶壶。

	glutSwapBuffers();
	return;
}

在这里插入图片描述
茶壶画到立方体前面,茶壶挡住了立方体。

(2)调用glDisable(GL_DEPTH_TEST),去掉深度测试功能,看看效果。

void Step10_DeepthTest(void)
{
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	const GLfloat light_position[] = { 1.0f, 0.0f, -1.0f, 1.0f };
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	const GLfloat light_ambient[] = { 1.0f, 1.0f, 0.0f, 1.0f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);

	glEnable(GL_DEPTH_TEST);<-----

	// 先画立方体
	glLoadIdentity();  //加载单位矩阵   
	glTranslatef(0, 0.2, -1.0);  // 移动位置
	glRotatef(60, 0.0, 1.0, 0);  // 沿Y轴旋转60度(以弧度值为单位),
	glutSolidCube(0.4);// 画一个立方体

	// 先画立方体
	glLoadIdentity();  //加载单位矩阵,下面绘制的在原点,清除原有的平移和旋转操作。
	glutSolidTeapot(0.3);// 画一个茶壶。

	glutSwapBuffers();
	return;
}

在这里插入图片描述

立方体画到茶壶前面,立方体挡住了茶壶。

5、工程项目源代码下载

在Debug–x86下编译

源代码下载

发布了31 篇原创文章 · 获赞 9 · 访问量 1024

猜你喜欢

转载自blog.csdn.net/x879014419/article/details/105239581
今日推荐