2016-09-06 21 views
2

私はさまざまなサイズのプラットフォームを用意していますが、常に8ピクセルの乗算と常に8ピクセルの高さのゲームを作成しています。GLSL Fragmentシェーダでインテリジェントなタイルテクスチャ

すべてのプラットフォームは、ここでは1のように同じテクスチャを使用します。

Tiling texture image with description

テクスチャが3つの8×8のセクションに分割されます。私は最初の8ピクセルが左端にのみ適用されるように、このテクスチャをフラグメントシェーダでタイル化できるようにしたい - ジオメトリの幅から最後の8ピクセルを引いた数のピクセルの中央の8ピクセルのタイル「終了」タイルがレンダリングされる。高い32個のピクセルの幅と8つの画素でこのジオメトリのようなもの:

Tiled platform

I、使用フレームワークが頂点とUV座標(単純なテクスチャクワッド)の設定を許可しないので、私はこの問題を解決することができませんジオメトリ。

私はフラグメントシェーダでは、以下のユニフォームを取得:sampler2D

  • u_texture - ジオメトリのサイズ -

  • VEC2 u_sprite_size上記のテクスチャテクスチャをタイルで飾りたい(ピクセル単位)

...と、この変化:

  • VEC2v_tex_coord - テクスチャにアクセスするために使用される座標。これらは、ポイント(0.0,0.0)がテクスチャの左下隅の にあるように正規化されています。

コードで他のユニフォームを追加することは可能です。

誰かがフラグメントシェーダーの作成方法の方向を教えてくれますか?

+1

あなたは、デスクトップのOpenGLまたはOpenGL ESについて尋ねていますか?彼らは同じことではないからです。また、サイズが常に8の倍数になることは保証されていますか? –

+0

これは初心者のためのOpenGL-ESですが、私はMacにゲームを移植するので、OpenGLの解決策も必要になります。他の質問には、はい、それは8倍のグリッドに基づくタイルなので、このゲームでは常に8の倍数になります。 – Kim

答えて

1

私はあなたの問題を解決しようとしましたので、私は単純なフラグメントシェーダーを書きました。それはおそらく最もクリーンなソリューションではないので、最適化しようとすることができます。あなたが現在処理しているタイルとを計算する必要が

float verticalTiles = u_sprite_size.x/8.0; 

をその後:

あなたが必要がある最初の事は(垂直方向にのみ)オブジェクト内のタイル数を計算することですこのタイルのUV。これを行うには、uv座標に垂直タイルの量を掛けて、整数だけが必要なので値をフロアします。そして、あなたはまた、UV座標を取得するために値をFRACTする必要があります。

float tile = floor(verticalTiles * v_tex_coord.x); 
float tileUV = fract(verticalTiles * v_tex_coord.x); // [0; 1] for each tile 

は今、あなたは唯一の最後のタイルに最初のタイルと最後の8つのピクセルにテクスチャの最初の8つのピクセルを適用したいです。他のタイルは中央の8ピクセルを持ちます。単純なif文を使用してサンプリングすることができます。 Vはとにかく変更されませんので、我々は唯一の U値を計算している。

float resultU; 

if(tile == 0.0){ 
    // If this is first tile, then we want the UV coordinates of the first 8 pixels. 
    // We divide tileUV by 3 to get UV coordinates [0; 0.3333]. 
    resultU = tileUV/3.0; 

}else if(tile == verticalTiles - 1.0){ 
    // If this is last tile we do the same thing but add two thirds 
    // to the coordinates to get last 8 pixels [0.6666; 1] 
    resultU = tileUV/3.0 + (2.0/3.0); 

}else{ 
    // Else we want the middle 8 pixels [0.3333; 0.6666] 
    resultU = tileUV/3.0 + (1.0/3.0); 
} 

が続いてテクスチャからサンプリングするこの値を使用します。

gl_FragColor = texture2D(u_texture, vec2(resultU, v_tex_coord.y)); 
+1

MarGenDoありがとうございました:)私はif ... elseを避けることを望んでいましたが、シェーダを適用するとパフォーマンスがあまりにも負の影響を受けないので、必要に応じて動作します。 – Kim

0

あなたがすでに知っているように、これを達成する典型的な方法は、UV座標を頂点と共に送信することです。データ。しかし、ちょうど安全であるために、私は繰り返し述べます。テクスチャマッピングが発生するためには、テクスチャ座標を頂点シェーダから補間用のフラグメントシェーダに渡す必要があります。適切にマッピングされたUV座標を指定することはできませんので、正確に行われなければ、畳み込まれ、エラーが発生しやすいフラグメントシェーダーでそれらを計算する必要があります。つまり、正規化されたUV座標は0〜1の範囲であるため、8×8のタイルは実際の{0-1} x {0-1}になります。ランダムジオメトリでは、実際にUV(歪みなし)を自動的に生成するために幅、高さ、ワールドオフセットを知る必要があります。別の手で

可能であれば、あなたが最善の策だあなたは、あなたがハードできる4つの既知の点を持っているように、すべての等しい幅と高さの1枚の平方タイルを描くように、オブジェクトのインスタンス化を使用することですUV [0-1] x [0-1]にマップするコード。それらはモデル行列のオフセットを使って行内の同じタイルをインスタンス化するだけです。基本的には、1つの既知の正方形のジオメトリを複製し、同じオブジェクトを可能な限り並べています。別のインスタンスコレクションとして、すべての種類の正方形(左、中央、右)を考えてみましょう。新しい問題は、次々とラインのタイルをオフセットするモデル行列を生成することになります。

これは、GPUに渡されるトライアングルが比較的少ない大規模な世界を生成する非常に効率的な方法です。

+0

ありがとうございました。問題は、私が使用しているフレームワークでUVを設定できないということです。オブジェクトは単純なクワッドにレンダリングされます。つまり、UVは0,0の左下から1,1の右上に移動します。この情報は、さまざまな** v_tex_coord **のフラグメントシェーダで取得します。私はまた、ユニフォーム** u_sprite_size **を介してオブジェクトの幅をピクセル単位で知っています。私は何らかの形でこの情報をvec2に翻訳する必要があります。これは、上記のように** u_texture **をサンプリングするために使用できます。私はオブジェクトのサイズを知っているので、vec2 count = u_sprite_size/vec2(8.0、8.0)でタイルの数を得ることができます。 – Kim

+0

。私は答えを他人への参照として残しておきますが、あなたは単純にAPIにバインドされているように聞こえます。おそらく、APIプロバイダがより良いソースかもしれません。 –

関連する問題