当前位置:   article > 正文

OpenGL3.3 颜色像素和片元

片元

目录

颜色

每个红色,绿色,蓝色分量占用8位 因此一个像素深度位24位(二进制)的颜色缓存
总共可以显示共224种独立颜色

片元

每个片元包含与像素位置对应的坐标数据,颜色和深度的存储值
也就是一个点和他的相关信息
片元在通过了一系列测试之后就可以在帧缓冲中修改像素的值
片元本质不是像素,它是潜在的像素。光栅化将几何图元(例如三角形)分解,覆盖到每个像素,像素大小的片段。片段具有关联的像素位置,深度值,纹理坐标,以及其他值。当片段通过光栅化测试后,它才是缓冲区的像素

图元

几何顶点被组合为图元(点,线,面) 图元被合成片元
光栅化将裁剪好的图元变为片元
就如下图中 点 线 线围成的面就是图元 而图元经过了下面的光栅化 深色的格子组成的就是片元

光栅化

光栅化是将一个图元转变为一个二维图象的过程
光栅化的目的:是找出一个几何单元(比如三角形)所覆盖的像素在这里插入图片描述
光栅化会根据三角形顶点的位置,来确定需要多少个像素点才能构成这个三角形,以及每个像素点都应该得到哪些信息
总结:光栅化,就是将几何信息转换成一个个的栅格组成的图像的过程。
opengl在光栅化的时候采用的一般是半空间算法 主要是适用于并行实现 所谓半空间算法 简单点说 就是在判断一个像素是否在这个三角形里面的时候 三角形有三条边 对每条边进行一次判定
请添加图片描述
就是类似于这样 每条边都做一次 方便SIMD就是同一个计算式子 对多个点进行判定
如果没有进行early-z(在光栅化之后 片元着色器之前) 那么这个阶段会对每一个图元都进行 然后执行一次就会产生该图元生成的片元 和片元信息 就是类似于我会对每一个图形都画一次画 这些信息会进入片元着色器
请添加图片描述
比如我们窗口里有这些图元 那么如果我们先绘制长方形 再绘制三角形 那么就会先对长方形进行光栅化
请添加图片描述
就会发现两个像素被覆盖了 那么就会将这两个像素以及这些像素被插值后的信息传递给片段着色器 片段着色器就会对这两个像素进行计算 然后发送到帧缓冲的颜色缓冲 深度缓冲中 然后再用同样的方式对三角形进行计算 然后会获得相应的像素 再发送到帧缓冲 先进行深度测试 如果通过了就写入颜色缓冲中

像素

像素是图像元素的缩写
一个像素可能关联多个颜色缓存
片元比像素多了许多信息
在光栅化中纹理映射之后图元信息转化为了像素

颜色缓存

"主"颜色缓存是与屏幕上的窗口相关联的 绘制在其中的图像都会直接显示到屏幕上 其他颜色缓存都是与屏幕无关的

输入到片元着色器的颜色并不是直接来自于之前的着色阶段(顶点着色器)而是来自光栅化的结果(但是光栅化好像在片元着色器之后啊)

双重缓冲技术

将主颜色缓存划分位两个部分:
1.直接在窗口中显示的前置缓存
2.用来渲染新图像的后备缓存
注意:只有默认帧缓存中的主颜色缓存可以使用双重缓冲的特性
还有什么立体图像可以了解一下

片元进入到帧缓存之前所需要经过的完整测试过程如下

剪切测试(scissor test)

将程序窗口中的一个矩形区域乘坐一个剪切盒 所有的绘制操作都限制在这个区域

(设置剪切矩形的位置和大小)glScissor(GLint x,GLint y,GLsizei width.GLsizei height)

定义了矩形的左下角(x,y)高度heighr 宽度width
剪切可以通过glEnable()和glDisable()开启和禁止 参数GL_SCISSOR_TEST
默认条件下剪切矩形与窗口大小相等 并且剪切测试时关闭的

多重采样片元操作(独立做一篇将 网站上和书上都要重新看一遍 这里没写全 书123面)

