3

「OpenGL プログラミング ガイド」第 8 版 (赤い本) のデモに基づいて OIT を実装しました。次に、MSAA を追加する必要があります。MSAA を有効にするだけで、レイヤー化されたピクセルが x 回解決されるため、透明度が台無しになります。サンプル レベル。DirectX を使用してピクセル シェーダーをピクセルごとではなくサンプルごとに実行する方法についての記事を読みました。

ここでは実装全体を公開するのではなく、レイヤー化されたピクセルの最終的な解像度が発生するフラグメント シェーダー チャンクを公開します。

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
layout (early_fragment_tests) in;
layout (binding = 0, r32ui) uniform uimage2D head_pointer_image;
layout (binding = 1, rgba32ui) uniform writeonly uimageBuffer list_buffer;
layout (binding = 0, offset = 0) uniform atomic_uint list_counter;
layout (location = 0) out vec4 color;//dummy output

in vec3 frag_position;
in vec3 frag_normal;
in vec4 surface_color;
in int gl_SampleMaskIn[];
uniform vec3 light_position = vec3(40.0, 20.0, 100.0);

void main(void)
{
    uint index;
    uint old_head;
    uvec4 item;
    vec4 frag_color;
    index = atomicCounterIncrement(list_counter);
    old_head = imageAtomicExchange(head_pointer_image, ivec2(gl_FragCoord.xy), uint(index));

    vec4 modulator =surface_color;
    item.x = old_head;
    item.y = packUnorm4x8(modulator);
    item.z = floatBitsToUint(gl_FragCoord.z);
    item.w = int(gl_SampleMaskIn[0]);
    imageStore(list_buffer, int(index), item);
    frag_color = modulator;
    color = frag_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;
}
4

2 に答える 2

3

OpenGL は必要な機能と同じ機能を提供するため、コードが実際にどのように機能するかを知らなくても、リンクされた DX11 デモとほとんど同じ方法で実行できます。

したがって、レンダリングされたすべてのフラグメントのみを格納する最初のシェーダーには、各フラグメントのサンプル カバレッジ マスクも格納します (もちろん、色と深度も一緒に)。これはフラグメント シェーダーの入力変数として指定されint gl_SampleMaskIn[]、 id を持つ各サンプルに対して、フラグメントがそのサンプルをカバーする場合32*i+j、ビットjglSampleMaskIn[i]設定されます (おそらく >32xMSAA を使用しないため、通常は単に使用できglSampleMaskIn[0]、単一intのカバレッジとして保存するだけで済みます)マスク)。

...
fragment.color = inColor;
fragment.depth = gl_FragCoord.z;
fragment.coverage = gl_SampleMaskIn[0];
...

次に、最終的な並べ替えおよびレンダリング シェーダーが、フラグメントごとではなく、サンプルごとに実行されます。int gl_SampleIDこれは、現在のサンプルの ID を提供する入力変数 を使用することによって暗黙的に実現されます。したがって、このシェーダーで (非 MSAA バージョンに加えて) 行うことは、現在のサンプルが実際にカバーされている場合にのみ、最終的な (並べ替えられる) フラグメント リストにフラグメントを追加することによって、並べ替えステップがサンプルを考慮に入れることです。このフラグメントによって:

どのようなものでしたか(注意してください、あなたの小さなスニペットとDXリンクから推定された疑似コード):

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];
}

または、それらの線に沿った何か。

編集:サンプルがカバーされていない場合、フラグメントをリストに追加したくないため、更新されたコードではfragment_count、ブロック内のみをインクリメントする必要があります。if(covered)常に増分すると、MSAA (したがってカバレッジ) が作用する領域である端にアーティファクトが表示される可能性があります。

一方、current_index = fragment.xサンプルがカバーされている場合だけでなく、各ループ反復でリストポインターを転送する必要があります()。そうしないと、あなたの場合のように無限ループになる可能性があります。したがって、コードは次のようになります。

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;
}
于 2013-06-05T09:46:12.237 に答える
1

OpenGL 4.3 Specgl_SampleIDは、組み込み変数について 7.1 で次のように述べています。

フラグメント シェーダーでこの変数を静的に使用すると、シェーダー全体がサンプルごとに評価されます。

(これは、ARB_sample_shading で既に当てはまり、修飾子gl_SamplePositionで宣言された または カスタム変数の場合でも当てはまります)sample

したがって、SampleID が必要になる可能性が高いため、非常に自動化されています。

于 2013-06-05T08:54:51.093 に答える