シームレスなタイルマップレンダリング(境界のない隣接画像)


18

タイルセットイメージからタイルを描画してタイルマップを描画する2Dゲームエンジンがあります。デフォルトでは、OpenGLはテクスチャのGL_REPEAT一部()ではなくテクスチャ全体のみをラップできるため、各タイルは個別のテクスチャに分割されます。次に、同じタイルの領域が互いに隣接してレンダリングされます。意図したとおりに動作しているときの外観は次のとおりです。

縫い目のないタイルマップ

ただし、分数スケーリングを導入するとすぐに、継ぎ目が表示されます。

シーム付きのタイルマップ

なぜこれが起こるのですか?これは、四角形の境界線をブレンドする線形フィルタリングによるものだと思いましたが、それでもポイントフィルタリングでは発生します。私がこれまでに見つけた唯一の解決策は、すべての位置決めとスケーリングが整数値でのみ発生するようにし、ポイントフィルタリング使用することです。これにより、ゲームの視覚的品質が低下する可能性があります(特に、サブピクセルの配置が機能しなくなるため、動きがそれほど滑らかになりません)。

私が試した/考えたこと:

  • アンチエイリアスは、継ぎ目を減らしますが、完全に排除しません
  • ミップマッピングをオフにしても効果はありません
  • 各タイルを個別にレンダリングし、1ピクセルずつエッジを押し出します-しかし、これは最適化されていません。タイルの領域を一度にレンダリングできなくなり、透明領域のエッジに沿って他のアーティファクトを作成するためです。
  • ソース画像の周囲に1pxの境界線を追加し、最後のピクセルを繰り返します-しかし、それらは2のべき乗ではなくなり、NPOTサポートのないシステムとの互換性の問題を引き起こします
  • タイル化された画像を処理するためのカスタムシェーダーを記述しますが、それではどうしますか?GL_REPEAT境界で画像の反対側からピクセルをつかみ、透明度を選択しないでください。
  • ジオメトリは正確に隣接しているため、浮動小数点の丸め誤差はありません。
  • フラグメントシェーダーが同じ色を返すようにハードコーディングされている場合、縫い目は消えます。
  • テクスチャに設定されている場合GL_CLAMPの代わりにGL_REPEAT継ぎ目が消え(レンダリングが間違っているが)。
  • テクスチャがに設​​定されているGL_MIRRORED_REPEAT場合、縫い目は消えます(ただし、レンダリングは再び間違っています)。
  • 背景を赤にしても、縫い目は白のままです。これは、透明ではなく、どこかから不透明な白をサンプリングしていることを示唆しています。

そのため、シームGL_REPEATは設定されている場合にのみ表示されます。このモードでのみ何らかの理由で、ジオメトリの端にブリード/漏れ/透明度があります。それはどうですか?テクスチャ全体が不透明です。


テクスチャサンプラーをクランプに設定したり、境界線の色を調整したりすることができます。また、GL_RepeatはUV座標を単純にラップするため、テクスチャの一部ではなく、テクスチャ全体のみを繰り返すことができると言うと、個人的に少し混乱します。
エヴァン

1
どういうわけかメッシュに亀裂を導入している可能性はありますか?テクスチャをサンプリングするのではなく、単色を返すようにシェーダーを設定することでテストできます。その時点でまだ亀裂が見られる場合、それらはジオメトリにあります。アンチエイリアスは継ぎ目を減らすという事実は、アンチエイリアスがテクスチャサンプリングに影響を与えるべきではないため、これが問題である可能性を示唆しています。
ネイサンリード

テクスチャアトラスで個々のタイルの繰り返しを実装できます。ただし、いくつかの追加のテクスチャ座標計算を行い、各タイルの周囲に境界テクセルを挿入する必要があります。この記事では、この多くについて説明します(ただし、主にD3D9の迷惑なテクスチャ座標規則に焦点を当てています)。あるいは、実装が十分に新しい場合は、タイルマップに配列テクスチャを使用できます。各タイルの寸法が同じであると仮定すると、これはうまく機能し、追加の座標計算を必要としません。
アンドンM.コールマン

