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 textureglActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, userData->textureIdFront);// Set the sampler texture unit to 0glUniform1i(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 cubeuserData->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 rotateesMatrixLoadIdentity(&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)是指两个平面(或三角形)相互平行且靠近的过于紧密,深度缓冲区不具有足够的精度确定哪一个平面靠前,导致这两个平面的内容不断交替显示,看上去像平面内容争夺顶靠前的位置。

防止深度冲突的方法:

  • 不要让物体之间靠得过近,以免它们的三角形面片发生重叠; - 把近平面设置得远一些(越靠近近平面的位置精度越高);
  • 牺牲一些性能,使用更高精度的深度值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/469545.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MATLAB】PSO_BP神经网络回归预测(多输入多输出)算法原理

有意向获取代码,请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 PSO-BP神经网络回归预测(多输入多输出)算法是一种结合粒子群优化算法(PSO)和反向传播(BP)神经网络的混合算法。该算…

【蓝桥杯单片机入门记录】认识单片机

目录 单片机硬件平台 单片机的发展过程 单片机开发板 单片机基础知识 电平 数字电路中只有两种电平:高和低 二进制(8421码) 十六进制 二进制数的逻辑运算 “与” “或” “异或” 标准C与C51 如何学好单片机 端正学习的态度、培…

Java学习手册——第七篇基础语法

Java学习手册——第七篇基础语法 1. 注释2. 顺序语句3. 条件语句3.1 if语句3.2 switch语句 4. 循环语句4.1 for循环4.2 while 语句4.3 do...while语句 本篇为大家快速入门Java基础语法,了解一个语言的基础语法是必要的, 因为我们后期都是需要用这些基础语…

汽车出租管理系统

文章目录 汽车出租管理系统一、系统演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目源码(9.9¥带走) 汽车出租管理系统 一、系统演示 汽车租赁系统 二、项目介绍 语言:java 框架:SpringBoot、…

openGauss学习笔记-217 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-内存

文章目录 openGauss学习笔记-217 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-内存217.1 查看内存状况217.2 性能参数分析 openGauss学习笔记-217 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-内存 获取openGauss节点的CPU、内存、I/O和网络资源使用情况&…

C++类和对象-C++运算符重载->加号运算符重载、左移运算符重载、递增运算符重载、赋值运算符重载、关系运算符重载、函数调用运算符重载

#include<iostream> using namespace std; //加号运算符重载 class Person { public: Person() {}; Person(int a, int b) { this->m_A a; this->m_B b; } //1.成员函数实现 号运算符重载 Person operator(const Per…

【王道数据结构】【chapter5树与二叉树】【P158t11】

在二叉树中查找值为x的结点&#xff0c;试编写算法&#xff08;用c语言&#xff09;打印值为x的节点的所有祖先&#xff0c;假设值为x的结点不多于1个 #include <iostream> #include <stack> #include<queue> typedef struct treenode{char data;struct tree…

linux系统zabbix监控配置电话告警

电话报警 睿象云官网操作zabbix-server主机操作睿象云操作zabbix-server的web页面操作 睿象云官网&#xff1a;https://www.aiops.com/ 睿象云官网操作 登录睿象云平台后点击智能告警平台 在集成栏选择监控工具选择zabbix 填写应用名称保存并获取key zabbix-server主机操…

【Linux技术宝典】深入理解Linux基本指令:命令行新手指南

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅Linux技术宝典 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 一、Linux下基本指令1. ls 指令2. pwd指令3. clear指令4. cd指令什么是家目录&#xf…

ros自定义srv记录

文章目录 自定义srv1. 定义srv文件2. 修改 package.xml3. 修改 CMakeLists.txt4. sevice_server.py5. 运行 catkin build 测试 自定义srv ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.txt | |-- srv | | -- WordCount.srv | …

DS:二叉树的顺序结构及堆的实现

创作不易&#xff0c;兄弟们给个三连&#xff01;&#xff01; 一、二叉树的顺序存储 顺序结构指的是利用数组来存储&#xff0c;一般只适用于表示完全二叉树&#xff0c;原因如上图&#xff0c;存储不完全二叉树会造成空间上的浪费&#xff0c;有的人又会问&#xff0c;为什么…

红色系可视化界面,偶尔用用可以,长时间太刺眼。

继昨日发了白色的可视化界面&#xff0c;表明了不适合做大屏展示用&#xff0c;友友们从很多角度阐述了&#xff0c;为什么不能用白色&#xff0c;大家的结论基本一致。 今天发一些红色&#xff0c;这些在某个节日用个一小会还行&#xff0c;长时间用肯定不适合。