WebGL 正确处理对象前后的关系——隐藏面消除(深度测试)/ 深度冲突

目录

前言

验证WebGL处理对象前后关系的规则——后绘制的图形覆盖先绘制的图形 

隐藏面消除(深度测试)

开启隐藏面消除功能,需要遵循以下两步:

1.开启隐藏面消除功能。

gl.enable()函数规范

2.在绘制之前,清除深度缓冲区。 

gl.clear(gl.DEPTH_BUFFER_BIT)

隐藏消除面示例代码(DepthBuffer) 

示例效果

深度冲突

深度冲突效果

产生深度冲突的原因 

开启多边形偏移功能,同样需要遵循以下两步:

1.启用多边形偏移。

2.在绘制之前指定用来计算偏移量的参数。 

gl.polygonOffset()函数规范​编辑

深度冲突示例代码(Zfighting)

示例效果


前言

在真实世界中,如果你将两个盒子一前一后放在桌上,如下图所示,前面的盒子会挡住部分后面的盒子。

验证WebGL处理对象前后关系的规则——后绘制的图形覆盖先绘制的图形 

看一下WebGL模型视图投影矩阵_山楂树の的博客-CSDN博客示例程序PerspectiveView_mvp的效果,如下图所示。绿色三角形的一部分被黄色和蓝色三角形挡住了。看上去似乎是WebGL专为三维图形学设计,能够自动分析出三维对象的远近,并正确处理遮挡关系。 

 遗憾的是,事实没有想象得那么美好。在默认情况下,WebGL为了加速绘图操作,是按照顶点在缓冲区中的顺序来处理它们的。之前的程序都是先定义远的物体,后定义近的物体,从而产生正确的效果。

比如,在PerspectiveView_mvp中,我们按照如下顺序定义了三角形的顶点和颜色数据,注意加粗显示的Z坐标。

WebGL按照顶点在缓冲区中的顺序(第1个是最远的绿色三角形,第2是中间的黄色三角形,第3是最近的蓝色三角形)来进行绘制。后绘制的图形将覆盖已经绘制好的图形,这样就恰好产生了近处的三角形挡住远处的三角形的效果,如上图所示。 

为了验证这一点,我们将缓冲区中三角形顶点数据的顺序调整一下,把近处的蓝色三角形定义在前面,然后是中间的黄色三角形,最后是远处的绿色三角形,如下所示:

运行程序,你就会发现本该出现在最远处的绿色三角形,不自然地挡住了近处的黄色和蓝色三角形,如下图所示。 

WebGL在默认情况下会按照缓冲区中的顺序绘制图形,而且后绘制的图形覆盖先绘制的图形,因为这样做很高效。如果场景中的对象不发生运动,观察者的状态也是唯一的,那么这种做法没有问题。但是如果,比如说你希望不断移动视点,从不同的角度看物体,那么你不可能事先决定对象出现的顺序。 

隐藏面消除(深度测试)

为了解决这个问题,WebGL提供了隐藏面消除(hidden surface removal)功能。这个功能会帮助我们消除那些被遮挡的表面(隐藏面),你可以放心地绘制场景而不必顾及各物体在缓冲区中的顺序,因为那些远处的物体会自动被近处的物体挡住,不会被绘制出来。这个功能已经内嵌在WebGL中了,你只需要简单地开启这个功能就可以了。

开启隐藏面消除功能,需要遵循以下两步:

1.开启隐藏面消除功能。

gl.enable(gl.DEPTH_TEST)

所谓深度检测(DEPTH_TEST)听上去可能有些奇怪,实际上这么命名是因为该机制是通过检测物体(的每个像素的)的深度来决定是否将其画出来的。 

第1步所用的gl.enable()函数实际上可以开启WebGL中的多种功能,其规范如下: 

gl.enable()函数规范

 

2.在绘制之前,清除深度缓冲区。 

gl.clear(gl.DEPTH_BUFFER_BIT)

 第2步,使用gl.clear()方法清除深度缓冲区(depth buffer)。深度缓冲区是一个中间对象,其作用就是帮助WebGL进行隐藏面消除。WebGL在颜色缓冲区中绘制几何图形,绘制完成后将颜色缓冲区显示到<canvas>上。如果要将隐藏面消除,那就必须知道每个几何图形的深度信息,而深度缓冲区就是用来存储深度信息的。由于深度方向通常是Z轴方向,所以有时候我们也称它为Z缓冲区。

深度缓冲区与隐藏面消除

在绘制任意一帧之前,都必须清除深度缓冲区,以消除绘制上一帧时在其中留下的痕迹。如果不这样做,就会出现错误的结果。我们调用gl.clear()函数,并传入参数gl.DEPTH_BUFFER_BIT清除深度缓冲区: 

gl.clear(gl.DEPTH_BUFFER_BIT)

当然,还需要清除颜色缓冲区。用按位或符号(|)连接gl.DEPTH_BUFFER_BIT和gl.COLOR_BUFFER_BIT,并作为参数传入gl.clear()中:

类似地,同时清除任意两个缓冲区时,都可以使用按位或符号。