座標方向にGL_NEARESTサンプリングされた3DテクスチャRも、このシナリオのほとんどの場合に配列テクスチャと同様に機能します。ミップマッピングは機能しませんが、アプリケーションから判断すると、おそらくミップマップは必要ありません。
アンドンM.コールマン

1
CLAMPに設定すると、レンダリングはどのように「間違った」状態になりますか?
マーティンコートー

回答:


1

縫い目は、GL_REPEATによるサンプリングの正しい動作です。次のタイルを検討してください。

ボーダータイル

分数の値を使用してタイルの端をサンプリングすると、端と反対側の端の色が混ざり、間違った色になります。左端は緑であるはずですが、緑とベージュが混ざっています。右端はベージュである必要がありますが、同様に混合色です。特に、緑の背景のベージュ色の線は非常に目立ちますが、よく見ると緑の縁がにじんで見えます。

スケーリングされたタイル

アンチエイリアスは、継ぎ目を減らしますが、完全に排除しません

MSAAは、ポリゴンエッジの周囲により多くのサンプルを取得することで機能します。エッジの左または右から取られたサンプルは「緑」になり(最初の画像の左端を考慮して)、エッジに「オン」になり、「ベージュ」領域から部分的にサンプリングされます。サンプルが混合されると、効果は減少します。

可能な解決策:

いずれにしてもGL_CLAMP、テクスチャの反対側のピクセルからのにじみを防ぐために切り替える必要があります。次に、3つのオプションがあります。

  1. アンチエイリアスを有効にして、タイル間の移行を少しスムーズにします。

  2. テクスチャフィルタリングをに設定しGL_NEARESTます。これにより、すべてのピクセルにハードエッジが与えられるため、ポリゴン/スプライトエッジは区別できなくなりますが、明らかにゲームのスタイルがかなり変更されます。

  3. 既に説明した1pxの境界線を追加し、境界線の色が隣接するタイルの色であることを確認します(反対側のエッジの色ではありません)。

    • これは、テクスチャアトラスに切り替える良い機会かもしれません(NPOTサポートが心配な場合は、大きくしてください)。
    • これは、唯一の「完璧な」ソリューションでGL_LINEARあり、ポリゴン/スプライトのエッジ全体のようなフィルタリングを可能にします。

ああ、ありがとう-テクスチャを包むことで説明できます。それらのソリューションを見ていきましょう!
アシュリーズブレイン

6

デフォルトでは、OpenGLはテクスチャの一部(GL_REPEAT)のみをラップできるため、各タイルは個別のテクスチャに分割されます。次に、同じタイルの領域が互いに隣接してレンダリングされます。

OpenGLの単一の通常のテクスチャ付きクワッドの表示を検討してください。どんな規模でも縫い目はありますか?いいえ、決して。目標は、すべてのシーンタイルを1つのテクスチャにしっかりと詰め込み、それを画面に送信することです。編集これをさらに明確にするために:各タイルクワッドに個別の境界の頂点がある場合、ほとんどの状況で一見不当な継ぎ目あります。GPUハードウェアの仕組みです...浮動小数点エラーは、現在の視点に基づいてこれらのギャップを作成します... 2つの面が同じ多様体内で隣接している場合、統一された多様体で回避されるエラー(サブメッシュ)、ハードウェアは継ぎ目なしでそれらをレンダリングします。これは数え切れないほどのゲームやアプリで見ました。これを完全に回避するには、頂点を2重にせずに、1つのサブメッシュに1つの密集したテクスチャを配置する必要があります。このサイトや他の場所で何度も発生する問題です。タイルのコーナー頂点をマージしない場合(4つのタイルがコーナー頂点を共有する場合)、継ぎ目が予想されます。

