OpenGL-ES 学习(2)---- DepthTest

深度测试

OpenGL-ES 深度测试是指在片段着色器执行之后,利用深度缓冲区所保存的深度值决定当前片段是否被丢弃的过程

深度缓冲区通常和颜色缓冲区有着相同的宽度和高度,一般由窗口系统自动创建并将其深度值存储为 16、 24 或 32 位浮点数。(注意只保存深度值)

当深度测试开启的时候, OpenGL-ES 才会测试深度缓冲区中的深度值;如果此测试通过,深度缓冲内的值可以被设为新的深度值;如果深度测试失败,则丢弃该片段。

深度测试是在片段着色器运行之后(并且在模板测试运行之后)在屏幕空间 (screen space) 中执行的。

屏幕空间坐标相关的视区是由 OpenGL-ES 的视口设置函数 glViewport 函数给定,并且可以通过片段着色器中内置的 gl_FragCoord 变量访问。

gl_FragCoord 的 X 和 y 表示该片段的屏幕空间坐标 ((0,0) 在左下角),其取值范围由 glViewport 函数决定,屏幕空间坐标原点位于左下角。

gl_FragCoord 还包含一个 z 坐标,它包含了片段的实际深度值,此 z 坐标值是与深度缓冲区的内容进行比较的值。

深度缓冲区中包含深度值介于 0.0 和 1.0 之间,物体接近近平面的时候,深度值接近 0.0 ,物体接近远平面时,深度接近 1.0。

深度测试实现

开启深度测试后,如果片段通过深度测试,OpenGL-ES 自动在深度缓冲区存储片段的 gl_FragCoord.z 值,如果深度测试失败,那么相应地丢弃该片段。

如果启用深度测试,那么需要在渲染之前使用 glClear(GL_DEPTH_BUFFER_BIT);清除深度缓冲区,否则深度缓冲区将保留上一次进行深度测试时所写的深度值。

另外在一些场景中,我们需要进行深度测试并相应地丢弃片段,但我们不希望更新深度缓冲区,那么可以设置深度掩码 glDepthMask(GL_FALSE);实现禁用深度缓冲区的写入(只有在深度测试开启时才有效)。

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

OpenGL-ES 深度测试是通过深度测试函数 glDepthFunc 控制深度测试是否通过和如何更新深度缓冲区。

参数作用说明
GL_ALWAYS永远通过测试
GL_NEVER永远不通过测试
GL_LESS片段值小于深度缓冲区通过测试
GL_EQUAL片段值等于深度缓冲区通过测试
GL_LEQUAL片段值小于等于深度缓冲区通过测试
GL_NOTEQUAL片段值不等于等于深度缓冲区通过测试
GL_GREATER片段值大于深度缓冲区通过测试
GL_GEQUAL片段值大于等于深度缓冲区通过测试

深度测试启用后,默认情况下深度测试函数使用 GL_LESS,这将丢弃深度值高于或等于当前深度缓冲区的值的片段。

代码实现

原理: 绘制了两张图片,并且设置投影矩阵,使其都绕着 Y 轴旋转,注意这两张图片的初始化的 Z 轴坐标是不一致的,所以会出现不同的深度,此时的深度可以理解为 Camera
系统里的景深的概念。

  • 如果开启深度测试,近端的画面会遮挡远端,出现正确的深度效果
  • 如果不开启,会出现两张图片在抢夺 Z 的现象
static int Init(ESContext *esContext)
{
	UserData *userData = esContext->userData;
	const char vShaderStr[] =
		"#version 300 es                             \n"
		"uniform mat4 u_mvpMatrix;                   \n"
		"layout(location = 0) in vec4 a_position;    \n"
		"layout(location = 1) in vec2 a_texCoord;   \n"
		"out vec2 v_texCoord;                       \n"
		"void main()                                 \n"
		"{                                           \n"
		"   gl_Position = u_mvpMatrix * a_position;  \n"
		"   v_texCoord = a_texCoord;                \n"
		"}                                           \n";


	char fShaderStr[] =
		"#version 300 es                                     \n"
		"precision mediump float;                            \n"
		"in vec2 v_texCoord;                                 \n"
		"layout(location = 0) out vec4 outColor;             \n"
		"uniform sampler2D s_texture;                        \n"
		"vec4 tempColor;                                     \n"
		"void main()                                         \n"
		"{                                                   \n"
		"  tempColor = texture( s_texture, v_texCoord );    \n"
		"  outColor = vec4(tempColor.r, tempColor.b, tempColor.g, tempColor.a); \n"
		"}                                                   \n";

	userData->programObject = esLoadProgram(vShaderStr, fShaderStr);
	userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");
	userData->textureIdFront = loadTgaTextures("./Huskey.tga");
	userData->textureIdBack = loadTgaTextures("./scene.tga");

	userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix");
	userData->angle = 0.0f;

	// 启用深度测试
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

	return TRUE;
}

