Opengl 通过MSAA订购独立的透明度

Opengl 通过MSAA订购独立的透明度,opengl,glsl,Opengl,Glsl,我已经在“OpenGL编程指南”第8版(红皮书)的演示基础上实现了OIT。现在我需要添加MSAA。只需启用MSAA会增加透明度,因为分层像素的分辨率是采样级别数的x倍。我读过一篇关于如何使用DirectX的文章,他们说像素着色器应该按采样而不是按像素运行。如何在OpenGL中运行 在这里,我不会给出整个实现,但会给出最终分辨率为分层像素的片段着色器块: vec4 final_color = vec4(0,0,0,0); for (i = 0; i < fragment_count; i++

我已经在“OpenGL编程指南”第8版(红皮书)的演示基础上实现了OIT。现在我需要添加MSAA。只需启用MSAA会增加透明度,因为分层像素的分辨率是采样级别数的x倍。我读过一篇关于如何使用DirectX的文章,他们说像素着色器应该按采样而不是按像素运行。如何在OpenGL中运行

在这里,我不会给出整个实现,但会给出最终分辨率为分层像素的片段着色器块:

vec4 final_color = vec4(0,0,0,0);
for (i = 0; i < fragment_count; i++)
{
    /// Retrieving the next fragment from the stack:
    vec4 modulator = unpackUnorm4x8(fragment_list[i].y) ;
    /// Perform alpha blending:
    final_color =   mix(final_color, modulator, modulator.a);
}

color = final_color ;
列表解析:

#version 420 core
// The per-pixel image containing the head pointers
layout (binding = 0, r32ui) uniform uimage2D head_pointer_image;
// Buffer containing linked lists of fragments
layout (binding = 1, rgba32ui) uniform uimageBuffer list_buffer;
// This is the output color
layout (location = 0) out vec4 color;
// This is the maximum number of overlapping fragments allowed
#define MAX_FRAGMENTS 40

// Temporary array used for sorting fragments
uvec4 fragment_list[MAX_FRAGMENTS];

void main(void)
{
    uint current_index;
    uint fragment_count = 0;
    current_index = imageLoad(head_pointer_image, ivec2(gl_FragCoord).xy).x;

    while (current_index != 0 && fragment_count < MAX_FRAGMENTS )
    {   
        uvec4 fragment = imageLoad(list_buffer, int(current_index));
        int coverage = int(fragment.w);
        //if((coverage &(1 << gl_SampleID))!=0) {

            fragment_list[fragment_count] = fragment;
            current_index = fragment.x;

        //}

        fragment_count++;
    }

    uint i, j;

    if (fragment_count > 1)
    {
        for (i = 0; i < fragment_count - 1; i++)
        {
            for (j = i + 1; j < fragment_count; j++)
            {
                uvec4 fragment1 = fragment_list[i];
                uvec4 fragment2 = fragment_list[j];

                float depth1 = uintBitsToFloat(fragment1.z);
                float depth2 = uintBitsToFloat(fragment2.z);

                if (depth1 < depth2)
                {
                    fragment_list[i] = fragment2;
                    fragment_list[j] = fragment1;
                }
            }
        }
    }

    vec4 final_color = vec4(0,0,0,0);

    for (i = 0; i < fragment_count; i++)
    {  
        vec4 modulator = unpackUnorm4x8(fragment_list[i].y);
        final_color =  mix(final_color, modulator, modulator.a);      
    }

    color = final_color;
}
#版本420核心
//包含头部指针的每像素图像
布局(绑定=0,r32ui)统一的uimage2D头\指针\图像;
//包含片段链接列表的缓冲区
布局(binding=1,rgba32ui)统一uimageBuffer列表\u buffer;
//这是输出颜色
布局(位置=0)输出vec4颜色;
//这是允许的最大重叠片段数
#定义最大碎片数40
//用于对片段进行排序的临时数组
uvec4碎片列表[最大碎片];
真空总管(真空)
{
uint当前_指数;
单位碎片计数=0;
当前索引=图像加载(头指针图像,ivec2(gl\u FragCoord).xy);
while(当前索引!=0&&fragment\u count
OpenGL 4.3在7.1中说明了
gl\u SampleID
内置变量:

在片段着色器中静态使用此变量会导致对每个样本计算整个着色器

(ARB_sample_着色中已经存在这种情况,
gl_SamplePosition
或使用
sample
限定符声明的自定义变量也存在这种情况)


因此,它是非常自动的,因为您可能无论如何都需要SampleID。

在不知道代码实际如何工作的情况下,您可以使用与链接的DX11演示相同的方式来完成,因为OpenGL提供了所需的相同功能

因此,在第一个只存储所有渲染片段的着色器中,还存储每个片段的样本覆盖率掩码(当然还有颜色和深度)。这是作为片段着色器输入变量
int gl_SampleMaskIn[]
给出的,对于id为
32*i+j
的每个样本,
glSampleMaskIn的位
j
[i] 如果片段覆盖了该样本,则设置
(因为您可能不会使用>32xMSAA,您通常可以只使用
glSampleMaskIn[0]
,并且只需要将单个
int
存储为覆盖掩码)

然后为每个样本而不是每个片段运行最终的排序和渲染着色器。这是通过使用输入变量
int gl_SampleID
隐式实现的,该变量为我们提供当前样本的ID。那么我们在该着色器中做什么(除了非MSAA版本)如果当前样本实际包含在此片段中,则排序步骤仅通过向最终(待排序)片段列表添加片段来说明样本:

是什么样的(注意,从您的小片段和DX链接推断出的伪代码):

现在是

while(fragment.next != 0xFFFFFFFF)
{
    if(fragment.coverage & (1 << gl_SampleID))
        fragment_list[count++] = vec2(fragment.depth, fragment.color);
    fragment = fragments[fragment.next];
}

在不知道完整代码的情况下很难回答,但是你不能像链接的DX11演示中那样做吗?除了存储过程中每个片段的颜色和深度之外,只存储样本覆盖率,然后让最终的排序和渲染着色器为每个样本运行,而不是只为每个片段运行,只为每个片段添加样本然后让最终的排序和渲染着色器为每个样本运行,而不仅仅是为每个片段运行,只添加片段实际覆盖的样本这就是我不知道如何做的。我如何检查片段覆盖或未覆盖的样本?我猜,与DX演示的方法相同。GLSL也将覆盖掩码和样本ID作为片段着色器输入。注意:要手动启用每个样本着色,请使用
glEnable(GL_sample_着色)
。我确实启用了示例着色。但问题是,例如,如果我在像素列表中有2个片段,当我将MSAA设置为x2时,列表中包含4个片段,如在列表构建过程中,多采样会为每个片段插入多个片段。然后在解析过程中,每个片段的混合会不止一次,并且作为I的结果t透明度是错误的。@MichaelIV当然,您只在解析过程中使用示例着色,以前的列表生成过程通常只对每个片段运行一次,只记录覆盖范围掩码,如
gl\u SampleMaskIn
所示。请参阅链接的DX11演示和我的(非常类似)回答。但是构建过程是否也应该是mutlisample以获得gl_SampleMaskIn值?@MichaelIV否,
gl_SampleMaskIn
提供此片段所覆盖的所有样本(作为位掩码,即位i集->样本i覆盖)。请考虑在对每个样本执行此操作时的值,样本掩码将仅设置1个单位,因为单个
...
fragment.color = inColor;
fragment.depth = gl_FragCoord.z;
fragment.coverage = gl_SampleMaskIn[0];
...
while(fragment.next != 0xFFFFFFFF)
{
    fragment_list[count++] = vec2(fragment.depth, fragment.color);
    fragment = fragments[fragment.next];
}
while(fragment.next != 0xFFFFFFFF)
{
    if(fragment.coverage & (1 << gl_SampleID))
        fragment_list[count++] = vec2(fragment.depth, fragment.color);
    fragment = fragments[fragment.next];
}
while (current_index != 0 && fragment_count < MAX_FRAGMENTS )
{
    uvec4 fragment = imageLoad(list_buffer, int(current_index));
    uint coverage = fragment.w;
    if((coverage &(1 << gl_SampleID))!=0)
        fragment_list[fragment_count++] = fragment;
    current_index = fragment.x;
}