如何使用多采样帧缓冲区在 OpenGL 中选择几何体?

How pick geometries in OpenGL with multisample framebuffer?

(编辑) 我使用帧缓冲区进行了工作几何拾取。我的目标是在一次绘制调用中绘制巨大的场景,但我需要绘制到 multisample 颜色纹理附件 (GL_COLOR_ATTACHMENT0) 并绘制到(已编辑)non-multisample拾取纹理附件 (GL_COLOR_ATTACHMENT1)。问题是如果我使用多重采样纹理来拾取,拾取会因为多重采样而损坏。

我像这样将几何 ID 写入片段着色器:

//...

// Given geometry id
uniform int in_object_id;

// Drawed to screen (GL_COLOR_ATTACHMENT0)
out vec4 out_frag_color0;

// Drawed to pick texture (GL_COLOR_ATTACHMENT1)
out vec4 out_frag_color1;

// ...

void main() {

    out_frag_color0 = ...; // Calculating lighting and other stuff

    //...

    const int max_byte1 = 256;
    const int max_byte2 = 65536;
    const float fmax_byte = 255.0;

    int a1 = in_object_id % max_byte1;
    int a2 = (in_object_id / max_byte1) % max_byte1;
    int a3 = (in_object_id / max_byte2) % max_byte1;

    //out_frag_color0 = vec4(a3 / fmax_byte, a2 / fmax_byte, a1 / fmax_byte, 1);
    out_frag_color1 = vec4(a3 / fmax_byte, a2 / fmax_byte, a1 / fmax_byte, 1);
}

(该代码的要点是使用 RGB space 存储几何 ID,然后回读用于更改立方体颜色)

当我将光标向左移动一个像素时会发生这种情况:

由于立方体像素的 alpha 值:

没有多重采样效果很好。但是多重采样使我的输出颜色相乘,然后几何体 ID 被破坏,因此它选择具有相乘值的随机立方体。

(编辑) 我无法将一个多重采样纹理目标附加到颜色 0 并将非多重采样纹理目标附加到颜色 1,这是不支持的。我怎样才能在一次绘制调用中做到这一点?

多重采样不是我的朋友我不确定我是否理解得很好(整个帧缓冲)。无论如何,这种选择几何图形的方式对我来说看起来很糟糕(我的意思是计算颜色的 ID)。我做得好吗?如何解决多样本问题?有没有更好的办法?

PS: 对不起,英语不好。 :)

谢谢。

您不能在单个绘制调用中进行多重采样和非多重采样渲染。

正如您已经发现的那样,不支持在 FBO 中使用两个颜色目标,其中只有一个被多重采样。来自规范中的 "Framebuffer Completeness" 部分:

The value of RENDERBUFFER_SAMPLES is the same for all attached renderbuffers; the value of TEXTURE_SAMPLES is the same for all attached textures; and, if the attached images are a mix of renderbuffers and textures, the value of RENDERBUFFER_SAMPLES matches the value of TEXTURE_SAMPLES.

您也不能同时渲染到多个帧缓冲区。始终只有一个当前帧缓冲区。

我能想到的唯一合理的选择是在单独的通道中进行采摘。然后您可以轻松地将 framebuffer/attachment 切换到非多重采样渲染缓冲区,并避免所有这些问题。

无论如何,使用单独的通行证进行采摘对我来说似乎更干净。这还允许您为每种情况使用专门的着色​​器,而不是总是产生两个输出,即使其中一个大部分未被使用。

我认为这是可能的... 您必须将拾取纹理设置为多重采样,在渲染场景后,您可以在屏幕上渲染 2 个三角形,在另一个片段着色器中您可以读出每个样本...为此,您必须使用 GLSL 命令:

texelFetch(sampler, pixelposition/*[0-texturesize]*/, /*important*/layernumber);

然后可以渲染成单采样纹理,通过glReadPixel读取颜色。

还没有测试过,但我认为它有效