2

C# で OpenTK を介して OpenGL を使用しており、一般的なビットマップからテクスチャを読み込もうとしています。私のドライバーは NPOT テクスチャをサポートしていないので、GL.TexImage2D で POT テクスチャを割り当て、GL.TexSubImage2D を介してビットマップで塗りつぶします。ただし、これらのテキストの描画中にアーティファクトがあります。テクスチャの下部と右側にも追加のピクセルが描画されるようです。比率からピクセルを差し引くだけですか、それとも他に何か問題がありますか?

作成コード:

GL.BindTexture(TextureTarget.Texture2D, t.Name);

GL.PixelStore(PixelStoreParameter.PackAlignment, 1);
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, texture.W2, texture.H2, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture.DataSize.Width, texture.DataSize.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data);

GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D);

GL.BindTexture(TextureTarget.Texture2D, 0);

描画用コード:

GL.BindTexture(TextureTarget.Texture2D, t.Name);

float x1 = 0;
float x2 = texture.WidthRatio;
float y1 = 0;
float y2 = texture.HeightRatio;

float rx1 = rect.X;
float rx2 = rect.X + rect.W;
float ry1 = rect.Y;
float ry2 = rect.Y + rect.H;

GL.Begin(BeginMode.Quads);

GL.TexCoord2(x1, y1);
GL.Vertex3(rx1, ry1, rect.Z + CGraphics.ZOffset);

GL.TexCoord2(x1, y2);
GL.Vertex3(rx1, ry2, rect.Z + CGraphics.ZOffset);

GL.TexCoord2(x2, y2);
GL.Vertex3(rx2, ry2, rect.Z + CGraphics.ZOffset);

GL.TexCoord2(x2, y1);
GL.Vertex3(rx2, ry1, rect.Z + CGraphics.ZOffset);

GL.End();

GL.Disable(EnableCap.Blend);
GL.BindTexture(TextureTarget.Texture2D, 0);

texture.WidhtRatio = DataSize.Width / W2;

4

2 に答える 2

1

これはすべて、テクスチャリングのエッジ ケースに関係しています。GL でテクスチャを初めて見たとき、ほとんどのチュートリアルでは次のことが紹介されています。

  1. フィルタリング (テクセル間で何が起こるか)

    • 最寄り
    • 線形

    違いは下の画像で確認できます。

  2. ラップ モード (テクスチャ境界の後に何が起こるか)

    テクスチャ座標が -1 から 1 の外側になくても、色のラッピングに注意してください --- 線形フィルタリングとリピート ラッピング モードの両方の組み合わせです。

言う必要があるもう 1 つの重要なことは、サンプルがピクセルとテクセルの中間に配置されることです。そのため、gl_FragCoord.xy常に分数があり.5ます (マルチ/スーパー サンプリングなどに到達するまで)。これは下の画像で見ることができます。ここに問題があるのではないかと思います。テクスチャ座標を調整して、テクスチャのインセットをサンプリングし、隣接するピクセルの補間を回避することができます (つまりx+0.5、 へx+width-0.5)。

ここに画像の説明を入力


ミップマップにはより広い領域の色が含まれるため、座標を変更するだけでは機能しません。の動作を再現するにはGL_CLAMP_TO_EDGE、サブ イメージの境界線を手動で押し出す必要があります。または、アップロードする前にテクスチャをクリアする方がはるかに簡単です。手っ取り早い方法は、テクスチャを FBO にアタッチすることglClearです。

glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glDeleteFramebuffers(1, &fbo);

さらに一歩進んでテクスチャを押し出すには、サブ画像をアップロードしてから、サブ画像と目的の境界線の上にクワッドを描きます。フラグメント シェーダーで、サブ イメージ内のピクセルを破棄し、文字通り を呼び出しますcoord = clamp(coord, imageMin, imageMax)。ダブル バッファリングを回避するには、描画中に読み取ります。複数のサブ画像がある場合は、ここで z バッファーを使用して、四角形の代わりに四角錐を描画し、深さテストを各サブ画像への最小距離のように機能させることができます (円錐でボロノイ セルを描画するのと同じように) )

于 2014-09-16T09:03:18.550 に答える
1

バイリニア フィルタリングを使用しているため、最後の列と行が初期化されていないテクスチャ データで補間されます (したがってアーティファクト)。

バイリニア フィルタリングを有効にしたい場合、テクスチャ データ テクスチャの最後の行と最後の列を複製することができます。つまり、NPOT テクスチャが 800x600 の場合、最後の列/行を複製して 801x601 ピクセルをアップロードします。

このようにして、最後の行/列の補間は期待される結果を返し、アーティファクトは消えるはずです。

編集: Reto Koradi が示唆したように、これはミップマップを使用していない場合にのみ機能します。ミップマップを使用している場合、特に異方性フィルタリングを使用している場合は、空の領域をすべて最後の列/行で埋める必要があります。

于 2014-09-15T14:40:52.747 に答える