web-dev-qa-db-ja.com

GLSLで無限の2Dグリッドをレンダリングするにはどうすればよいですか?

理想的には、私がやりたいのは、単一のクワッドを描画し、GLSLに実際のグリッド線の作成を処理させることです。

これまでの私の試みでは、頂点シェーダー:

#version 400

layout (location = 0) in vec4 in_position;
layout (location = 2) in vec3 in_UV;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

smooth out vec3 ex_UV;
smooth out vec3 ex_originalPosition;

void main()
{
    gl_Position = projection * view * model * in_position;

    ex_UV = in_UV;
    ex_originalPosition = vec3(in_position.xyz);
}

モデル行列は、クワッドを10,000などの大きな数だけスケールアップします。

#version 400

layout (location = 0) out vec4 color;

smooth in vec3 ex_UV;
smooth in vec3 ex_originalPosition;

uniform vec4 lineColor;

void main(void)
{
    if(fract(ex_UV.x / 0.001f) < 0.01f || fract(ex_UV.y / 0.001f) < 0.01f)
        color = lineColor;
    else
        color = vec4(0);
}

これには、テクスチャ座標とワールドスペースの位置の両方を使用してみました。どちらも同じ影響をもたらし、ある角度ではうまく見えますが、他の角度では恐ろしく見え始めます。

enter image description here

enter image description here

距離に応じてアルファをスケーリングして、グリッドがフェードアウトしてゼロになると思いましたが、問題は、画面の中央から2番目の画像で、それらの線もそれらを通るギャップでレンダリングされます(グリッドのポイントは、原点の周りに視覚的な参照フレームを与えることです)。

これを行う簡単な方法はありますか?

編集

要求に応じたスクリーンショット:

X8マルチサンプルフレームバッファーを備えたVBOライン

enter image description here

X8マルチサンプルフレームバッファーとglEnable(GL_LINE_SMOOTH)を備えたVBOライン

enter image description here

私は落ち着きました

私は上記のいずれかに落ち着き(どちらでもかまいません)、原点からの距離の関数としてアルファを単純に下げました。それは私が尋ねた質問ではありませんが、これは私の目的を果たします。 enter image description here

16
NeomerArcana

エイリアシング の単純なケース。ポリゴンレンダリングの場合と同様に、フラグメントシェーダーはピクセルごとに1回実行されます。色は単一の中心座標に対してのみ計算され、実際の色を表すも​​のではありません。

enter image description here

  1. マルチサンプルFBOを作成し、スーパーサンプリングを有効にすることができます。しかし、それは高価です。
  2. 各ピクセルの下にあるライン領域と空のグリッド領域の正確な量を数学的に計算し、フラグメントシェーダーでそれに応じて色を付けることができます。それが均一なグリッドであることを考えると、これは可能な領域にあるかもしれませんが、それでも計算はかなり複雑になる可能性があります。
  3. Mipmappingはすでにテクスチャに対してこれを行っています。ほんの数行のグリッドテクスチャを作成し、それをマップして、非常に大きなクワッドに対して繰り返されるようにします(必ず_GL_REPEAT_を設定してください)。テクスチャの正しいミップマップフィルタリングパラメータを設定し、 glGenerateMipmap を呼び出します。フラグメントシェーダーでtexture2D()/texture()を呼び出すと、OpenGLは、隣接するピクセル間のテクスチャ座標デルタに基づいて、使用するミップマップのレベルを自動的に計算します。最後に、さらに見栄えのするグリッド用に異方性フィルタリングを設定します。

    enter image description here

グリッドを本当に「無限」にしたい場合は、いくつかの海洋レンダラーがグリッドのエッジを垂直ジオメトリで地平線に接続するのを見てきました。それらの前に十分なグリッドがある場合は、それらを1つのフラットカラー(ミップマップのトップレベルの色)に設定することで解決できる可能性があります。


例(コメントに関連):

VBOから描画された1024x2GL_LINES
enter image description here
45fps(HD解像度でのベンチマーク用に100回描画)

GL_LINESエイリアシングに対処するためのマルチサンプリングに関するコメントを参照してください。

ミップマップを使用してクワッドにマッピングされた32 ^ 2テクスチャ
enter image description here
954fps(HD解像度でのベンチマーク用に100回描画)

_Image img;
int w = 128;
int h = 128;
img.resize(w, h, 1);
for (int j = 0; j < h; ++j)
    for (int i = 0; i < w; ++i)
        img.data[j*w + i] = (i < w / 16 || j < h / 16 ? 255 : 0);

tex = img.upload();

glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);

...

//for the quick and dirty, immediate mode
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
glTexCoord2f(0,       0); glVertex3f(0, 0, 0);
glTexCoord2f(1024,    0); glVertex3f(1, 0, 0);
glTexCoord2f(1024, 1024); glVertex3f(1, 0, 1);
glTexCoord2f(0,    1024); glVertex3f(0, 0, 1);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
_
19
jozxyqk

それらの線でさえ、それらを通るギャップでレンダリングされていることがわかります

ああ、もちろんできます。そして、これはあなたがCG 101を怒らせたからです。(怒りはありません:)

を使用しております GL_LINES理由;コンピュータ画面にギャップのない線を描くことは簡単ではありません(解決されたとしても)。私が話しているのは このようなもの 。あなたがしたことは浮動小数点数の計算を行い、サブピクセルラインが描かれることになります(つまり、ギャップ)。

私の提案は、このGLSLコードを廃棄し、通常の頂点として行を生成することです。それはおそらくより速くなるでしょう、そしてあなたは適切な結果を得るでしょう。

また、通常のフォグ計算を使用して、必要な「距離のフェード」効果を得ることができます。

1