在 OpenGL 3.2 中绘制全屏四边形的最佳方法是什么?

2024-03-28

我正在片段着色器中进行光线投射。我可以想出几种方法来为此目的绘制全屏四边形。要么在剪辑空间中绘制一个四边形,并将投影矩阵设置为单位矩阵,要么使用几何着色器将点变成三角形带。前者使用立即模式,在 OpenGL 3.2 中已弃用。我使用后者是出于新奇,但它仍然使用立即模式来画点。


我认为最有效的方法是绘制一个single“全屏”triangle。为了让三角形覆盖整个屏幕,它需要比实际视口大。在 NDC 中(还有剪辑空间,如果我们设置w=1),视口将始终是[-1,1]正方形。为了使三角形完全覆盖该区域,我们需要两条边的长度是视口矩形的两倍,以便第三条边将穿过视口的边缘,因此我们可以使用以下坐标(在逆时针顺序):(-1,-1), (3,-1), (-1,3).

我们也不需要担心文本坐标。为了得到通常的标准化[0,1]在整个可见视口的范围内,我们只需要使顶点的相应纹理坐标变大,并且重心插值对于任何视口像素都会产生与使用四边形时完全相同的结果。

这种方法当然可以与无属性渲染相结合,如德曼泽的回答 https://stackoverflow.com/a/51625078/2327517:

out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle
void main() {
        vec2 vertices[3]=vec2[3](vec2(-1,-1), vec2(3,-1), vec2(-1, 3));
        gl_Position = vec4(vertices[gl_VertexID],0,1);
        texcoords = 0.5 * gl_Position.xy + vec2(0.5);
}

为什么单个三角形会更有效?

This is not关于保存一个顶点着色器调用,以及在前端处理的少一个三角形。使用单个三角形最显着的效果是更少的片段着色器调用

一旦图元的单个像素落入 2x2 像素大小的块(“四边形”),真正的 GPU 总是会调用该块的片段着色器。这对于计算窗口空间导函数 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/dFdx.xhtml(纹理采样也隐含需要这些,请参见这个问题 https://stackoverflow.com/questions/52975878/what-is-in-simple-terms-texturegrad/52977548#52977548).

如果基元没有覆盖该块中的所有 4 个像素,则剩余的片段着色器调用将不会执行任何有用的工作(除了提供用于导数计算的数据之外),并且将被称为辅助调用(甚至可以通过gl_HelperInvocationGLSL功能 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_HelperInvocation.xhtml)。也可以看看Fabian“ryg”Giesen 的博客文章 https://fgiesen.wordpress.com/2011/07/10/a-trip-through-the-graphics-pipeline-2011-part-8/更多细节。

如果您渲染具有两个三角形的四边形,则两个三角形的一条边都会对角地穿过视口,并且在两个三角形上,您将在对角边生成大量无用的辅助调用。对于完美的正方形视口(纵横比 1),效果最差。如果您绘制单个三角形,则不会有这样的对角线边缘(它位于视口之外,根本不关心光栅化器),因此不会有额外的帮助器调用。

等一下,如果三角形延伸穿过视口边界,它不会被剪切并实际放置吗more在 GPU 上工作?

如果您阅读有关图形管道(甚至 GL 规范)的教科书材料,您可能会有这样的印象。但现实世界的 GPU 使用一些不同的方法,例如保护带削波。我不会在这里详细介绍(这将是一个单独的主题,请查看Fabian“ryg”Giesen 的精彩博客文章 https://fgiesen.wordpress.com/2011/07/05/a-trip-through-the-graphics-pipeline-2011-part-5/详细信息),但总体思路是,无论如何,光栅化器只会为视口(或剪刀矩形)内的像素生成片段,无论图元是否完全位于其中,因此我们可以简单地向其抛出更大的三角形,如果以下两项均属正确:

  • a) 三角形仅延伸 2D 顶部/底部/左/右剪裁平面(与 z 维度近/远剪裁平面相反,后者处理起来更棘手,特别是因为顶点也可能位于behind相机)

  • b) 实际的顶点坐标(以及光栅化器可能对其执行的所有中间计算结果)可以用 GPU 硬件光栅化器使用的内部数据格式表示。光栅化器将使用特定于实现的宽度的定点数据类型,而顶点坐标是 32 位单精度浮点数。 (这基本上就是定义保护带大小的)

我们的三角形只比视口大 3 倍,所以我们可以非常确定根本不需要裁剪它。

但是这值得吗?

嗯,片段着色器调用的节省是真实的(特别是当您有复杂的片段着色器时),但在现实场景中总体效果可能几乎无法衡量。另一方面,该方法并不比使用全屏四边形更复杂,并且使用数据较少,所以即使可能不会产生巨大的差异,也不会造成伤害,所以为什么not使用它?

这种方法是否可以用于各种轴对齐矩形,而不仅仅是全屏矩形?