与gl.enable()函数对应的还有gl.disable()函数,其规范如下所示,前者启用某个功能,后者则禁用之。

gl.disable()函数规范 

隐藏消除面示例代码(DepthBuffer) 

示例程序名为DepthBuffer.js,它在WebGL模型视图投影矩阵_山楂树の的博客-CSDN博客PerspectiveView_mvp.js的基础上,加入了隐藏面消除的相关代码。注意,缓冲区中顶点的顺序没有改变,程序依然按照近处(蓝色),中间(黄色),远处(绿色)的顺序绘制三角形(但颠倒了绘制顺序——蓝色 -> 黄色 -> 绿色)。程序运行的效果和PerspectiveView_mvp完全一样,程序的代码如下所示。

示例效果

运行DepthBuffer,可见程序成功地消除了隐藏面,位于近处的三角形挡住了远处的三角形。该程序证明了不管视点位于何处,隐藏面都能够被消除。在任何三维场景中,你都应该开启隐藏面消除,并在适当的时刻清空深度缓冲区(通常是在绘制每一帧之前)。

 应当注意的是,隐藏面消除的前提是正确设置可视空间,否则就可能产生错误的结果。不管是盒状的正射投影空间,还是金字塔状的透视投影空间,你必须使用一个。

深度冲突

隐藏面消除是WebGL的一项复杂而又强大的特性,在绝大多数情况下,它都能很好地完成任务。然而,当几何图形或物体的两个表面极为接近时,就会出现新的问题,使得表面看上去斑斑驳驳的,如下图。这种现象被称为深度冲突(Z fighting)。现在,我们来画两个Z值完全一样的三角形。

深度冲突效果

产生深度冲突的原因 

 之所以会产生深度冲突,是因为两个表面过于接近,深度缓冲区有限的精度已经不能区分哪个在前,哪个在后了。严格地说,如果创建三维模型阶段就对顶点的深度值加以注意,是能够避免深度冲突的。但是,当场景中有多个运动着的物体时,实现这一点几乎是不可能的。

WebGL提供一种被称为多边形偏移(polygon offset)的机制来解决这个问题。该机制将自动在Z值加上一个偏移量,偏移量的值由物体表面相对于观察者视线的角度来确定。启用该机制只需要两行代码:

开启多边形偏移功能,同样需要遵循以下两步:

1.启用多边形偏移。

gl.enable(gl.POLYGON_OFFSET_FILL)

2.在绘制之前指定用来计算偏移量的参数。 

gl.polygonOffset(1.0, 1.0)

绘制两个冲突物体的中间时刻调用

 第1步调用了gl.enable()启用多边形偏移,注意启用隐藏面消除用到的也是该函数,只不过两者传入了不同的参数。第2步中的函数gl.polygonOffset()的规范如下。

gl.polygonOffset()函数规范

来看一下示例程序Zfighting,该程序使用了多边形偏移来避免深度冲突。 

深度冲突示例代码(Zfighting)

可见,所有顶点的Z坐标值都一样,为-0.5(第80行),但是却没有出现深度冲突现象。 

在代码的其余部分,我们开启了多边形偏移机制(第70行),然后绘制了一个绿色的三角形(第72行)和一个黄色的三角形(第74行)。两个三角形的数据存储在同一个缓冲区中,所以需要格外注意gl.drawArrays()的第2个和第3个参数。第2个参数表示开始绘制的顶点的编号,而第3个参数表示该次操作绘制的顶点个数。所以,我们先画了一个绿色三角形,然后通过gl.polygonOffset()设置了多边形偏移参数,使之后的绘制受到多边形偏移机制影响,再画了一个黄色三角形。运行程序,你将看到两个三角形没有发生深度冲突,如下图)所示。注释掉第73行再次运行程序,深度冲突就会再次出现,如上图:深度冲突效果。

示例效果

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

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

相关文章

2023常用的原型设计软件推荐

美观易操作的产品原型可以帮助团队构建积极的用户体验,帮助团队理解产品交互逻辑。 因此,可互动、易修改的产品原型设计对产品的点击率和回访率具有重要意义。 选择专业的产品原型设计工具,可以为团队和企业带来高效的产品设计体验。本文选…

ddtrace 系列篇之 dd-trace-java 项目编译

dd-trace-java 是 Datadog 开源的 java APM 框架,本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要:jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常&#xf…

Linux JAVA环境的搭建tomcat的部署(含多实例)

tomcat tomcat是Apache软件基金会项目中的一个核心项目由 Apache、Sun 和其他一些公司及个人共同开发而成。tomcat 是 Java 语言开发的,Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器. tomcat的组成 tomcat用于支持Java Servlet和JSP。它是一个重要的We…

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单AdaptiveTextSelectionToolba样式UI效果

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单样式UI效果 在开发过程中,需要长按TextField输入框cut、copy设置为中文“复制、粘贴”,我首先查看了TextField中的源码,看到了ToolbarOptions、AdaptiveTextSelectionToo…

AI与医疗保健:革命性技术如何拯救生命

