OpenGL ES 学习教程 DEPTH_TEST(深度缓冲测试)

Posted _Captain

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL ES 学习教程 DEPTH_TEST(深度缓冲测试)相关的知识,希望对你有一定的参考价值。

接触到3D,就一定会接触到深度这个概念,最直接的就是看Z轴,两个人在场景中,你的Z轴是1,我的Z轴是2,摄像机位于Z -10的位置,那么我的深度比你的大。

在OpenGL中,默认是没有开启深度检测的,也就是说,后绘制的物体覆盖先绘制的物体(颜色缓冲区中,先绘制的物体 被 后绘制的物体 覆盖)。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

来看代码例子:

//重写Render;
virtual void render()

    glClearColor(0, 0, 0, 1.0);

    glClear(GL_COLOR_BUFFER_BIT);
    
    glViewport(0, 0, m_width, m_height);
    
        //model;
        glm::mat4 model = glm::mat4(1.0f);
        
        //View
        glm::mat4 view = glm::lookAt(glm::vec3(0, 0, -10.0f), glm::vec3(0, 0,0), glm::vec3(0, 1, 0));

        //透视 注意近裁剪面 远裁剪面的值是相对于Camera Position的 这里Camera位于Z -10,那么近裁剪面是 0,远裁剪面是2.
        glm::mat4 proj = glm::perspective(glm::radians(60.0f), 1.0f, 10.0f, 12.0f);

        proj = proj*view*model;

        m_program.begin();
        
            
            //红色
            
                glm::vec4 pos[] =
                
                    glm::vec4(-2.0f, -2.0f, 1.5f, 1.0f),
                    glm::vec4(2.0f, -2.0f, 1.5f, 1.0f),
                    glm::vec4(0.0f, 2.0f, 1.5f, 1.0f),
                ;

                glm::vec4 color[] =
                
                    glm::vec4(1, 0, 0, 1),
                    glm::vec4(1, 0, 0, 1),
                    glm::vec4(1, 0, 0, 1),
                ;

                glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);

                glVertexAttribPointer(m_program.m_position, 4, GL_FLOAT, false, sizeof(glm::vec4), pos);
                glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);

                glDrawArrays(GL_TRIANGLES, 0, 3);
            
            //黄色
            
                glm::vec4 pos[] =
                
                    glm::vec4(0.0f, -2.0f, 1.7f, 1.0f),
                    glm::vec4(4.0f, -2.0f, 1.7f, 1.0f),
                    glm::vec4(2.0f, 2.0f, 1.7f, 1.0f),
                ;

                glm::vec4 color[] =
                
                    glm::vec4(1, 1, 0, 1),
                    glm::vec4(1, 1, 0, 1),
                    glm::vec4(1, 1, 0, 1),
                ;

                glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);

                glVertexAttribPointer(m_program.m_position, 4, GL_FLOAT, false, sizeof(glm::vec4), pos);
                glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);

                glDrawArrays(GL_TRIANGLES, 0, 3);
            
        
        m_program.end();
    
    eglSwapBuffers(m_EGLDisplay, m_EGLSurface);

在上面的例子中,先绘制了一个红色的三角形,再绘制了一个黄色三角形。注意 到黄色三角形的 Z 轴,是比红色三角形  大的,所以理论上黄色三角形应该在红色三角形后面。

但是实际上


然而实际上黄色三角形却到了红色三角形前面。

这是因为 OpenGL中默认没有开启深度缓冲测试,就是说,后绘制的物体覆盖先绘制的物体(颜色缓冲区中,先绘制的物体 被 后绘制的物体 覆盖)。

所以这里红色三角形 被 后绘制的黄色三角形盖住了。


下面来启用 深度缓冲测试。

首先在创建窗口的时候请求一个深度缓冲区