理论上,您可以将其与剪刀测试结合起来绘制一些任意轴对齐的矩形(剪刀测试将非常有效,因为它只是限制首先生成哪些片段,这不是真正的“测试” “在丢弃片段的硬件中)。但是,这需要您更改要绘制的每个矩形的剪刀参数,这意味着大量的状态更改并限制您每次绘制调用只能使用单个矩形,因此在大多数情况下这样做并不是一个好主意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 OpenGL 3.2 中绘制全屏四边形的最佳方法是什么? 的相关文章

  • LibGDX纹理混合与OpenGL混合功能

    在 libGdx 中 我试图创建一个成形纹理 采用完全可见的矩形纹理并将其遮罩以获得成形纹理 如下所示 在这里我在矩形上测试它 但我想在任何形状上使用它 我调查过本教程 http www learnopengles com tag addi
  • GLSL 中统一浮点行为和常量浮点行为的不同

    我正在尝试在 GLSL 中实现模拟双精度 并且观察到一种奇怪的行为差异 导致 GLSL 中出现细微的浮点错误 考虑以下片段着色器 写入 4 浮点纹理以打印输出 layout location 0 out vec4 Output unifor
  • 使用 glGetFloatv 检索 pyglet 中的模型视图矩阵

    我正在使用 pyglet 在 python 中进行 3D 可视化 并且需要检索模型视图和投影矩阵来进行一些选择 我使用以下方式定义我的窗口 from pyglet gl import from pyglet window import wi
  • OpenGL:VAO 和 VBO 对于大型多边形渲染任务是否实用?

    如果您想渲染一次在视锥体中包含数千个多边形的大型景观 并且用户的视点不断变化 那么使用 VAO 或 VBO 是否实用 我的意思是 每次玩家的位置或摄像机旋转发生变化时 您都必须重新计算顶点数据 以便正确剔除不再可见的任何顶点或场景 以保持良
  • 为什么我的 CAOpenGLLayer 更新速度比之前的 NSOpenGLView 慢?

    我有一个在 Mac OS X 上渲染 OpenGL 内容的应用程序 最初它渲染到 NSOpenGLView 然后我将其更改为渲染到 CAOpenGLLayer 子类 当我这样做时 我看到了巨大的性能损失 帧速率减半 鼠标响应能力降低 卡顿
  • OpenGL什么时候完成函数中指针的处理?

    OpenGL有多项功能 http www opengl org wiki GLAPI glTexSubImage2D直接获取指针 他们中有一些从这些指针读取数据 http www opengl org wiki GLAPI glBuffer
  • GLSL聚光投影体积

    在我的开源项目中 我使用 Qt3D 设置了延迟渲染管道 到目前为止一切顺利 但现在我想通过添加聚光灯投影量来继续前进 例如场景中好像有烟雾 像这样 我正在使用的片段着色器位于问题的末尾 我读过 对于每个片段 我应该从光位置进行光线行进并找到
  • OpenGL - 自动生成 glDrawArrays 的索引/步幅参数

    我正在渲染一个包含大量数据点 gt 1M 的网格结构 我的数据结构如图所示 所以我的索引缓冲区的内容看起来像这样0 100 1 101 2 102 3 103 我对索引缓冲区的巨大尺寸有点恼火 我需要它来定义我的三角形带 是否有可能告诉 O
  • 纹理采样:根据LOD值计算BIAS值

    GL ES 2 0 中的功能纹理2DLod在片段着色器中不可用 我需要移植 GLSL 着色器 在 GL ES 2 0 中我只能使用二维纹理 sampler2D 采样器 vec2 坐标 浮点数bias 告诉我如何计算 a 的值bias相当于已
  • 渲染到一个颜色通道而不影响其他通道

    使用 OpenGL 任何版本 如何通过一次仅影响一个颜色通道来渲染到帧缓冲区对象 例如 我的帧缓冲区对象具有 GL BGRA 布局 现在我想执行一些渲染命令 这些命令应该只改变红色通道 因此 如果片段用颜色 204 0 0 0 渲染并且像素
  • 在着色器中旋转法线

    我有一个场景 其中有多个具有各自位置和旋转的模型 给定法线 着色器对每个像素应用简单的双向照明 那是我的顶点着色器 version 150 in vec3 position in vec3 normal in vec2 texcoord o
  • 进行亚像素平移时,2D 纹理会扭曲

    我想知道一个理论推理为什么这是可能的 几何体的平移与纹理映射有何关系 我只能在进行子像素平移时注意到这种效果 如果通过整个像素平移 纹理看起来很好 我正在使用正交投影 GL CLAMP TO EDGE GL NEAREST 片段着色器是hi
  • OpenGL 缓冲区、glFlush 和 glutSwapBuffers()

    使用之间有什么区别吗 glutInitDisplayMode GLUT SINGLE GLUT RGB with glFlush and glutInitDisplayMode GLUT DOUBLE GLUT RGB with glutS
  • 如何创建自己的 openGL 上下文并将其绑定到 GLCanvas?

    所以当我开始掌握java时 paint Graphics g 我继续创建自己的渲染方法 但我必须了解缓冲区策略以及如何 获取 图形 所以现在我在学习openGL 我必须掌握方法 Override public void display GL
  • nVidia 和 ATI 之间的 OpenGL 渲染差异

    最近 我将 ATI 驱动程序 我使用的是 HD7970 更新为最新版本 但我的 OpenGL 项目的一些对象停止工作 更重要的是 他们适用于 nVidia 最新驱动程序 在 960m 上测试 ATI 和 nVidia 渲染管道之间有什么我应
  • SDL 程序中颜色关闭

    我目前正在开发一个非常简单的游戏 使用纯 C 方法和 SDL 及其官方额外库 如 SDL image 和 OpenGL 现在 虽然我遇到了一些障碍 但我不知道为什么要这样做 绘制时颜色全部关闭 我目前在 Mac 上运行该程序 但如果我没记错
  • OpenGL 计算着色器调用

    我有一个与新计算着色器相关的问题 我目前正在研究粒子系统 我将所有粒子存储在着色器存储缓冲区中 以便在计算着色器中访问它们 然后我派遣一个一维工作组 define WORK GROUP SIZE 128 shaderManager gt u
  • sRGB 纹理。它是否正确?

    我最近阅读了一些有关 sRGB 格式以及它们如何允许硬件自动对典型显示器执行色彩校正的文章 作为我阅读的一部分 我发现您可以使用普通纹理和返回结果上的 pow 函数来模拟此步骤 无论如何 我想问两个问题 因为我以前从未使用过此功能 首先 有
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