OpenGLを使用してSDLで2D画像を描画する方法


8

結局のところ、openGLで2D画像を描画する方法を示す簡単なコードを見つけることができました。

    #include "SDL/SDL.h"
    #include "SDL/SDL_opengl.h"
    #include "SDL/SDL_image.h"

    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int SCREEN_BPP = 32;

    int tex;

    int loadTexture(char* fileName){
        SDL_Surface *image=IMG_Load(fileName);
        SDL_DisplayFormatAlpha(image);
        GLuint object;
        glGenTextures(1,&object);
        glBindTexture(GL_TEXTURE_2D,object);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,image->w,image ->h,0,GL_RGBA,GL_UNSIGNED_BYTE,image->pixels);
        SDL_FreeSurface(image);
        return object;
    }
    void init(){
        glClearColor(0.0,0.0,0.0,0.0);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0.0,800,600,1.0,-1.0,1.0);
        glEnable(GL_BLEND);
        glEnable(GL_TEXTURE_2D);
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
        tex = loadTexture("hi.png");
    }
    void draw(){
        glClear(GL_COLOR_BUFFER_BIT);
        glBindTexture(GL_TEXTURE_2D,tex);
        glBegin(GL_QUADS);
            glTexCoord2f(0,0);
            glVertex2f(0,0);
            glTexCoord2f(1,0);
            glVertex2f(500,0);
            glTexCoord2f(1,1);
            glVertex2f(500,500);
            glTexCoord2f(0,1);
            glVertex2f(0,500);
        glEnd();
        glFlush();
    }
    int main(int argc,char** argv){
        SDL_Init(SDL_INIT_EVERYTHING);
        SDL_Surface* screen=SDL_SetVideoMode(800,600,32,SDL_SWSURFACE|SDL_OPENGL);
        bool running=true;
        Uint32 start;
        SDL_Event event;
        init();
        while(running){
            start=SDL_GetTicks();
            draw();
            while(SDL_PollEvent(&event)){
                switch(event.type){
                    case SDL_QUIT:
                        running=false;
                        break;
                }
            }
            SDL_GL_SwapBuffers();
            if(1000/60>(SDL_GetTicks()-start))
                SDL_Delay(1000/60-(SDL_GetTicks()-start));
        }
        SDL_Quit();
        return 0;
    }

私は2Dの経験がなく、約1週間前にSDLをいじり始めました。レイヤー上にある画像を持つ単純な構造をいくつか構築し、独自の描画順序を設定できるようにしたため、スプライトは背景などの後に描画され、小さな「スプライトエンジン」が実行されました。ロックマンスプライトを900x900の単純な背景画像の上に、思い通りに左右に歩いてもらいました。

実は、i5でCPUがほぼ20%に達したので、グラフィックカードを使用して描画を行うことを考えました!OpenGLに少し掘り下げて、今日、ようやくgl3wを動作させることができました!

そこで、OpenGLを使用してウィンドウにスプライト/イメージを表示する簡単な方法を探しています。私が遭遇したあらゆる種類のコードを試してみましたが、基本的にどこでもエラーチェックを実行したにもかかわらず、何も表示されず、すべてが正しくチェックアウトされているようです!

TL:DR; 2D画像を描画する方法について、SDLを使用していくつかの簡単な作業コードを探していました(これが機能しない場合は、間違いがあります)。

ありがとう!


1
組み込みのビットブリット関数を使用していますか、それとも自分でスプライトを描画していますか?それは大きな違いを生むことができます!
Ali1S232 2013年

パフォーマンスがひどいゲームでSDL_Blit()を使用しています
GigaBass

どういう意味かわかりますか?自分でスプライトを描画することは何ですか?
GigaBass 2013年

バッファにピクセルを設定
Ali1S232

その場合は、SDLが直接提供するBLITSのみを使用しています。
GigaBass 2013年

回答:


7

私はSOILを使用してスプライトをロードし、テクスチャのあるクワッドを描画するだけでレンダリングすることをお勧めします。非推奨の機能を使用せずにそれを行う場合(シェーダーを使用)、非常に高速であることがわかります。