static void Draw(ESContext *esContext)
{
	UserData *userData = esContext->userData;
	GLfloat vertices1[] = {
		-0.7f,  0.7f, 0.5f,  // 左上
		-0.7f, -0.7f, 0.5f,  // 左下
		 0.7f, -0.7f, 0.5f,  // 右下
		 0.7f,  0.7f, 0.5f   // 右上
	};

	GLfloat vertices2[] = {
		// 顶点坐标 (x, y, z)
		-0.5f,  0.5f, 0.1f, 
		-0.5f, -0.5f,  0.1f, 
		 0.5f, -0.5f,  0.1f, 
		 0.5f,  0.5f,  0.1f, 
	};

	GLfloat texCoords[] = {
		// 纹理坐标 (s, t)
		0.0f, 0.0f,  
		0.0f, 1.0f,  
		1.0f, 1.0f,   
		1.0f, 0.0f, 
	};

	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

	glViewport(0, 0, esContext->width, esContext->height);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glUseProgram(userData->programObject);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), vertices1);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), texCoords);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);

	// Bind the texture
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, userData->textureIdFront);

	// Set the sampler texture unit to 0
	glUniform1i(userData->samplerLoc, 0);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);


    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), vertices2);
    glEnableVertexAttribArray(0);
	glActiveTexture(GL_TEXTURE0);

	glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);
	glBindTexture(GL_TEXTURE_2D, userData->textureIdBack);
	glUniform1i(userData->samplerLoc, 0);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

}

static void Update(ESContext *esContext, float deltaTime)
{
	UserData *userData = esContext->userData;
	ESMatrix perspective;
	ESMatrix orthographic;
	ESMatrix modelview;
	float    aspect;

	// Compute a rotation angle based on time to rotate the cube
	userData->angle += (deltaTime * 40.0f);

	if (userData->angle >= 360.0f)
	{
		userData->angle -= 360.0f;
	}

	aspect = (GLfloat)esContext->width / (GLfloat)esContext->height;

	// Generate a perspective matrix with a 60 degree FOV
	// 如果不需要 Perspective 可以不设置
	esMatrixLoadIdentity(&perspective);
	esPerspective(&perspective, 45.0f, aspect, 1.0f, 20.0f);

	//  Generate a model view matrix to rotate/translate the cube
	//  沿着 Z 轴负方向平移两个位置
	//  沿着 y 轴旋转一定的角度  x y z repsents x y z rotate
	esMatrixLoadIdentity(&modelview);
	esTranslate(&modelview, 0.0, 0.0, -2.0);
	esRotate(&modelview, userData->angle, 0.0, 1.0, 0.0);

	esMatrixMultiply(&userData->mvpMatrix, &modelview, &perspective);

}
static void ShutDown(ESContext *esContext)
{
	UserData *userData = esContext->userData;
	glDeleteTextures(1, &userData->textureIdFront);
	glDeleteTextures(1, &userData->textureIdBack);
	glDeleteProgram(userData->programObject);
}

实际效果如下:
启动深度测试的效果:
正确的深度测试效果

不启用深度测试:
不正确的深度测试效果

Z-Fight 现象

深度测试中,深度冲突现象需要值得注意。深度冲突(Z-fighting)是指两个平面(或三角形)相互平行且靠近的过于紧密,深度缓冲区不具有足够的精度确定哪一个平面靠前,导致这两个平面的内容不断交替显示,看上去像平面内容争夺顶靠前的位置。