文章目录 引言AI的应用领域1. 影像识别2. 疾病诊断3. 药物研发4. 个性化治疗 AI技术1. 机器学习2. 深度学习3. 自然语言处理4. 基因组学 实际案例1. Google Health的深度学习模型2. IBM Watson for Oncology3. PathAI的病理学分析 道德和隐私考虑结论 🎉欢迎来到AIG…

实验4 交换机端口隔离(access模式)

交换机端口隔离(access模式) 实验目的实验拓扑实验步骤(1)在未划分vlan前,配置pc1、pc2的地址,如图所示(2)测试两台pc机的连通性(3)创建vlan,并验…

按键点亮led灯

原理图: K0这个按键按下时,开发板D1这个灯亮,松开,灯灭 代码如下: #include "stm32f4xx.h" void LED_Init(void) {//1.定义一个GPIO外设的结构体变量 GPIO_InitTypeDef GPIO_InitStructure;//RCC_AHB1PeriphClockCmd(RCC_AHB1Pe…

Linux底层基础知识

一.汇编,C语言,C,JAVA之间的关系 汇编,C语言,C可以通过不同的编译器,编译成机器码。而java只能由Java虚拟机识别。Java虚拟机可以看成一个操作系统,Java虚拟机是由汇编,C&#xff0c…

分享一下微信商城如何添加新客有礼活动

一、新客有礼活动的优势 新客有礼活动是一种非常有效的营销策略,通过向新用户提供优惠和礼品,可以吸引更多的用户关注和购买。以下是一些新客有礼活动的优势: 吸引新用户:新客有礼活动可以吸引更多的新用户关注和购买&#xff0c…

12306 抢票小助手: 完整易用的抢票解决方案 | 开源日报 0917

testerSunshine/12306 Stars: 31.4k License: MIT 12306 购票小助手是一个使用 Python 编写的项目,主要功能包括自动打码、自动登录、准点预售和捡漏、智能候补以及邮件通知等。该项目具有以下核心优势: 支持多个版本的 Python提供验证码本地识别功能可…

docker四种网络模式

文章目录 一.为什么要了解docker网络二.docker 网络理论三.docker的四类网络模式3.1 bridge模式3.2 host模式3.3 container模式3.4 none模式 四.bridge模式下容器的通信4.1 防火墙开启状态4.2 防火墙关闭状态 一.为什么要了解docker网络 当你开始大规模使用Docker时&#xff0…

Springboot部署服务器项目上线

第一步,项目打包,有两种方式 第一种、直接在项目根目录打开终端,输入以下语句即可。如下图: mvn clean package -DskipTests 第二种、在右侧点击 Maven选项,选择鼠标左键双击package选项即可。如下图: 两…

CocosCreator3.8研究笔记(十七)CocosCreator UI组件(一)

CocosCreator 中,用户界面 User-interface(UI)组件和2d渲染对象的区别在于2D 渲染对象一般只负责将2D 对象渲染出来,而 UI 则更多的承担着用户交互的能力。 常用的 UI 控件可通过添加节点的方式来创建。 在 层级管理器 中点击左上…

算法宝典1——Java版本(此系列持续更新,这篇文章有20道)(有题目的跳转链接)(此份宝典包含了链表、栈、队列、二叉树的算法题)

注:由于字数的限制,我打算把算法宝典做成一个系列,一篇文章就20题!!! 目录 一、链表的算法题(目前10道) 1. 移除链表元素(力扣;思路:前后指针&…

宋浩概率论笔记(六)样本与统计量

参数估计的入门章节,为后面的参数估计与假设检验铺垫基础,难点在于背诵公式,此外对于统计量的理解一定要清晰——本质是多个随机变量复合而成的函数~

ARM接口编程—Interrupt(exynos 4412平台)

CPU与硬件的交互方式 轮询 CPU执行程序时不断地询问硬件是否需要其服务,若需要则给予其服务,若不需要一段时间后再次询问,周而复始中断 CPU执行程序时若硬件需要其服务,对应的硬件给CPU发送中断信号,CPU接收到中断信号…

MySQL常用函数集锦 --- 字符串|数值|日期|流程函数总结

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、字符…

在c#中使用CancellationToken取消任务

目录 🚀介绍: 🐤简单举例 🚀IsCancellationRequested 🚀ThrowIfCancellationRequested 🐤在控制器中使用 🚀通过异步方法的参数使用cancellationToken 🚀api结合ThrowIfCancel…

js创建动态key的对象ES6和ES5的方法

前提: 有个场景,循环数组,根据每一项的值,往一个数组中push一个新对象,对象的key不同要从数组中获取 情况解析:push没有什么问题,问题就是创建一个动态key的对象。下面就说一下如何以参数为key…

第二证券股票分析:什么是赛道股和题材股?

赛道股和题材股是两种经常被出资者关注的股票类型。赛道股是指代表着产业趋势和未来增加方向的上市公司股票,例如新能源汽车、5G通信等。题材股则是针对商场上的某些抢手事情或话题而产生的股票炒作。那么赛道股和题材股有哪些不同之处?在进行这类出资时…