OpenGL ES 片元操作

2023-10-09 02:30
文章标签 es 操作 opengl 片元

本文主要是介绍OpenGL ES 片元操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 剪裁测试
  • 模板测试
  • 深度测试
  • 混合

片元着色器后续操作还包括剪裁测试、模板测试、深度测试、混合等,最终才会被送到帧缓冲区。

剪裁测试

剪裁测试可以在渲染时用来限制绘制区域,通过制定一个矩阵进一步限制帧缓冲区可以写入的像素,启用剪裁测试后,绘制不会在整个屏幕(帧缓冲区)进行,而是在指定的矩形区域进行。不在矩形区域中的片元被丢弃,在矩形区域内的片元才能被送往帧缓冲区,实际效果就是在屏幕上开辟了一个小窗口。剪裁矩形确定的范围内的视口区域的物体才会最终进入帧缓冲区。

使用函数glScissor指定剪裁区域

public static native void glScissor(int x, int y,  // 以视口坐标指定的剪裁矩形左下角int width, // 剪裁矩形像素宽度int height // 剪裁矩形像素高度);

指定剪裁矩形后,需要通过glEnable(GL_SCISSOR_TEST)函数启用剪裁测试,启用后所有的渲染操作都只对剪裁矩形生效。

模板测试

模板测试是对每一帧中的每个像素进行测试,通过和一个模板指定的对应像素进行对比决定该像素是否能通过测试,模板测试就是通过模板缓冲区中记录的模板信息完成的,首先需要初始化模板缓冲区,这可以通过渲染几何形状并制定模板缓冲区的更新方式来完成;接下来就可以使用指定的模板缓冲区中的模板信息进行其他的绘制了。

模板测试原理,比如模板缓冲区如图所示,当绘制图形时设置模板缓冲区值等于1时才绘制的话,那么接下来绘制的时候就只会在模板缓冲区设置为1的部分绘制,其他位置的片元都会被丢弃。
模板测试原理
使用glEnable(GL_STENCIL_TEST)函数启用模板测试,同时使用glClear和glClearStencil设置模板缓冲区模板值。

使用函数glStencilFunc控制模板测试的运算符

public static native void glStencilFunc(int func, // 指定模板测试的比较函数int ref,  // 指定模板测试比较值int mask  // 指定在于参考值比较之前与模板缓冲区中的值进行&运算);

比较函数取值

比较函数含义
GL_NEVER从不通过模板测试
GL_ALWAYS总是通过模板测试
GL_LESS只有参考值<(模板缓存区的值&mask)时才通过
GL_LEQUAL只有参考值<=(模板缓存区的值&mask)时才通过
GL_EQUAL只有参考值=(模板缓存区的值&mask)时才通过
GL_GEQUAL只有参考值>=(模板缓存区的值&mask)时才通过
GL_GREATER只有参考值>(模板缓存区的值&mask)时才通过
GL_NOTEQUAL只有参考值!=(模板缓存区的值&mask)时才通过

设置了模板测试的方式后,还需要设置模板测试通过或是未通过时OpenGL ES将采取什么样的操作,使用glStencilOp函数进行设置。

public static native void glStencilOp(int fail,  // 指定片元未通过模板测试时,对应模板缓冲区模板值(像素)的操作int zfail,  // 指定片元通过模板测试但没有通过深度测试时的操作int zpass  // 既通过了模板测试又通过了深度测试时执行的操作);

对模板缓冲区中的模板值(像素值)所执行的操作

模板操作含义
GL_KEEP保持当前的模板缓存区值
GL_ZERO把当前的模板缓存区值设为0
GL_REPLACE用glStencilFunc函数所指定的参考值替换模板参数值
GL_INCR/GL_INCR_WRAP增加当前的模板缓存区值,已经是最大值保持不变/变为0
GL_DECR/GL_DECR_wrap减少当前的模板缓存区值,已经是最大值保持不变/变为0
GL_INVERT将当前的模板缓存区值进行逐位的翻转

利用模板测试可以达到剪裁效果,并且可以实现不规则的剪裁。

  • 开启模板测试,使用glClear方法设置模板缓存区中的模板值都为0,然后设置模板测试的操作。
GLES20.glStencilFunc(GLES20.GL_ALWAYS, 1, 1); // 总是通过
GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE); // 通过测试未设置深度测试,认为也通过深度测试,因此是GL_REPLACE,即用glStencilFunction设置的参考值1来代替深度缓冲区中的值

进行上面的设置后再绘制不规则的剪裁区域,绘制玩该剪裁区域后,该区域对应的模板缓冲区的模板值为1,其他区域对应的模板缓冲区中的模板值为0,

  • 重新设置模板测试参数
GLES20.glStencilFunc(GLES20.GL_EQUAL, 1, 1); // 只有模板缓冲区中的模板值为1的地方才被绘制
GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_KEEP);

进行上面的设置后,只有模板缓冲区中的模板值为1的地方才被绘制,也就是只有处于该不规则的图形范围内的部分会被绘制,其他位置的片元都会被丢弃。

绘制一个矩形,用该矩形产生该区域内的模板缓冲区的数据,然后再设置符合需求的模板参数设置,比如模板值为1时通过测试,再绘制三角形。关键代码在onDrawFrame函数中

GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
Matrix.setIdentityM(mModuleMatrix, 0);
Matrix.rotateM(mModuleMatrix, 0, xAngle, 1, 0, 0);
Matrix.rotateM(mModuleMatrix, 0, yAngle, 0, 1, 0);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mViewProjectionMatrix, 0, mModuleMatrix, 0);
// 未开启模板测试
if (!openStencilTest) {mShape.drawRanctangle(mMVPMatrix);mShape.drawTrangle(mMVPMatrix);
} else {// 使用模板测试GLES20.glEnable(GLES20.GL_STENCIL_TEST);GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);GLES20.glStencilFunc(GLES20.GL_ALWAYS, 1, 0xff); // 总是通过GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE);mShape.drawRanctangle(mMVPMatrix);GLES20.glStencilFunc(GLES20.GL_EQUAL, 1, 0xff); // 只有模板缓冲区中的模板值为1的地方才被绘制GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_KEEP);mShape.drawTrangle(mMVPMatrix);GLES20.glDisable(GLES20.GL_STENCIL_TEST);
}

