opengl窗口超过分辨率

opengl窗口超过分辨率,第1张

我有一个基于 OpenGL 的 gui。我使用超分辨率能够处理各种比例。不是放大图像,而是缩小图像(除非碰巧有人以 4000x4000+ 分辨率运行)。

问题是,OpenGL 似乎并不能顺利缩减。我有工件,好像缩放是最近的邻居。 (例如,文本边缘是块状的,即使它们不在原始文件中)

这些是我使用的设置:

glBindTexture(GL_TEXTURE_2D, tex)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)

这是一个工件样本,我相信比例是 2:1。由于窗口边缘等原因,可能并不准确。

您可以看到左边缘看起来很完美(虽然不是这样),但右边缘有奇怪的中断。原始图形完全对称,没有伪影。

我试过 GL_NEAREST、GL_LINEAR。没有 mipmapping 所以...

OpenGL 在缩放方面肯定不是那么差吗?我想要双三次缩放之类的东西或能产生良好结果的东西。

我使用的是 OpenGL 1.1。我可能会预先缩放图像,但每次窗口大小发生变化时我都必须这样做,并且 cpu 可能会很慢。首先高碰,您必须了解信号理论,即Nyquist Theorem(该***页面在谈论“时间”域中的信号时过于具体;该原理对于所有类型的离散采样信号(包括图像)都是通用的)。在进行下采样时,您始终必须应用lowpass anti aliasing filter,它会切断采样频率一半以上的所有频率分量,以避免产生混叠伪影。如果没有过滤,即使是线性积分下采样器也会产生伪影。实现纹理低通滤波器的实时图形方式是mipmaps。每个 mipmap 级别的截止频率恰好是下一个更高级别的频率的一半。

你现在有两个选择:

实现 mipmapping

实现下采样片段着色器

当然,明智的做法是首先不要以过高戚返谈的分辨率进行渲染,而是以完全目标分辨率来渲染你的 GUI。

【讨论】:

【解决方案2】:

根据你提供的代码,我会猜测可能是什么问题。

尝试加载您的图像或至少分配内存在您使用glParameteri 设置这些世好纹理参数之前。另外,将GL_TEXTURE_MIN_FILTER 设置各向异性过滤可以应用于不同的级别,此代码将应用到最大级别,如果您愿意,可以使用小于aniso 的数字我用OpenGL渲染出三维场景,然后通过glReadPixels()将三维场景保存为BMP格式的图片,发现保存图片的分辨率就是渲染窗口的分辨率,请问通过什么方法可以实现将渲染的场景保存为超过窗口分辨率的图片?例如:我的图形显示窗口为300*300,我想保存为1000*1000分辨率的图片如何实现,请大家给点思路,要是有相关的链接或代码也可以我可能问题描述的不清楚,我并不是想渲染得到纹理,只是想将渲染窗口的图像保存为BMP图片,遇到的问题是保存的图片只能和窗口大小一样,有没有办法得到保存图片的场景内容与窗口中的一样,只是得到的图片大小几倍于窗口么?例如:我渲染的窗口比较小,直观看的话图像并不清晰,保存为图片后由于图片较大就比较清晰了是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法线,顶点颜色数据等。

顶点着色器渲染时,可直接从VBO中取出顶点的各类属性数据,由于VBO在显存而不是在内存中,不需要从CPU传输数据,处理效率更高。所以可以理解为VBO就是显存中的一个存储区域,可以保持大量的顶点属性信息。并且可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取 *** 作。

顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER,允许同时绑定多个缓冲,只要它们是不同的缓冲类型

可使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上。

使用VBO画图

在这里插入图片描述

顶点数组对象 (Vertex Array Object,VAO)

是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。

VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起作为一个对象统一管理。一个着色器程序对象(shader program object) 就是多个着色器结合链接到一起的最终版本。激活的着色器程序对象将在调用渲染 *** 作时使用它会使用比正常分辨率更高的分辨率(即超采样)来渲染场景,当图像输出在帧缓冲中更新时,分辨率会被下采样(Downsample)至正常的分辨率。栅器会将一个图元的所有顶点作为输入,并将它转换为一系列的片段。顶点坐标理论上可以取任意值,但片段不行,因为它们受限于你窗口的分辨率。顶点坐标与片段之间几乎永远也不会有一对一的映射,所以光栅器必须以某种方式来决定每个顶点最终所在的片段/屏幕坐标由于屏幕像素总量的限制,有些边缘的像素能够被渲染出来,而有些则不会。结果就是我们使用了不光滑的边缘来渲染图元,导致之前讨论到的锯齿边缘。多重采样所做的正是将单一的采样点变为多个采样点(这也是它名称的由来)。我们不再使用像素中心的单一采样点,取而代之的是以特定图案排列的4个子采样点(Subsample)。我们将用这些子采样点来决定像素的遮盖度。当然,这也意味着颜色缓冲的大小会随着子采样点的增加而增加。在这里插入图片描述这里,每个像素包含4个子采样点(不相关的采样点都没有标注),蓝色的采样点被三角形所遮盖,而灰色的则没有。对于三角形的内部的像素,片段着色器只会运行一次,颜色输出会被存储到全部的4个子样本中。而在三角形的边缘,并不是所有的子采样点都被遮盖,所以片段着色器的结果将只会储存到部分的子样本中。根据被遮盖的子样本的数量,最终的像素颜色将由三角形的颜色与其它子样本中所储存的颜色来决定。

