6

次のシナリオを想像してみてください。PNG形式のRPGキャラクタースプライトシートのセットがあり、それらをOpenGLアプリケーションで使用したいとします。

個別の文字は(通常)16 x 24ピクセルのサイズ(つまり、24ピクセルの高さ)であり、パディングを残さずに任意の幅と高さにすることができます。このようなちょっと:

ファイナルファンタジーVIのテラ
(出典:kafuka.org

フレームインデックスとサイズを指定して、整数ベースのクリッピング長方形を決定するコードをすでに持っています。

int framesPerRow = sheet.Width / cellWidth;
int framesPerColumn = sheet.Height / cellHeight;
framesTotal = framesPerRow * framesPerColumn;
int left = frameIndex % framesPerRow;
int top = frameIndex / framesPerRow;
//Clipping rect's width and height are obviously cellWidth and cellHeight.

このコードをで実行すると、幅/高さではなく右/下であると仮定してframeIndex = 11, cellWidth = 16, cellHeight = 24、cliprectが返されます。(32, 24)-(48, 48)

実際の質問

さて、スプライトを配置するためのクリッピング長方形とX / Y座標が与えられた場合、これをOpenGLで描画するにはどうすればよいですか?左上にゼロ座標を設定することをお勧めします。

4

4 に答える 4

10

座標が[0、1]の範囲にある「テクスチャ空間」で考え始める必要があります。

したがって、スプライトシートがある場合:

class SpriteSheet {
    int spriteWidth, spriteHeight;
    int texWidth, texHeight;

    int tex;

public:
    SpriteSheet(int t, int tW, int tH, int sW, int sH)
    : tex(t), texWidth(tW), texHeight(tH), spriteWidth(sW), spriteHeight(sH)
    {}

    void drawSprite(float posX, float posY, int frameIndex);
};

あなたがしなければならないのは、頂点テクスチャ頂点の両方をOpenGLに送信することです。

    void SpriteSheet::drawSprite(float posX, float posY, int frameIndex) {
        const float verts[] = {
            posX, posY,
            posX + spriteWidth, posY,
            posX + spriteWidth, posY + spriteHeight,
            posX, posY + spriteHeight
        };
        const float tw = float(spriteWidth) / texWidth;
        const float th = float(spriteHeight) / texHeight;
        const int numPerRow = texWidth / spriteWidth;
        const float tx = (frameIndex % numPerRow) * tw;
        const float ty = (frameIndex / numPerRow + 1) * th;
        const float texVerts[] = {
            tx, ty,
            tx + tw, ty,
            tx + tw, ty + th,
            tx, ty + th
        };

        // ... Bind the texture, enable the proper arrays

        glVertexPointer(2, GL_FLOAT, verts);
        glTexCoordPointer(2, GL_FLOAT, texVerts);
        glDrawArrays(GL_TRI_STRIP, 0, 4);
    }

};
于 2009-10-14T20:07:21.533 に答える
7

フランクのソリューションはすでに非常に優れています。

コメントのいくつかは別の方法で示唆しているので、(非常に重要な)補足です。

glBegin/glEndは絶対に使用しないでください。誰かにそれを使うように言わないでください。

glBegin / glEndを使用しても問題がないのは、最初のOpenGLプログラムだけです。

配列の処理はそれほど難しくありませんが...

  • ...彼らはより速いです。
  • ...新しいOpenGLバージョンでも引き続き機能します。
  • ...彼らはGLESで動作します。
  • ...ファイルからそれらをロードする方がはるかに簡単です。
于 2009-10-31T22:54:57.263 に答える
0

私はあなたがOpenGLを学んでいて、これをなんとかして機能させる必要があるだけだと思います。生の速度が必要な場合は、シェーダーと頂点バッファー、およびあらゆる種類のきちんとした複雑なものがあります。

最も簡単な方法は、PNGをテクスチャにロードし(画像をメモリにロードする機能があると仮定すると、htatが必要です)、適切なテクスチャ座標を設定するクワッドで描画します(浮動小数点座標で0から1になります)。 、したがって、テクスチャの幅または高さで割る必要があります)。

これを描画する最も簡単な(ただし最速ではない)方法として、glBegin(GL_QUADS)、glTexcoord2f()、glVertex2f()、glEnd()を使用します。

左上をゼロにするには、gluOrtho()を使用して通常のGLとは異なる方法でビューマトリックスを設定するか(その関数のドキュメントを検索し、topを0に、bottomを1に設定するか、整数座標が必要な場合はscreen_heightを設定します)、または単に変更します描画ループを実行し、glVertex2f(x / screen_width、1-y / screen_height)を実行します。

これを行うためのより良い、より速い方法がありますが、生のOpenGLを最初から学習している場合、これはおそらく最も簡単な方法の1つです。

于 2009-10-14T20:02:12.463 に答える
0

可能であれば、提案。SDLを使用してテクスチャをロードしているので、次のようにしました。1.テクスチャをロードしました。2。スプライトシートを個別のスプライトに分割する方法を決定しました。3.それらを別々のサーフェスに分割します。4。それぞれにテクスチャを作成します(それらを管理するためのスプライトクラスがあります)。5.表面を解放します。これは(明らかに)ロードに時間がかかりますが、後で支払います。このようにすると、表示するテクスチャのインデックスを計算してから表示するだけで済むため、はるかに簡単(かつ高速)になります。次に、必要に応じて拡大縮小/変換し、ディスプレイリストを呼び出して必要なものにレンダリングできます。または、即時モードで実行することもできます。どちらでも機能します:)

于 2009-10-14T20:20:22.467 に答える