产生的的效果如图所示
模板测试

代码

深度测试

深度就是像素点在距离摄象机的距离,对应的也有一个深度缓冲区存储着每个像素点(绘制在屏幕上的)的深度值,深度值越大,表示离摄像机越远。深度缓冲区中保存着渲染表面上每个像素与视点最近物体的距离值。

如果没有深度缓冲区,当要绘制多个物体时,必须先绘制远处的物体再绘制近处的物体,因为如果先绘制近处的物体,那么后绘制的远处的物体会覆盖掉近处的物体。而有了深度缓冲区后,绘制的顺序就不重要了,因为深度缓冲区代表了物体离视点的距离

深度测试的默认做法:对于每个新的输入片元,将其与视点的距离和深度缓冲区中的值进行比较,如果输入的片元的深度值小于深度缓冲区中的深度值,则表示它离视点更近,则输入片元的深度将代替深度缓冲区中的值,其颜色值将代替颜色缓冲区中的颜色值。否则,表示当前要绘制的片元在已绘制的部分物体后面,则无需绘制该图形,即丢弃。

启用深度测试glEnable(GL_DEPTH_TEST)

  • glClear(GL_DEPTH_BUFFER_BIT) 清空 Depth Buffer (赋值为1.0),通常清空 Depth Buffer 和 Color Buffer 同时进行。
  • glClearDepthf(float depth) 指定清空 Depth Buffer 是使用的值,缺省为 1.0,通常无需改变这个值。

混合

混合就是把某一像素位置原来的颜色和将要画上去的颜色通过某种方式混在一起。 即某个片元的颜色(源片元)和颜色缓冲区中的像素颜色(目标片元中的像素颜色)进行混合。

Cfinal=fsourceCsourceopfdestinationCdestination

其中, fsource Csource 分表表示输入的片元的比例因子和颜色, fdestination Cdestination 分表表示颜色缓冲区中的对应位置的像素比例因子和颜色

使用函数glBlendFunc和glBlendFuncSeparate设置混合因子