私はライブラリをざっと見てみましたが、それはいいですね。SOILの使用に関する非常に小さなサンプルコードを提供してもらえますか?シンプルな画像を出力する例は素晴らしいでしょう!ありがとう
GigaBass

そこに画像をロードするためのリンク上のコードスニペットは、あなたがそれはあなたに依存しますレンダリング方法。ですが、あなたはそれを「正しい方法」を行いたい場合は、あなたのような何かに従うことになるでしょう、これを。残念ながら、シェーダーなどでOpenGLを設定することはそれほど迅速で簡単ではありませんが、特に一度に多くのスプライトを使用する場合は、その価値はあります。
エリックB

3

OpenGLでテクスチャクワッドを描画するためのかなり基本的ですが、すばらしい出発点です。この関数の開始点から、わずかに異なる機能を提供する7つの関数があり、色合いのある色で描画したり、アルファ値の異なるアイテムを描画したり、回転したりします。クリッピングなど。しかし、これはあなたが始めるのに役立つはずです:)。

編集:コードを更新。

void Draw(int x, int y, Image* texture, bool blendFlag) {
//Bind Texture
glBindTexture(GL_TEXTURE_2D, texture->getData());

if (blendFlag)
{
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GLfloat Vertices[] = {(float)x, (float)y, 0,
                    (float)x + texture->getWidth(), (float)y, 0,
                    (float)x + (float)texture->getWidth(), (float)y + (float)texture->getHeight(), 0,
                    (float)x, (float)y + (float)texture->getHeight(), 0};
GLfloat TexCoord[] = {0, 0,
    1, 0,
    1, 1,
    0, 1,
};
GLubyte indices[] = {0,1,2, // first triangle (bottom left - top left - top right)
                     0,2,3}; // second triangle (bottom left - top right - bottom right)

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, Vertices);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, TexCoord);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

if (blendFlag) glDisable(GL_BLEND);
}

画像は、テクスチャデータ(GLuint)と、幅と高さを保持する2つの整数を保持する基本構造です。


そのglBegin、glEndの種類のOpenGL関数は、最新の関数よりもかなり遅いので廃止されましたが、これは正しいですか?それでも、単純な2Dゲームの場合、これは、GPUが50%を超えることなく、必要なすべてのスプライトを取得するのに十分な量でしょうか?
GigaBass 2013年

はい、glDrawArraysを使用してすべての頂点データを一度に送信する方が良いでしょう。ただし、特に4つの頂点のみを処理する場合は、違いはかなり小さいと思います。
dan369

1000x1000ピクセルの画面に、500x500の画像を20フレームずつ、フレームごとに描画していたとしましょう。違いは顕著でしょうか?ちょうどそれがどれほど良いかを理解しています
GigaBass

いいえ、その場合は目立たないと思います。実際に問題が発生するまで、最適化についてあまり気にしないでください。その一般的な落とし穴。
dan369 2013年

私はCPUの20%を使用していることに気づき、すぐに何かを修正する必要があると思いました...友人のコンピューターのいくつかでは、通常の速度で実行できませんでした!
GigaBass 2013年

0

SDLは必要ですか?SFMLは、レンダリングにOpenGLを使用するSDLの代替です。オブジェクト指向のAPIにより、初心者にとっても簡単な場合もあります。


あなたの答えが彼の問題を解決していないため、反対票を投じます。彼はOpenGLの操作方法を知りたいと思っています。彼は代替ソリューションに使用していません。
Ali1S232 2013年

ええ、私はSDLからSFMLへの移行を避けたかったのですが、かなりそれが好きです... SFMLがOpenGLをレンダリングに使用して、SDLがブリットでできる簡単な描画を実行できることを意味しますか?それは実際には非常に良いでしょう。
GigaBass 2013年

2
@ user1896797:はい、SFMLはすべてのグラフィックにOpenGLを使用します。
szotp 2013年

それはあなたが言うように、それは素晴らしいです、私はそれにスピンを与えます!できれば賛成投票します!
GigaBass 2013年

確かに、OpenGLを実際に使用しています。質問に答える必要があるという理由だけで、あなたのものを受け入れることはできません。しかし、本当にありがとう!
GigaBass 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.