12.4 OpenGL顶点后处理:图元裁剪

2024-02-11 23:52

本文主要是介绍12.4 OpenGL顶点后处理:图元裁剪,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

图元裁剪 Primitive Clipping

Primitive Clipping(图元裁剪)是图形渲染管线中的一个重要步骤,发生在顶点处理之后、光栅化之前。这个阶段主要目的是去除位于视体(View Volume)之外或者被用户自定义裁剪平面(Clip Planes)裁剪掉的图元(如点、线段和三角形),以减少不必要的渲染计算。

在OpenGL中,原始图元裁剪过程首先会根据视口坐标系(Viewport)、近裁剪面(Near Clip Plane)、远裁剪面(Far Clip Plane)以及可能存在的额外用户定义裁剪平面来确定有效视体。接着,对每个传入的图元进行裁剪操作:

  1. 如果整个图元都在视体内,则保留该图元。
  2. 如果部分图元在视体内,则通过线性插值算法生成新的顶点,并根据这些顶点重新构造出一个位于视体内的新图元。
  3. 如果整个图元都在视体外或被用户定义裁剪平面裁剪,则丢弃该图元。

此外,可以通过查询对象追踪经过原始图元裁剪阶段处理的图元数量(CLIPPING_INPUT_PRIMITIVES)以及成功通过裁剪并进一步由光栅化阶段处理的图元数量(CLIPPING_OUTPUT_PRIMITIVES)。同时,启用RASTERIZER_DISCARD状态时,实现可能会直接在裁剪阶段后丢弃图元,这可能导致裁剪输入和输出计数器不增加。

控制裁剪空间坐标的原点和深度范围

void glClipControl( enum origin, enum depth );

允许开发者控制裁剪空间坐标的原点和深度范围。这对于精确的投影和深度测试至关重要,尤其是在需要与某些渲染API进行兼容性调整时。

  • origin 参数指定裁剪空间坐标系的原点位置:

    • GL_LOWER_LEFT: 原点位于左下角,这是默认值,符合传统OpenGL坐标系统。
    • GL_UPPER_LEFT: 原点位于左上角,这更符合Direct3D等其他API的习惯。
  • depth 参数定义裁剪空间深度范围:

    • GL_NEGATIVE_ONE_TO_ONE: 深度范围从-1到1,这是OpenGL的传统深度缓冲范围。
    • GL_ZERO_TO_ONE: 深度范围从0到1,这与某些其他图形API如Vulkan和Direct3D中的深度范围一致。

通过调用这个函数,开发者可以根据自己的需求来匹配不同API的深度缓冲区设置,以及根据不同的坐标系统原点来确保跨平台应用的一致性。

裁剪和剔除过程

几何体(primitives)在渲染过程中需要经过裁剪和剔除阶段以确保只有位于视口可见区域内的部分被绘制。以下是该过程的详细说明:

  1. Culling Against Cull Volume

    • 用户可以通过gl_CullDistance数组定义多个自定义剔除半空间,并且系统允许的最大数量由MAX_CULL_DISTANCES决定。
    • 在顶点着色器阶段结束后,每个几何体根据其顶点对应的cull距离与用户定义的cull半空间进行比较。如果一个几何体的所有顶点相对于任何启用的cull半空间的距离均为负值,则该几何体会被剔除,不会进入后续的渲染流程。
  2. Clipping to Clip Volume

    • 视口视锥体(view volume)是按照特定坐标范围定义的(例如:-wc ≤ xc ≤ wc, -wc ≤ yc ≤ wc, zmin ≤ zc ≤ wc),其中zmin取决于深度裁剪模式(NEGATIVE_ONE_TO_ONE或ZERO_TO_ONE)。
    • 除了视口视锥体之外,还可以结合多达MAX_CLIP_DISTANCES个客户端定义的裁剪半空间来形成最终的裁剪体积(clip volume)。如果没有启用自定义裁剪半空间,那么裁剪体积就是视口视锥体本身。
    • 最后一个顶点处理阶段通过gl_ClipDistance[]数组为每个启用的裁剪半空间写入相应的裁剪距离。当顶点P满足ci§ ≥ 0时,它位于裁剪半空间i内,对于点、线段和三角形,裁剪距离会进行适当的插值计算。
  3. Clipping Process for Different Primitives

    • 对于不同类型的几何体,裁剪过程有不同的处理方式:
      • 点:若点位于近裁剪平面和远裁剪平面之间及所有启用的半空间内,则保留;否则可能被丢弃。此外,实现也可以选择丢弃超出视口视锥体的点。
      • 线段:完全位于裁剪体积内的线段不做处理;完全位于体积外则丢弃;部分位于内外则会被裁剪,并根据裁剪算法计算新的顶点坐标。
      • 多边形:多边形需保证所有边缘都在裁剪体积内才能被完整保留;否则将进行裁剪操作。裁剪后的多边形可能会导致边缘被裁剪,为了保持多边形连接性,会在裁剪边界上添加新的边缘,这可能导致引入新顶点。
  4. Depth Clamping

    • 深度钳制功能通过调用Enable或Disable并指定DEPTH_CLAMP目标来开启或关闭。如果开启深度钳制,系统将在裁剪阶段忽略视锥体关于深度坐标的限制(即不再有明确的近/远裁剪平面)。
  5. Complementarity Criterion and Initial State

    • 使用用户定义半空间裁剪的几何体必须满足互补准则,即无论何时更改裁剪距离符号,都不能导致像素丢失或重复绘制。
    • 初始状态下,裁剪控制原点设为LOWER_LEFT,深度模式默认为NEGATIVE_ONE_TO_ONE,所有用户定义的半空间均未启用。
  6. Implementation Considerations

    • 实现可以灵活地处理输入几何体,即使在某些情况下不改变几何体或者因为实现依赖的原因将一个输入几何体输出为多个裁剪后的几何体,只要保证最终渲染结果不变即可。

