「隣接する」エッジに等しい (正確に等しい) 座標を渡すにもかかわらず、レンダリングされたタイルのグリッドをスケーリングすると、隣接する要素間に奇妙な線ができてしまいます。
私のタイル グリッド レンダリング アルゴリズムはスケーリングされたタイルを受け入れるので、他の理由の中でもとりわけ、同じ縦横比の選択されたウィンドウ サイズに一致するようにグリッドのビジュアル サイズを調整できます。正確な整数といくつかの非整数値にスケーリングすると正しく動作するように見えますが、他の値については一貫性のない結果が得られます。
いくつかのスクリーンショット:
ブルーのラインは透けて見えるクリアカラーです。未使用のタイルはマゼンタで、実際の透明度はアルファ レイヤーによって処理されるため、選択したテクスチャにはタイルシートに透明なギャップがありません。シート内の隣接するタイルは完全に不透明です。スケーリングは、1f と 2f の間のゲームパッド トリガーによって取得された正規化された値にスケールを設定することで実現されるため、最大/最小を除いて、ショットが撮影されたときに実際に適用されたスケールはわかりません。
属性の更新とエンティティの描画はスレッド間で同期されるため、描画中に値が適用されることはありませんでした。これはスクリーンショットではうまく伝わりませんが、その時点で縮尺が維持されている場合は線がちらつかないため、論理的には、縮尺の割り当て間の描画で問題になることはありません (スレッド ロックによりこれが防止されます)。
1x にスケーリング:
A にスケーリング、1x < Ax < Bx :
B にスケーリング、Ax < Bx < Cx :
C にスケーリング、Bx < Cx < 2x :
2倍にスケーリング:
投写設定機能
正射投影を設定する場合 (画面サイズが変更された場合のみ変更):
.......
float nw, nh;
nh = Display.getHeight();
nw = Display.getWidth();
GL11.glOrtho(0, nw, nh, 0, 1, -1);
orthocenter.setX(nw/2); //this is a Vector2, floats for X and Y, direct assignment.
orthocenter.setY(nh/2);
.......
スクリーンショットでは、nw は 512、nh は 384 です (int から暗黙的にキャストされます)。これらは、上記の例全体で変わることはありません。
一般的な GL 描画コード
カットしても問題が解決しなかった無関係な属性をカットした後:
@Override
public void draw(float xOffset, float yOffset, float width, float height,
int glTex, float texX, float texY, float texWidth, float texHeight) {
GL11.glLoadIdentity();
GL11.glTranslatef(0.375f, 0.375f, 0f); //This is supposed to fix subpixel issues, but makes no difference here
GL11.glTranslatef(xOffset, yOffset, 0f);
if(glTex != lastTexture){
GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTex);
lastTexture = glTex;
}
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(texX,texY + texHeight);
GL11.glVertex2f(-height/2, -width/2);
GL11.glTexCoord2f(texX + texWidth,texY + texHeight);
GL11.glVertex2f(-height/2, width/2);
GL11.glTexCoord2f(texX + texWidth,texY);
GL11.glVertex2f(height/2, width/2);
GL11.glTexCoord2f(texX,texY);
GL11.glVertex2f(height/2, -width/2);
GL11.glEnd();
}
グリッド描画コード (「draw」から削除されたものと同じパラメーターを削除):
//Externally there is tilesize, which contains tile pixel size, in this case 32x32
public void draw(Engine engine, Vector2 offset, Vector2 scale){
int xp, yp; //x and y position of individual tiles
for(int c = 0; c<width; c++){ //c as in column
xp = (int) (c*tilesize.a*scale.getX()); //set distance from chunk x to column x
for(int r = 0; r<height; r++){ //r as in row
if(tiles[r*width+c] <0) continue; //skip empty tiles ('air')
yp = (int) (r*tilesize.b*scale.getY()); //set distance from chunk y to column y
tileset.getFrame(tiles[r*width+c]).draw( //pull 'tile' frame from set, render.
engine, //drawing context
new Vector2(offset.getX() + xp, offset.getY() + yp), //location of tile
scale //scale of tiles
);
}
}
}
タイルとプラットフォーム固有のコードの間で、ベクトルのコンポーネントが取得され、以前に貼り付けた一般的な描画コードに渡されます。
私の分析
数学的には、各位置は、x 方向または y 方向、またはその両方の scale*tilesize の正確な倍数であり、グリッドの位置のオフセットに追加されます。次に、オフセットとして描画コードに渡され、glTranslatef を使用してそのオフセットを変換し、寸法を半分にしてその位置を中心にタイルを描画し、各プラスとマイナスのペアを描画します。
これは、タイル 1 が原点で描画されるとき、オフセットが 0 であることを意味します。次に、OpenGL は、左端が -halfwidth、右端が +halfwidth、上端が -halfheight のクワッドを描画するように指示されます。 、および +halfheight の下端。次に、隣接するタイル 2 を 1 幅のオフセットで描画するように指示されているため、0 からその幅に変換し、-halfwidth で左端を描画します。これは、座標的に tile1 の右端とまったく同じである必要があります。それ自体で、これは機能するはずです。等尺で考えるとなんとなく壊れます。
スケールが適用されると、それはすべての幅/高さの値に対して一定の倍数であり、数学的には何も変更されません。ただし、次の 2 つの理由のいずれかが考えられるため、違いはあります。
- OpenGL はサブピクセルの塗りつぶしに問題があります。つまり、頂点の左側を塗りつぶしても、頂点を含むピクセル空間が塗りつぶされず、同じ頂点の右側を塗りつぶしても、頂点を含むピクセル空間が塗りつぶされません。
- float の精度の問題が発生しています。どこかと
X+width/2
等しくなく、 tilewidth は整数で、X は float です。X+width - width/2
width = tilewidth*scale
どれが問題であるかを判断する方法、またはサポートできるようにしたい整数以外のスケール値を単に回避する以外にそれを修正する方法についてはよくわかりません。解決策を見つけるために適用できると思われる唯一の手がかりは、行のギャップのパターンが実際には一貫していないことです (場合によってはタイルをスキップする方法、垂直または水平のみで両方ではないなど)。ただし、これが何を意味するのかはわかりません。