GL_SAMPLE_ALPHA_TO_COVERAGE 使用片元的alpha值来计算最后的采样覆盖率 这一过程与具体的硬件实现无关
GL_SAMPLE_ALPHA_TO_ONE 将片元的alpha值设置为最大的alpha值 然后使用这个值来进行覆盖率的计算 如果GL_SAMPLE_ALPHA_TO_COVERAGE 也开启了 则系统将使用替代前的片元的alpha值 而不是替代之1.0
GL_SAMPLE_COVERAGE 将使用glSampleCoverage中设置的数值 与覆盖率计算的结果进行合并(”与“操作)由此生成的样本掩码也可以通过glSampleCoverage()函数的invert参数来进行反转

glSampleCoverage(GLfloat value,Glboolean invert)

设置多重采样覆盖率的参数 以正确解计算alpha值 如果开启了GL_SAMPLE_COVERAGE 或者GL_SAMPLE_ALPHA_TO_COVERAGE 则value是一个临时的采样覆盖值
invert是一个布尔变量
用于设置这个零食覆盖值是否需要进行位反转 然后再与片元覆盖率进行合并(“与”操作)

glSampleMaski(GLuint index,GLbitfield mask)

设置一个精确的位掩码来计算和表达覆盖率 而不是通过OpenGL来生成这个位掩码
设置一个32位的采样掩码mask

模板测试(有独立博客)

可以实现:

点画

也就是类似于 你先画出你想要画的那个图案 把他放进模板缓存中 就类似于那种蒙版的那种

加盖

就是如果我们有个视横切面 然后我们的物体又是封闭物体(但是内部是空的) 如果我们的所在位置会让视横切面切开物体 也就是可以看到物体的内部 这个时候我们就需要给这个切口加一个盖子
为了实现这个功能:
将模板缓存清除位0值 然后启用模板测试 设置比较函数为总是让片元通过测试 然后绘制图像 每次片元通过测试的时候 我们都要将模板未免中的数据进行反转

深度测试(有独立的博客)

模板测试

混溶(就是混合 也有独立博客 只不过还没看书)

混合

颜色缓存的逻辑操作

glEnable(GL_COLOR_LOGIC_OP)开启逻辑操作

glLogicOp(GLenum opcode)

逻辑操作主要作用于:输入的片元数据以及当前颜色缓存中的数据
对于给定的
输入片元
(源)和当前颜色缓存的像素(目标) 选择需要执行的逻辑操作 默认值是GL_COPY
目前我实验的结果是
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);这里的是颜色缓存的像素
从片元着色器传进去的就是 输入片元
s表示数据源 d表示目标源
在这里插入图片描述

流程:

先开启glEnable(GL_COLOR_LOGIC_OP)然后使用glLogicOp()就行

遮挡查询

通过遮挡查询可以判断一系列几何体的可见性 这一步是在逐片元的各种测试之后完成的
简单来说遮挡查询就是:在绘制一个复杂物体的时候 不先绘制这个物体的全部几何信息 而是先渲染他的一个包围体(就是一个他的大致形状)然后再计算通过了所有测试的片元的数量 如果OpenGL将这个简化几何体(包围体)渲染之后 没有得到任何片元或者采样值(也就是这个包围体的任何一个片元都没有通过测试)则这个复杂物体在这一帧就是不可见的 就可以不用绘制出来了
但是也有缺点 他需要暂时停止几何体和片元的处理 先计算深度缓存中收到影响的样本数目

遮挡查询实现步骤

创建查询对象

每次遮挡查询都需要创建一个查询对象

glCreateQueries(GLenum target,GLsizei n,GLuint*ids)

创建n个新的查询对象 使用时对用的目标由target决定 新的查询对象的名称被放置在ids对应的数组当中 ids中保存的名称不一定是连续的整数数列

(判断某个标识符是否对应一个可用的遮挡查询对象)gllsQuery(GLuint id)

如果id是一个遮挡查询对象的名称 那么返回GL_TRUE 如果id为0或者非零值 但是不是遮挡查询对象的名称 返回GL_FALSE

遮挡查询初始化

想要指定哪些几何体要用到遮挡查询 就将绘制操作放置在glBeginQuery()和glEndQuery()之间

(启动遮挡查询)glBeginQuery(GLenum target,GLuint id)