裁剪着色器输出 Clipping Shader Outputs

在图形渲染管线中,顶点着色器输出值的裁剪阶段紧随顶点处理阶段之后。对于位于裁剪体积内的顶点,其关联的输出值不受裁剪影响。

然而,如果一个图元(如三角形、线段等)被裁剪了,那么由裁剪产生的新顶点所对应的输出值会受到裁剪的影响。例如:

假设未裁剪边P1和P2上的两个顶点分别具有输出值c1和c2。对于被裁剪点P,我们可以通过计算出的t值,按照以下方式获取与点P相关的输出值c:

c = t c1 + (1 − t) c2

这里的乘法操作意味着每个输出分量x、y、z和w都会与标量t进行相应的乘法运算。

当进行多边形裁剪时,可能会在线框与裁剪体积边界相交的地方创建新的裁剪顶点。这种情况通过观察到多边形裁剪是沿着单个半空间逐一进行的来处理。同样地,输出值的裁剪也按此方式进行,确保裁剪点总是出现在已裁剪或未裁剪的多边形边缘与裁剪体积边界的交点上。

对于最后一级顶点着色器指定不采用透视校正插值(使用noperspective限定符)的输出值,在计算与点P相关联的输出值时,所使用的t值会被调整以保证结果在屏幕空间内呈线性变化。

另外,实现无需支持整型或无符号整型类型的输出值插值,因为所有这类属性必须采用平面着色技术,即同一图元的所有片段共享同一个顶点属性值,而不是在片段间进行插值计算。

图元裁剪查询 Primitive Clipping Queries

,以及。

调用 glBeginQuery,并设置目标如下值时:

  1. CLIPPING_INPUT_PRIMITIVES 查询
    跟踪经过原始图元裁剪阶段处理的图元数量。

  2. CLIPPING_OUTPUT_PRIMITIVES 查询
    通过原始图元裁剪阶段并进一步由光栅化阶段处理的图元数量。对于特定输入图元,实际通过裁剪阶段输出的图元数量依赖于具体实现,但必须满足以下条件:

    • 如果输入图元至少有一个顶点位于裁剪体积内,则计数器至少增加1。
    • 否则,计数器可能增加0或更多。
  3. RASTERIZER_DISCARD 状态的影响
    当启用 GL_RASTERIZER_DISCARD 标志时,实施允许在可选的变换反馈状态之后立即丢弃图元(参见第14.1节)。因此,如果启用了 RASTERIZER_DISCARD,裁剪输入和输出图元的计数器可能不会递增。这意味着在这种情况下,即使图元通过了裁剪阶段,也可能因为光栅化阶段被忽略而不计入相关计数器中。

这篇关于12.4 OpenGL顶点后处理:图元裁剪的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

