4

私は、OpenGL で滑らかなテクスチャ ベースのアウトライン効果を求めています。これまでのところ、ほとんどすべての種類のエッジ検出アルゴリズムを試しましたが、ほとんどが粗くてギザギザのアウトラインになりました。次に、ディスタンス フィールドについて読みました。私はかなり良い距離フィールドを行う例を見つけました。GLSL コードは次のとおりです。

#version 420
layout(binding=0)  uniform sampler2D colorMap;
flat in vec4 diffuseOut;
in vec2 uvsOut;
out vec4 outputColor;
const float ALPHA_THRESHOLD = 0.9;
const float NUM_SPOKES = 36.0; // Number of radiating lines to check in.
const float ANGULAR_STEP =360.0 / NUM_SPOKES;
const int ZERO_VALUE =128; // Color channel containing 0 => -128, 128 => 0, 255 => +127
int in_StepSize=15;    // Distance to check each time (larger steps will be faster, but less accurate).
int in_MaxDistance=30; // Maximum distance to search out to. Cannot be more than 127!

vec4 distField(){

    vec2 pixel_size = 1.0 / vec2(textureSize(colorMap, 0));
    vec2 screenTexCoords = gl_FragCoord.xy * pixel_size;
    int distance;

    if(texture(colorMap, screenTexCoords).a == 0.0)
    {
        // Texel is transparent, search for nearest opaque.
        distance = ZERO_VALUE + 1;
        for(int i = in_StepSize; i < in_MaxDistance; i += in_StepSize)
        {
            if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 1.0))
            {
                i = in_MaxDistance + 1; // BREAK!
            }
            else
            {
                distance = ZERO_VALUE + 1 + i;
            }
        }
    }
    else
    {
        // Texel is opaque, search for nearest transparent.
        distance = ZERO_VALUE;
        for(int i = in_StepSize; i <= in_MaxDistance; i += in_StepSize)
        {
            if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 0.0))
            {
                i = in_MaxDistance + 1; // BREAK!
            }
            else
            {
                distance = ZERO_VALUE - i;
            }
        }
    }

    return  vec4(vec3(float(distance) / 255.0) * diffuseOut.rgb, 1.0 - texture(colorMap, screenTexCoords).a);

}

void main()
{
    outputColor= distField();
}

このシェーダの結果は、ディスタンス フィールド アウトラインの外側の画面領域を塗りつぶすためにディフューズ カラーを使用して画面全体をカバーします。次のようになります。 ここに画像の説明を入力

私が必要とするのは、距離フィールドの外側の塗りつぶされた赤い塗りつぶしを持つすべての領域を透明のままにすることです。

4

2 に答える 2

2

ディスタンス フィールド グレー スケール 8 ビット アルファ マップを使用して解決策にたどり着きました。Stefan Gustavson がその方法を詳しく説明しています。基本的には、元のテクスチャのディスタンス フィールド バージョンを生成する必要があります。次に、このテクスチャは通常、最初のパスでプリミティブを使用して FBO にレンダリングされます。2 番目のパスでは、アルファ ブレンディング モードを使用する必要があります。最初のパスからのテクスチャは、スクリーン クワッドで使用されます。この段階で、フラグメント シェーダはそのテクスチャからアルファをサンプリングします。これにより、滑らかなエッジとエッジの周りのアルファ透明度の両方が得られます。結果は次のとおりです。 ここに画像の説明を入力

于 2012-09-03T06:38:36.357 に答える
0

スクリーンショットに基づいて、フルスクリーンのクワッドをレンダリングしていると思いますか? ティムが答えを提供したばかりの場合は、次を試してください。

glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

クワッドをレンダリングする前に。明らかに、透明でないものもレンダリングする場合は、深度バッファの問題が発生しないように、最初にそれらをレンダリングすることをお勧めします。透明なものの描画が完了したら、次を呼び出します。

glDisable( GL_BLEND ); 

アルファブレンディングを再びオフにします。

于 2012-09-01T20:13:14.530 に答える