target必须是:
GL_SAMPLES_PASSED
得到精确的片元数量 这些片元全部都通过了逐片元的测试 使用这个类型可能会降低OpenGL的性能
GL_ANY_SAMPLES_PASSED(也叫非遮挡查询)
得到一个近似的计数结果 他的主要作用是:
如果没有任何片元能够通过逐片元的测试那查询结果就是0 否则非零 这个非零值可能会不准确
GL_ANY_SAMPLES_PASSED_CONSERVATIVE
这是比上面哪个更宽松的结果 只有OpenGL绝对确信不会有任何片元通过测试 查询结果才会是0 但是即使实际上并没有片元通过测试 查询的结果也有可可能是一个非0值 但是他对性能的影响是最小的

id用于标识本次遮挡查询操作

(结束遮挡查询)

target必须是:
GL_SAMPLES_PASSED
GL_ANY_SAMPLES_PASSED
GL_ANY_SAMPLES_PASSED_CONSERVATIVE

判断查询结果

glGetQueryObjectiv(GLenum id,GLenum pname,GLint*params)
glGetQueryObjectuiv

id时遮挡查询物体的名称
如果pname是GL_QUERY_RESULT时 那么测试通过深度测试的片元或样本(如果开启了多重采样)的数量将被写入到params中
如果返回为0 那么表示这个物体已经被完全遮挡
如果pname为GL_QUERY_RESULT_AVAILABLE 并且查询id的结果已经可以读取 那么params中会写入GL_TRUE

count = 1000;
do
{
	glGetQueryObjectiv(Query,GL_QUERY_RESULT_AVAILABLE,&queryReady);//先判断是否被完全遮挡
}while(!queryReady&&count--)//如果发现没有被完全遮挡或者循环了1000次则退出循环
if(queryReady)//如果没有被完全遮挡
{
	glGetQueryObjectiv(Query,GL_QUERY_RESULT,&samples);//获取通过测试的片元数量
}
if(samples>0)//如果这个数量大于0 也就是没有被完全遮挡则绘制这个几何体
{
	glDrawArrays(GL_TRIANGLE_FAN, 0 ,NumVertices);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
glDeleteQueries(GLsizei n,const GLuint*ids)

删除n个遮挡查询对象 他们的名字为数组ids中的元素

条件渲染(没看 但是和遮挡查询有关)

像素设局的读取和拷贝

(将GPU像素数据读取到内存)glReadPixels(GLint x,GLint y, GLsizei width,GLsizei height,GLenum format,GLenum type,void*pixels)

前两个参数是 读取矩形区域范围的左下角(x,y)
尺寸为width河height
将数据数组保存到pixels
format用于指定要读取的像素数据元素的类型
type指定每个原色的数据类型
如果format设置为 GL_DEPTH但没有深度缓存那么会产生GL_INVALID_OPERATION错误
如果format为GL_DEPTH_STENCIL但type不是GL_UNSIGNED_INT_24_8或者GL_FLOAT_32_UNSIGNED_INT_24_8_REV 则产生GL_INVALID_ENUM
在这里插入图片描述
在这里插入图片描述
glReadBuffer()可以设置要读取像素的缓存名称
**注意:**glReadPixels实际上是从缓冲区中读取数据,如果使用了双缓冲区,则默认是从正在显示的缓冲(即前缓冲)中读取,而绘制工作是默认绘制到后缓冲区的。因此,如果需要读取已经绘制好的像素,往往需要先交换前后缓冲

glClampColor(GLenum target,GLenum clamp)(glReadPixels()读回数据的时候 可以自行设置这些数值是否需要使用glClampColor阶段到归一化的范围内)

如果targey设置为GL_CLAMP_READ_COLOR则开启截断
如果clamp为GL_TRUE 那么从缓存读取的颜色值将被截断到0-1之间 如果为GL_FALSE则不会
如果用户程序使用的是顶点数河浮点数混合的缓存类型 则设置clamp为GL_FIXED_ONLY的时候 只截断定点数据 浮点数保留

在这里插入图片描述

显存

显存也叫显示存储,帧缓存
他主要是存储显示芯片处理过(GPU)和即将被读取的数据 所以GPU渲染过的数据就被存储在显存里

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/574213
推荐阅读
相关标签
  

闽ICP备14008679号