使用AGG里面的clip_box函数裁剪画布, 绘制裁剪后的图形

// 矩形裁剪图片, 透明void agg_testImageClipbox_rgba32(unsigned char* buffer, unsigned int width, unsigned int height){// ========= 创建渲染缓冲区 =========agg::rendering_buffer rbuf;// BMP是上下倒置的,为了和GDI习惯相同,最后一个参数是

OpenGL-ES 学习(6)---- 立方体绘制

目录 立方体绘制基本原理立方体的顶点坐标和绘制顺序立方体颜色和着色器实现效果和参考代码 立方体绘制基本原理 一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形 顶点的坐标体系如下图所示,三维坐标的中心原点位于立方体的中心,但是要特别注意的是,前后方向表示的是Z轴,上下方向表示的是Y轴 立方体的顶点坐标和绘制顺序 立方体坐标定义

OpenGL:中点直线算法

理论部分 中点直线算法是通过在像素中确定与理想直线最靠近的像素来进行扫描转换的。 在上图中,假设直线的斜率 0 ≤ m ≤ 1 0\le m \le 1 0≤m≤1。假设当前最近的像素已经确认为 P ( x k , y k ) P(x_k, y_k) P(xk​,yk​),由于 x x x位最大的位移方向,因此直线在 x x x方向上每次增加一个像素单位,而在 y y y方向上是否

【PyTorch】【机器学习】图片张量、通道分解合成和裁剪

一、导入所需库 from PIL import Imageimport torchimport numpy as npimport matplotlib.pyplot as plt 二、读取图片 pic = np.array(Image.open('venice-boat.jpg')) 上述代码解释:先用Image.open()方法读取jpg格式图片,再用np.array()方法

OpenGL学习笔记(二十九)

目录 模板测试 模板测试 当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer)。

OpenGL学习笔记(二十八)

目录 面剔除 面剔除 一个3D立方体,从任何一个方向去看它,最多可以同时看到的面是3个。可以从一个立方体的任意位置和方向上去看它,但是永远不能看到多于3个面。所以为何还要去绘制那三个不会显示出来的3个面呢。如果可以以某种方式丢弃它们,会提高片段着色器超过50%的性能,这就是面剔除要做的事情。

OpenGL学习笔记(二十七)

目录 混合 混合 在OpenGL中,物体透明技术通常被叫做混合(Blending)。透明是物体(或物体的一部分)非纯色而是混合色,这种颜色来自于不同浓度的自身颜色和它后面的物体颜色。一个有色玻璃窗就是一种透明物体,玻璃有自身的颜色,但是最终的颜色包含了所有玻璃后面的颜色。这也正是混合这名称的出处,因为我们将多种(来自于不同物体)颜色混合为一个颜色,透明使得我们可以看穿物体。

OpenGL学习笔记(二十六)

目录 模板测试 模板测试 当片段着色器处理完片段之后,模板测试(Stencil Test) 就开始执行了,和深度测试一样,它能丢弃一些片段。仍然保留下来的片段进入深度测试阶段,深度测试可能丢弃更多。模板测试基于另一个缓冲,这个缓冲叫做模板缓冲(Stencil Buffer),我们被允许在渲染时更新它来获取有意思的效果。 模板缓冲中的模板值(Stencil Value)通常是

OpenGL学习笔记(二十五)

目录 EarlyZ EarlyZ 现在大多数 GPU 都支持一种称为提前深度测试(Early depth testing)的硬件功能。 提前深度测试允许深度测试在片段着色器之前运行。明确一个片段永远不会可见的 (它是其它物体的后面) 。 片段着色器通常是相当费时的所以应该尽量避免运行。 对片段着色器提前深度测试一个限制是,你不应该写入片段的深度值。如果片段着色器将写入其

OpenGL学习笔记(二十三)

目录 颜色 颜色 现实世界中有无数种颜色,每一个物体都有它们自己的颜色。我们要做的工作是使用(有限的)数字来模拟真实世界中(无限)的颜色,因此并不是所有的现实世界中的颜色都可以用数字来表示。然而我们依然可以用数字来代表许多种颜色,并且你甚至可能根本感觉不到他们与真实颜色之间的差异。颜色可以数字化的由红色(Red)、绿色(Green)和蓝色(Blue)三个分量组成,它们通常被缩