(マップ全体の四隅を除いて頂点さえ必要としないかもしれないと考えてください...シェーディングへのアプローチに依存します。)

解決するには:すべてのタイルテクスチャギャップなしでFBO / RBOに(1:1で)レンダリングし、そのFBOをデフォルトのフレームバッファー(画面)に送信します。FBO自体は基本的に単一のテクスチャであるため、スケーリングにギャップが生じることはありません。GL_LINEAR ....を使用している場合、画面のピクセル境界に収まらないすべてのテクセル境界がブレンドされます。これが標準的なアプローチです。

これにより、スケーリングへのさまざまなルートも開かれます。

  • FBOをレンダリングするクワッドのサイズをスケーリングします
  • そのクワッドのUVを変更する
  • カメラの設定をいじる

これが私たちにとってうまくいくとは思わない。10%のズームで10倍の領域をレンダリングすることを提案しているようです。これは、フィルレートが制限されているデバイスには適していません。また、特にGL_REPEATがシームのみを引き起こし、他のモードはそうしない理由について、私はまだ謎に思っています。どうでしたか?
アシュリーズブレイン

@AshleysBrain Non sequitur。私はあなたの声明に戸惑っています。ズームを10%増やすと、フィル率が10倍になることを説明してください。または、ズームを10倍にするとどうなりますか?ビューポートクリッピングにより、1回のパスで100%を超える塗りつぶし率が妨げられるためですか?一般的な手法であるRTTを使用して最終出力を統合することにより、より効率的でシームレスな方法で、すでに意図しているものを正確に表示することをお勧めします。ハードウェアは、ビューポートのクリッピング、スケーリング、ブレンド、および補間を事実上無料で処理します。これは2Dエンジンのみであるためです。
エンジニア

@AshleysBrain現在のアプローチの問題を明確にするために質問を編集しました。
エンジニア

@ArcaneEngineerこんにちは、シームの問題を完全に解決するアプローチを試してみました。ただし、現在では、継ぎ目が発生する代わりにピクセルエラーが発生します。私がここで言及している問題の考えを持つことができます。この原因は何であるか考えていますか?WebGLですべてを行っていることに注意してください。
ネミコル

1
@ArcaneEngineer新しい質問をしますが、ここで説明するのは面倒です。ご迷惑をおかけして申し訳ありません。
ネミコル

1

画像を1つの表面として表示する場合は、これらを1つの3Dメッシュ/平面上の1つの表面テクスチャ(スケール1x)としてレンダリングします。それぞれを個別の3Dオブジェクトとしてレンダリングする場合、丸め誤差により常に継ぎ目が生じます。

@ Nick-Wiggillによる答えは正しいです、あなたはそれを誤解したと思います。


0

試す価値がある2つの可能性:

  1. テクスチャフィルタリングのGL_NEAREST代わりに使用GL_LINEARします。(Andon M. Colemanが指摘したように)

    GL_LINEAR(実質的に)画像をほんの少しぼかします(最も近いピクセル間で補間)。これにより、ピクセル間の色の滑らかな移行が可能になります。これにより、テクスチャの全体にブロック状のピクセルができなくなるため、多くの場合、テクスチャの見栄えがよくなります。また、1つのタイルの1ピクセルから少し茶色がかかって、隣接するタイルの隣接する緑のピクセルにぼかしがかかるようにします。

    GL_NEAREST最も近いピクセルを見つけて、その色を使用します。補間なし。その結果、実際には少し速くなります。

  2. 各タイルのテクスチャ座標を少し縮小します。

    画像上のタイルを拡大する代わりに、ソフトウェアでタイルを縮小することを除いて、各タイルの周りにその余分なピクセルをバッファーとして追加するようなものです。16x16pxタイルではなく、レンダリング中の14x14pxタイル。

    14.5x14.5のタイルで、茶色があまり混じることなく逃げることができるかもしれません。

-編集-

オプション#2の説明の視覚化