bool initDevice()


	const EGLint attribs[] =
	
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_BLUE_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_RED_SIZE, 8,
		EGL_ALPHA_SIZE,8,
		EGL_DEPTH_SIZE, 24, //请求深度缓冲区
		EGL_NONE
	;
	EGLint 	format(0);
	EGLint	numConfigs(0);
	EGLint  major;
	EGLint  minor;

	//! 1
	m_EGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);

	//! 2init
	eglInitialize(m_EGLDisplay, &major, &minor);

	//! 3
	eglChooseConfig(m_EGLDisplay, attribs, &m_EGLConfig, 1, &numConfigs);

	eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_NATIVE_VISUAL_ID, &format);
	//! 4 
	m_EGLSurface = eglCreateWindowSurface(m_EGLDisplay, m_EGLConfig, m_hWnd, NULL);

	//! 5
	EGLint attr[] =  EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE ;
	m_EGLContext = eglCreateContext(m_EGLDisplay, m_EGLConfig, 0, attr);
	//! 6
	if (eglMakeCurrent(m_EGLDisplay, m_EGLSurface, m_EGLSurface, m_EGLContext) == EGL_FALSE)
	
		return false;
	

	eglQuerySurface(m_EGLDisplay, m_EGLSurface, EGL_WIDTH, &m_width);
	eglQuerySurface(m_EGLDisplay, m_EGLSurface, EGL_HEIGHT, &m_height);

	//! windows api
	SendMessage(m_hWnd, WM_SIZE, 0, 0);
	return  true;

然后启用深度缓冲测试

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

//重写初始化函数;
virtual void onInit()

	Light3dWinAPP::onInit();

	m_program.Initialize();

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS); //基准设置为 1.0,那么GL_LESS 则深度小余 1.0 的通过测试

glDepthFunc 用来修改深度比较运算符,参数枚举用来指定深度值比较函数。可能是 GL_LESS,GL_GREATER,GL_LEQUAL,GL_GEQUAL,GL_NOTEQUAL,GL_ALWAYS,GL_NEVER。

看英文就能看出来大概的意思,比如 GL_LESS 的意思就是说,比深度缓冲区中原来的深度值小,就通过测试。用新的值覆盖掉缓冲区中保存的值。深度值小,就是离摄像机近。


最后在绘制的时候,添加 glClearDepth

//重写Render;
virtual void render()

	glClearColor(0, 0, 0, 1.0);
	glClearDepthf(1.0f);//深度测试的基准,注意1.0代表从近裁剪面到远裁剪面 这一段范围!!并不是指Z轴的1个单位

	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	
	glViewport(0, 0, m_width, m_height);
	
	......
	......

glClearDepth(1.0f)

深度,是一个Normolized的值,范围是 0-1,对应Z轴是从近裁剪面到远裁剪面。

所以这里的 1.0f 指的是 ,深度缓冲区中默认值是远裁剪面。


启用深度缓冲测试后


当某些片段位于 近裁剪面与远裁剪面之外,就会被摄像机裁减掉。这是摄像机的功能。

m_program.begin();

	
		glm::vec4 pos[] =
		
			glm::vec4(-2.0f, -2.0f, 1.5f, 1.0f),
			glm::vec4(2.0f, -2.0f, 1.5f, 1.0f),
			glm::vec4(0.0f, 2.0f, 2.5f, 1.0f), //这个点已经在远裁剪面之外了,所以被裁剪掉了。
		;
		
		......
		......


红色三角形 底边深度比黄色三角形底边更小,所以红色三角形底边覆盖了黄色三角形底边。

红色三角形顶角深度比黄色三角形大,所以往上 是红色三角形被黄色三角形覆盖了。

而且由于红色三角形深度值大于1,也就是被远裁剪面裁剪了,所以上面缺了一个角。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn


示例代码工程下载:

http://pan.baidu.com/s/1eRJF8Im


以上是关于OpenGL ES 学习教程 DEPTH_TEST(深度缓冲测试)的主要内容,如果未能解决你的问题,请参考以下文章

IOS – OpenGL ES 调节图像色彩替换 GPUImageFalseColorFilter

IOS – OPenGL ES 调节图像饱和度 GPUImageSaturationFilter

Android上OpenGL-ES游戏的教程和库[关闭]

IOS – OpenGL ES 图像漩涡 GPUImageSwirlFilter

IOS OpenGL ES GPUImage GPUImageWeakPixelInclusionFilter

IOS – OpenGL ES 图像漩涡 GPUImageSwirlFilter