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.mzph.cn/news/682690.shtml

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

相关文章

YoloV8改进策略:BackBone改进|Mamba-UNet改进YoloV8,打造全新的Yolo-Mamba网络

摘要 本文尝试使用Mamba主干网络替换YoloV8的主干网络,打造最新的Yolo-Mamba网络。 论文:《Mamba-UNet:用于医学图像分割的类似UNet的纯视觉Mamba网络》 在医学图像分析的最新进展中,卷积神经网络(CNN)和视觉转换器(ViT)都取得了显著的基准成绩。前者通过其卷积操作…

红队笔记Day3-->隧道上线不出网机器

昨天讲了通过代理的形式(端口转发)实现了上线不出网的机器,那么今天就来讲一下如何通过隧道上线不出网机器 目录 1.网络拓扑 2.开始做隧道?No!!! 3.icmp隧道 4.HTTP隧道 5.SSH隧道 1.什么…

HarmonyOS鸿蒙学习基础篇 - 自定义组件(一)

前言 在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离&#…

【Linux】yum软件包管理器

目录 Linux 软件包管理器 yum 什么是软件包 Linux安装软件 查看软件包 关于rzsz Linux卸载软件 查看yum源 扩展yum源下载 Linux开发工具 vim编辑器 上述vim三种模式之间的切换总结: 命令模式下,一些命令: vim配置 Linux 软件包管理…

项目访问量激增该如何应对

✨✨ 欢迎大家来到喔的嘛呀的博客✨✨ 🎈🎈希望这篇博客对大家能有帮助🎈🎈 目录 引言 一. 优化数据库 1.1 索引优化 1.2 查询优化 1.3 数据库设计优化 1.4 事务优化 1.5 硬件优化 1.6 数据库配置优化 二. 增加服务器资源…

JVM(4)原理篇

1 栈上的数据存储 在Java中有8大基本数据类型: 这里的内存占用,指的是堆上或者数组中内存分配的空间大小,栈上的实现更加复杂。 以基础篇的这段代码为例: Java中的8大数据类型在虚拟机中的实现: boolean、byte、char…

【微信小程序开发】小程序版的防抖节流应该怎么写

由于微信小程序与普通网页的开发、编译、运行机制都有所不同,在防抖节流的方法使用上也就需要我们做一些比较棘手的适配操作。常见的H5开发的防抖节流此处就不再分享了,网上有太多的教程,或者直接问那群AI即可。 OK,言归正传&…

【AI视野·今日CV 计算机视觉论文速览 第300期】Tue, 30 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Tue, 30 Jan 2024 Totally 146 papers 👉上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Computer Vision for Primate Behavior Analysis in the Wild Authors Richard Vogg, Timo L ddecke, Jonathan Henrich, …

应用进程跨越网络的通信

目录 1 系统调用和应用编程接口 应用编程接口 API 几种应用编程接口 API 套接字的作用 几种常用的系统调用 1. 连接建立阶段 2. 传送阶段 3. 连接释放阶段 1 系统调用和应用编程接口 大多数操作系统使用系统调用 (system call ) 的机制在应用程序和操作系统之间传递控制…

Java基于SpringBoot+vue的租房网站,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

[BIZ] - 1.金融交易系统数据特点

1.1 数据量极大 交易系统的数据量特大,主要来自以下几种类型的数据。 1.1.1 行情 行情是交易系统最为重要的数据,交易就是在不断变化的行情中寻找时机来实现盈利的。海量的行情主要分成两种,一种是tick数据(也叫逐笔行情&#…

【学网攻】 第(27)节 -- HSRP(热备份路由器协议)

系列文章目录 目录 系列文章目录 文章目录 前言 一、HSRP(热备份路由器协议)是什么? 二、实验 1.引入 实验目标 实验背景 技术原理 实验步骤 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交…

day 31贪心

day31 贪心 分发饼干 题目链接: 分发饼干 题目描述 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最…

MySQL性能调优篇(4)-查询语句的优化与重构

MySQL数据库查询语句的优化与重构 MySQL是一种常用的关系型数据库管理系统,广泛应用于Web开发中。在实际应用中,对数据库查询语句的优化和重构是提高应用性能和响应速度的重要手段。本文将介绍一些常见的优化技巧和重构方法,帮助开发者提高数…

sqlserver2012 解决日志大的问题

当SQL Server 2012的事务日志变得过大时,这通常意味着日志备份没有被定期执行,或者日志文件的自动增长设置被设置得太高,导致它不断增长以容纳所有未备份的事务。解决日志大的问题通常涉及以下几个步骤: 备份事务日志:…

OpenAI ChatGPT 记忆功能怎么实现?

你的聊天助手现在能“记住”你的对话了! 2月14日凌晨,OpenAI宣布正在测试ChatGPT的新功能——记住用户提问内容,并自由控制内存。这意味着,ChatGPT能帮你记住那些重要的聊天内容,让你的对话更流畅、更自然。 想象一下…

HMI(人机界面设计)大扫盲了,UI设计的重要领域,附案例。

Hello,我是大千UI工场,开始分享HMI设计了,这个可是除了手机和电脑外的,最重要的设计领域哦,可能你觉的它很陌生,其实生活中处处可见。关注我们,学习N多UI干货,有设计需求&#xff0c…

Android 12.0 Camera 分辨率从高到低排列功能实现

1.前言 在12.0的系统ROM定制化开发功能中,在对Camera2的产品进行定制化的时候,在camera2的设置页面,总是会发现在预览 分辨率的列表中,有的产品不是按照分辨率的大小来进行排序显示的,所以就需要了解显示流程,然后按顺序排序来实现 功能,接下来实现相关功能 2.Camer…

C++中类和结构体的区别(代码说明)

C中的类和结构体都是用于定义自定义数据类型的关键字。它们之间有很多相似之处,但也有一些关键的区别。 1 主要区别 区别类结构体默认访问权限私有公有是否支持多态支持不支持是否支持继承支持支持是否可以定义构造函数和析构函数可以可以常用场景封装数据和行为&…

Python算法探索:从经典到现代(二)

一、引言 Python作为一种高级编程语言,其简洁明了的语法和丰富的库资源,使得它成为算法实现的理想选择。本文将带您从经典算法出发,逐步探索到现代算法,感受Python在算法领域的魅力。 二、经典算法:贪心算法 贪心算法…