上の画像に示すように、2のべき乗のテクスチャを簡単に使用できます。したがって、NPOTテクスチャをサポートしないハードウェアをサポートできます。変更されるのは、テクスチャ座標であり、からに(0.0f, 0.0f)移動(1.0f, 1.0f)するのではなくから(0.03125f, 0.03125f)に移動します(0.96875f, 0.96875f)です。

これにより、Tex-coordsがタイル内にわずかに配置され、ゲームの有効解像度が低下します(ただし、ハードウェアではないため、2のべき乗のテクスチャを使用できます)。


GL_NEAREST(別名ポイントフィルター)を試したことは既に述べましたが、修正されません。NPOTデバイスをサポートする必要があるため、#2を実行できません。
アシュリーズブレイン

いくつかの問題を解決する可能性のある編集を行いました。(「NPOT [(非2のべき乗)]]デバイスをサポートする必要がある」とは、テクスチャを2の累乗に保つ必要があるという意味です。)
Wolfgang Skyler

0

これは私が考えていることです。2つのタイルが衝突する場合、それらのエッジのxコンポーネントは等しくなければなりません。そうでない場合は、反対方向に丸められる可能性があります。したがって、x値がまったく同じであることを確認してください。これを確実に行うにはどうすればよいですか?たとえば、10で乗算し、丸めてから10で除算しようとします(頂点シェーダーに入る前に、CPUでのみこれを行います)。これで正しい結果が得られるはずです。また、変換マトリックスを使用してタイルごとに描画するのではなく、それらをバッチVBOに入れて、マトリックス乗算と組み合わせた損失の多いIEEE浮動小数点システムから間違った結果が生じないようにします。

なぜこれを提案するのですか?私の経験から、頂点シェーダーから出たときに頂点がまったく同じ座標を持っている場合、対応する三角形を塗りつぶすとシームレスな結果が得られるためです。IEEEのせいで、数学的に正しいものは少しずれている場合があることに注意してください。数値に対して実行する計算が多いほど、結果の精度は低下します。そして、はい、行列の乗算にはかなりの操作が必要です。これは、VBOを作成するときに乗算と加算だけで行うことができ、より正確な結果が得られます。

また、問題になる可能性があるのは、スプライトシート(アトラスとも呼ばれる)を使用していることと、テクスチャをサンプリングするときに、隣接するタイルテクスチャのピクセルが選択されることです。これが起こらないようにするには、UVマッピングに小さな境界線を作成します。したがって、64x64タイルがある場合、UVマッピングのカバー範囲は少し狭くなります。いくら?私は自分のゲームで、長方形の各辺で1/4ピクセルを使用したと思います。したがって、UVをxコンポーネントでは1 /(4 * widthOfTheAtlas)、yコンポーネントでは1 /(4 * heightOfTheAtlas)オフセットします。


感謝しますが、既に述べたように、ジオメトリは間違いなく正確に隣接しています-実際、すべての座標は正確な整数になるため、わかりやすいです。ここではアトラスは使用されません。
アシュリーズブレイン

0

3D空間でこれを解決するために、テクスチャアレイとWolfgang Skylerの提案を組み合わせました。各タイルの実際のテクスチャ(合計120x120、128x128)の周囲に8ピクセルの境界線を配置します。各辺は、「ラップされた」画像で埋めることができます。サンプラーは、イメージを補間するときにこの領域を読み取ります。

フィルタリングとミップマッピングにより、サンプラーは8ピクセルの境界全体を簡単に読み取ることができます。その小さな問題をキャッチするために(ジオメトリが実際に歪んでいるか遠く離れているときに数ピクセルでのみ発生するため、小さいと言います)、タイルをテクスチャ配列に分割し、各タイルに独自のテクスチャスペースを持たせ、エッジ。

あなたの場合(2D /フラット)、私は確かにピクセル完璧なシーンをレンダリングし、次に、ニック・ウィギルが示唆するように、結果の目的の部分をビューポートにスケーリングします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.