防止深度冲突的方法:

  • 不要让物体之间靠得过近,以免它们的三角形面片发生重叠;
  • 把近平面设置得远一些(越靠近近平面的位置精度越高);
  • 牺牲一些性能,使用更高精度的深度值。
  • 14
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【例3-2】使用glut库函数绘制一个真实感的球。 # include < GL/glut.h > /* 初始化材料属性、光源属性、光照模型,打开深度缓冲区等 */ void init(void) { GLfloat light_position [ ] = { 1.0, 1.0, 1.0, 0.0 }; glClearColor ( 0.0, 0.0, 1.0, 0.0 );//设置背景色为蓝色 glShadeModel ( GL_SMOOTH ); glLightfv ( GL_LIGHT0, GL_POSITION, light_position); glEnable (GL_LIGHTING); glEnable (GL_LIGHT0); glEnable (GL_DEPTH_TEST); } /*调用GLUT函数,绘制一个球*/ void display ( void ) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidSphere (1.0, 40, 50); //半径为1,40条纬线,50条经线 glFlush (); } /* 定义GLUT的reshape函数,w、h分别是输出图形的窗口的宽和高*/ void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity ( ); if (w <= h) glOrtho (-1.5, 1.5, -1.5 * ( GLfloat ) h / ( GLfloat ) w,1.5 * ( GLfloat ) h / ( GLfloat ) w, -10.0, 10.0 ); else glOrtho (-1.5 * ( GLfloat ) w / ( GLfloat ) h,1.5 * ( GLfloat ) w / ( GLfloat ) h, -1.5, 1.5, -10.0, 10.0); glMatrixMode ( GL_MODELVIEW ); glLoadIdentity ( ) ; } int main(int argc, char** argv) { glutInit (&argc, argv); // GLUT环境初始化 glutInitDisplayMode (GLUT_SINGLE |GLUT_RGB |GLUT_DEPTH); // 显示模式初始化 glutInitWindowSize (300, 300); // 定义窗口大小 glutInitWindowPosition (100, 100); // 定义窗口位置 glutCreateWindow ( argv [ 0 ] ); // 显示窗口,窗口标题为执行函数名 init( ); // 调用init函数 glutDisplayFunc ( display ); // 注册OpenGL绘图函数(一种的特殊调用方式,下同) glutReshapeFunc ( reshape ); // 注册窗口大小改变时的响应函数 glutMainLoop( ); // 进入GLUT消息循环,开始执行程序 return 0; }
OpenGLES是一个专门用于嵌入式系统和移动设备的图形渲染API,可以用来绘制各种2D和3D图形。下面是一个简单的使用OpenGLES绘制图形的步骤: 1. 创建OpenGL ES上下文,需要使用EGL来完成这个步骤。 2. 配置OpenGL ES的状态,包括背景颜色、深度缓冲区、清除颜色和深度缓冲区等。 3. 创建OpenGL ES对象,包括着色器程序、顶点缓冲区、纹理等。 4. 绘制图形,使用绑定的着色器程序、顶点缓冲区、纹理等,调用OpenGL ES绘制函数进行绘制。 5. 交换前后缓冲区,将绘制结果显示到屏幕上。 下面是一个简单的OpenGL ES绘制三角形的示例代码: ```c++ #include <GLES2/gl2.h> #include <EGL/egl.h> EGLDisplay display; EGLSurface surface; EGLContext context; GLuint programObject; const GLfloat vertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f }; const char *vertexShaderSource = "attribute vec4 a_Position;\n" "void main() {\n" " gl_Position = a_Position;\n" "}\n"; const char *fragmentShaderSource = "precision mediump float;\n" "void main() {\n" " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; void init() { // 创建OpenGL ES上下文 EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLConfig config; EGLint numConfigs; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, &majorVersion, &minorVersion); eglChooseConfig(display, configAttribs, &config, 1, &numConfigs); EGLSurface surface = eglCreateWindowSurface(display, config, nativeWindow, NULL); EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); eglMakeCurrent(display, surface, surface, context); // 配置OpenGL ES状态 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // 创建OpenGL ES对象 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); programObject = glCreateProgram(); glAttachShader(programObject, vertexShader); glAttachShader(programObject, fragmentShader); glLinkProgram(programObject); glViewport(0, 0, width, height); } void render() { // 清除颜色缓冲区和深度缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 绑定着色器程序 glUseProgram(programObject); // 绑定顶点缓冲区 GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 设置顶点属性 GLuint positionLocation = glGetAttribLocation(programObject, "a_Position"); glEnableVertexAttribArray(positionLocation); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); // 绘制三角形 glDrawArrays(GL_TRIANGLES, 0, 3); // 交换前后缓冲区 eglSwapBuffers(display, surface); } int main() { init(); while (true) { render(); } return 0; } ``` 这是一个OpenGL ES 2.0的示例代码,包含了创建OpenGL ES上下文、配置OpenGL ES状态、创建OpenGL ES对象、绘制三角形等步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值