这是我第一次写博客,格式和内容难免存在很多纰漏,忘指正

下兆碰搭面我将从以下纪录我所学到的

1.创建和使用几何着色器

2.使用//几个着色器创建额外的几何图元

3.使用集合着色器与transform feedback 共同生成多组几何数据流

4.在一个单独的渲染流程中渲染到多个视口

一.创建和使用几何着色器

1.创建

    几何着色器的创建和其他的着色器是完全相同的

a).GLuint glCreateShader (GLenu mtype)  mtype传 GL_GEOMETRY_SHADER 来创建

b).void glCompileShader (GLuint shader) shader 为glCreateShader 返回的shader的id, 使用此函数来编译着色器程序

c).void glAttachShader (GLuint program,GLuin tshader)将shader 附着到program里面

几何着色器是Opengl的一个可选阶段,你的程序对象不一样非要包含这个阶段,它位于光栅化和片元着色器之前。当不需要几何着色器的时候,我们可以通过GLEnable 传入GL_RASTERIZER_DISCARD来关闭光栅化阶段,并且通过transform feedback 来获取顶点数据

2.输入和输出

几何着色器的输入来自于顶点着色器或如果开启了细分着色器则来自于细分着色器,几何着色器对于每个输入的图元,输入的数据以数组的形式出现,每一项是一个接口块的形式,隐式的定义为gl_in

in gl_Pervertex {

vec4 gl_Position     

float gl_PointSize

float fl_ClipDistance[]

}

数组的长度由输入的图元类型决定并且由.length()方法获取。

支持的图元类型包括:

类型                            数组大小

points                         1

lines                            2

triangles                      吵瞎  3

lines_adjacency            4

triangles_adjacency            6

这里比较特别的事lines_adjacency 和 triangles_anjacency 这两种邻接图元类型,它们不能作为几何着色器的输出,后面会讲到。

我们也可以自定义接口块的数据结构,定义的方式如下:

out VS_GS_INTERFACE

{

    out vec4 position

    out vec4 normal

    out vec4 color

    out vec2 tex_coord[4]

}vs_out

并且在几何着色器中作如下声明

in VS_GS_INTERFACE 

{

  out vec4 position

    out vec4 normal

    out vec4 color

    out vec2 tex_coord[4]

}

接口块的匹配是通过块名称(这里是VS_GS_INTERFACE)来实现的。

特殊的输入:

    除了内置的gl_in[] 成员和用户自定义的输入之外,几何着色器还有gl_PrimitiveIDin和gl_InvocationID。

第一个等价于片元着色器中的gl_primitiveID,后缀用于区分是在几何着色器或者是片元着色器,若想偏远着色器的gl_primitiveID生效必须族拿指定gl_primitiveIDIn。

第二个输入gl_InvocationID用于实现几何着色器的实例化。这一块还不清楚,后面的博客会提到。

特殊的几何着色器图元lines_adjacency  和 triangles_adjacency 这两种图元分别是4个和6个顶点,并且支持邻接信息——也就是有关邻接图元或者边界的信息传入几个着色器中。带有邻接信息的线可以通过glDrawArrays()等绘制命令中传入GL_LINES_ADJACENCY 或者 GL_LINES_STRIP_ADJACENCY图元模式来设置,如果没有几何着色器,这些图元也可以使用,但是它们会被解析成普通的线段或者三角形儿多余的顶点信息将会被抛弃。

lines_adjacency 图元作为几何着色器的输入,表示一个4顶点的图元形式,包含两种子类型

GL_LINES_ADJACENCY    

        1)    a ...>b--->c...>d        2) e...>f--->g...>h

    图元装配的时候每次总是4个顶点的数量,如上所示,第一次是a,b,c,d  实际上真正绘制的点是b和c用 --->表示,其他的点是提供邻接关系的点。