public static native void glBlendFunc(int sfactor, // 源片元的混合因子int dfactor  // 目标像素的混合因子);
public static native void glBlendFuncSeparate(int srcRGB,  // 源片元的RGB颜色分量的混合因子int dstRGB,  // 目标像素的RGB颜色分量混合因子int srcAlpha,  // 源片元的alpha值的混合因子int dstAlpha   // 目标像素的alpha值的混合因子);

混合因子

混合系数枚举值RGB混合因子Alpha混合因子
GL_ZERO[0,0,0]0
GL_ONE[1,1,1]1
GL_SRC_COLOR[Rs,Gs,Bs]As
GL_ONE_MINUS_SRC_COLOR[1-Rs,1-Gs,1-Bs]1-As
GL_DST_COLOR[Rd,Gd,Bd]Ad
GL_ONE_MINUS_DST_COLOR[1-Rd,1-Gd,1-Bd]1-Ad
GL_SRC_ALPHA[As,As,As]As
GL_SRC_MINUS_SRC_ALPHA[1-As,1-As,1-As]1-As
GL_DST_ALPHA[Ad,Ad,Ad]Ad
GL_SRC_MINUS_DST_ALPHA[1-Ad,1-Ad,1-Ad]1-Ad
GL_SRC_ALPHA_STAURATE[f,f,f] f=min(As,1-Ad)1

(Rs, Gs, Bs, As)是与输入片段颜色相关的颜色分量,(Rd, Gd , Bd, Ad)是与输入片段颜色相关的颜色分量, (Rc,Gc,Bc,Ac)是通过 glBlendColor 设定的颜色常量。 使用 GL_SRC_ALHPA_SATURATE时,计算出来的最小值只适用于源颜色。

public static native void glBlendColor(float red, float green, float blue, float alpha // 指定常量混合颜色的分量值);

混合因子取值含义

  • glBlendFunc(GL_ONE, GL_ZERO) 只取源颜色,这也是默认值。
  • glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 典型的半透明遮挡效果,如果源色 alpha 为0,则取目标色,如果源色alpha为1,则取源色,最终绘制物体的颜色与物体的透明度有关。
  • glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR) 实现滤镜效果,透过有色眼镜观察事物的效果。

输入片元和像素颜色乘以各自的混合因子后,由函数glBlendEquation和glBlendEquationSeparate指定的运算来进行组合。默认情况下,混合后的颜色使用GL_FUNC_ADD运算进行加和。

public static native void glBlendEquation(int mode  // 对源片元和目标像素的操作);
public static native void glBlendEquationSeparate(int modeRGB,  // RGB分量的混合操作int modeAlpha  // alpha分量的混合操作);

上面的操作可以除了GL_FUNC_ADD还可以使用GL_FUNC_SUBTRACT、GL_FUNC_REVERSE_SUBTRACT,GL_FUNC_SUBTRACT表示从输入的片元值中减去颜色缓冲区中的像素值,GL_FUNC_REVERSE_SUBTRACT表示从当前颜色缓冲区中的像素值减去输入片元的颜色。

在上面模板测试的代码的基础上,修改onDrawFrame中增加混合部分的代码

if (!openStencilTest) {mShape.drawRanctangle(mMVPMatrix);GLES20.glEnable(GLES20.GL_BLEND);GLES20.glBlendFunc(GLES20.GL_SRC_COLOR, GLES20.GL_ONE_MINUS_SRC_COLOR);mShape.drawTrangle(mMVPMatrix);GLES20.glDisable(GLES20.GL_BLEND);
} else {GLES20.glEnable(GLES20.GL_STENCIL_TEST);GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);GLES20.glStencilFunc(GLES20.GL_ALWAYS, 1, 0xff);GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE);mShape.drawRanctangle(mMVPMatrix);// 开启混合GLES20.glEnable(GLES20.GL_BLEND);// 使用的模式为两个颜色混合GLES20.glBlendFunc(GLES20.GL_SRC_COLOR, GLES20.GL_ONE_MINUS_SRC_COLOR);GLES20.glStencilFunc(GLES20.GL_EQUAL, 1, 0xff);GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_KEEP);mShape.drawTrangle(mMVPMatrix);GLES20.glDisable(GLES20.GL_STENCIL_TEST);GLES20.glDisable(GLES20.GL_BLEND);  
}

产生如下的效果
混合

代码

这篇关于OpenGL ES 片元操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/169719

相关文章

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

Python自动化处理PDF文档的操作完整指南

《Python自动化处理PDF文档的操作完整指南》在办公自动化中,PDF文档处理是一项常见需求,本文将介绍如何使用Python实现PDF文档的自动化处理,感兴趣的小伙伴可以跟随小编一起学习一下... 目录使用pymupdf读写PDF文件基本概念安装pymupdf提取文本内容提取图像添加水印使用pdfplum

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

使用Python的requests库来发送HTTP请求的操作指南

《使用Python的requests库来发送HTTP请求的操作指南》使用Python的requests库发送HTTP请求是非常简单和直观的,requests库提供了丰富的API,可以发送各种类型的HT... 目录前言1. 安装 requests 库2. 发送 GET 请求3. 发送 POST 请求4. 发送

Python使用python-pptx自动化操作和生成PPT

《Python使用python-pptx自动化操作和生成PPT》这篇文章主要为大家详细介绍了如何使用python-pptx库实现PPT自动化,并提供实用的代码示例和应用场景,感兴趣的小伙伴可以跟随小编... 目录使用python-pptx操作PPT文档安装python-pptx基础概念创建新的PPT文档查看

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

MySQL 数据库表与查询操作实战案例

《MySQL数据库表与查询操作实战案例》本文将通过实际案例,详细介绍MySQL中数据库表的设计、数据插入以及常用的查询操作,帮助初学者快速上手,感兴趣的朋友跟随小编一起看看吧... 目录mysql 数据库表操作与查询实战案例项目一:产品相关数据库设计与创建一、数据库及表结构设计二、数据库与表的创建项目二:员