GL_LINES_STRIP_ADJACENCY

        2)    a ...>b--->c--->d--->e--->f--->g...>h

    这种类型第一次取a,b,c,d,下一次取b,c,d,e...依此类推

triangles_adjacency 作为图元输入时,每个图元由6个顶点组成,opengl 可以通过绘制命令传入GL_TRIANGLES_ADJACENCY和GL_TRIANGLES_STRIP_ADJACENCY来控制,为了说明怎么工作的盗两张图

GL_TRIANGLES_ADJACENCY图元类型第一个点由a-f6个点构成,第二个从g-l ,图中黄色三角形的三个顶点将保留,其余的二GL_LINES_ADJACENCY的类似也是邻接信息的点,输出的时候将被丢弃

GL_TRIANGLES_STRIP_ADJACENCY 图元类型理解费劲。

第一个图元由0-5个6个顶点构成,三角形顶点为0,2,4附加的信息是1,3,5

下一个图元通过后记的1个顶点加上之前的顶点构成,顶点为4,2,6,附加信息为0,5,8。

可以发现,第一个,奇数,偶数,和最后一个画的线是有相同规律的,通过划线很容易就知道那三个顶点是需要输出的,那几个提供邻接信息。

几何着色器的输出

几何着色器的输出将送入图元装配引擎,光栅化器,进而进入片元着色器,没有几何着色器输出则和顶点着色器相同,几何着色器的输出也是逐顶点输出的接口块定义。隐式定义如下:

out gl_PerVertext 

{

    vec4 gl_Position

    float gl_PositionSIze

    float gl_ClipDistance[]

}

用户可以自定义输出接口块的结构,并且它们会跟内置的接口块成员一块传递到片元着色器。因为每个几个着色器的请求都可以创建多个输出顶点,所以我们必须现实地通过EmitVertex() 函数来产生顶点,调用EmitVertex()之后多有的当前值都会被记录下来,就是这个当前数组的中的当前顶点。当调用完EmitVertex()之后,我们必须写出信息,哪怕输出和输入完全一致。

唯一例外的是flat关键字,此时唯有用于provoking vertex的顶点才会后继阶段,我们可以调用glProvokingVertex()并且设置所需的模式,默认的模式是GL_LAST_VERTEX_CONVENTION,即每个图元的最后一个顶点用作扁平的着色的插值。当然provoking vertex 不仅依赖于glProvokingVertex 也依赖于具体的图元类型。

我的理解:当在片元着色器需要插值的时候,GL_LAST_VERTEX_CONVENTION表示最后一个顶点的颜色用于多边形

除了内置和用户自定义的顶点输出之外,几何着色器还有三个特殊的内置变量类型,它们是gl_PrimitiveID、gl_Layer、gl_Viewportindex

gl_PrimitiveID用于片元着色器判断片元属于哪个图元,后面两个后面提到

3.产生图元

几何着色器的图元通过两个特殊的内置函数生成的,即EmitVertex()和EndPrimitive() ,每个着色器请求都必须调用EmitVertex(),以及必须必要的时候使用EndPrimitive()来产生图元,如果没有调用这些函数,那么就不会输出几何体,也就是剪裁的意思。如果多次调用那么就产生比输入更多的数据

1)、剪裁

    如上所说不调用EmitVertex和EndPrimitive就可以达到剪裁的目的,可以根据条件剪裁

2)、几何体的扩充

    产生的图元比输入的图元多叫做扩充,可以实现诸如毛发或者适度的细分等算法(当然最好使用固定的戏份硬件来实现细分的要求)

如果想要将两个SurfaceTexture的内容绘制到一个画布上,可以通过以下步骤实现:

1. 创建两个SurfaceTexture对象,并设置对应的纹理ID和监听器。

2. 实现两个SurfaceTexture的监听器,获取其接收到的视频帧。

3. 创建一个OpenGL ES上下文,创建两个纹理和FBO。

4. 将两个纹理对象绑定到FBO上,并将FBO绑定到OpenGL ES上下文中。

5. 在OpenGL ES上下文中旦和胡创建一个着色器程序,并设置顶点数据和着色器代码。

6. 在渲染过程中,分别将两个纹理的内容绑定到对应的着色器程序上,然后绘模拦制出它们的内容。

7. 最后,解绑FBO,将纹理内容绘制到画布上。

以上是将两个SurfaceTexture的内容绘制到画布上的一棚烂般步骤,具体实现还需要根据具体情况进行修改。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/8237789.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存