Làm cách nào để vẽ hình ảnh 2D bằng OpenGL, trong SDL?


8

Sau tất cả mọi thứ, tôi đã tìm được một đoạn mã đơn giản chỉ ra cách vẽ hình ảnh 2D bằng openGL:

    #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;
    }

Tôi chưa có kinh nghiệm về 2D và khoảng một tuần trước đã bắt đầu nhắn tin với SDL. Xây dựng một số cấu trúc đơn giản để có hình ảnh, trên các lớp, vì vậy tôi có thể có thứ tự vẽ của riêng mình, vì vậy các họa tiết sẽ được vẽ sau nền, v.v., và sau đó thực hiện một "công cụ sprite" nhỏ. Tôi đã nhận được một Megaman sprite đi bên trái và bên phải giống như tôi muốn, trên một hình nền 900x900ish đơn giản.

Điều đáng nói là, CPU gần như đạt 20% trên i5 của tôi ... vì vậy tôi đã nghĩ đến việc sử dụng card đồ họa để thực hiện bản vẽ! Đã bỏ abit vào OpenGL và hôm nay, cuối cùng cũng có thể làm cho gl3w hoạt động!

Vì vậy, bây giờ tôi đang tìm kiếm một cách đơn giản để hiển thị các hình ảnh / hình ảnh của tôi, trên cửa sổ, thông qua việc sử dụng OpenGL. Tôi đã thử tất cả các loại mã tôi đã chạy, nhưng tôi không thể hiển thị bất cứ thứ gì, mặc dù về cơ bản tôi đã thực hiện kiểm tra lỗi và mọi thứ dường như đều đúng!

TL: DR; Tôi đang tìm kiếm một số mã làm việc đơn giản, sử dụng SDL, về cách vẽ hình ảnh 2D (mà nếu nó không hoạt động, chắc chắn tôi đã có gì đó không đúng).

Cảm ơn!


1
bạn đang sử dụng các hàm bitblit tích hợp hay bạn đang tự vẽ các họa tiết? nó có thể tạo ra một sự khác biệt lớn
Ali1S 232

Tôi chỉ đang sử dụng SDL_Blit (), trên trò chơi có hiệu suất khủng khiếp
GigaBass

Trên thực tế bạn có thể làm rõ những gì bạn có ý nghĩa? Tự mình vẽ họa tiết là gì?
GigaBass

cài đặt pixel trong bộ đệm
Ali1S232

Trong trường hợp đó, không, tôi chỉ sử dụng BLITS do SDL cung cấp trực tiếp.
GigaBass

Câu trả lời:


7

Tôi khuyên bạn nên tải các họa tiết của mình bằng SOIL , và sau đó kết xuất chúng bằng cách chỉ vẽ các hình tứ giác có kết cấu. Nếu bạn làm điều đó mà không có bất kỳ chức năng không dùng nữa (sử dụng shader), bạn sẽ thấy nó rất nhanh.


Tôi đã xem nhanh thư viện, và điều đó nghe có vẻ tốt. Bạn có thể cung cấp một mã ví dụ rất nhỏ về việc sử dụng SOIL không, một ví dụ xuất ra một hình ảnh đơn giản sẽ rất tuyệt! Cảm ơn
GigaBass

có các đoạn mã trên liên kết để tải hình ảnh vào. Cách bạn kết xuất nó sẽ phụ thuộc vào bạn, nhưng nếu bạn muốn làm điều đó "đúng cách", bạn sẽ muốn làm theo cách như thế này . Thật không may, thiết lập OpenGL với các shader, v.v. không quá nhanh và dễ dàng nhưng có lẽ đáng giá, đặc biệt là nếu bạn sẽ có rất nhiều sprite cùng một lúc.
Eric B

3

Đây là một điểm khởi đầu khá cơ bản nhưng tuyệt vời để vẽ các hình tứ giác có kết cấu trong OpenGL, từ điểm bắt đầu chức năng này, tôi có 7 chức năng khác cung cấp chức năng hơi khác nhau, để vẽ với các màu được tô màu, để vẽ các mục với các giá trị alpha khác nhau và sau đó chúng tôi có xoay cắt vv vv Nhưng điều này sẽ giúp bạn bắt đầu :).

Chỉnh sửa: Mã cập nhật;

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);
}

Hình ảnh là một cấu trúc cơ bản chứa dữ liệu kết cấu (GLuint) và sau đó hai số nguyên để giữ chiều rộng và chiều cao.


Tôi đã đọc xung quanh mặc dù glBegin, loại chức năng OpenGL đã bị phản đối vì chúng chậm hơn so với các chức năng cập nhật, điều này có đúng không? Tuy nhiên, đối với một trò chơi 2d đơn giản, điều này sẽ là quá đủ để có được tất cả các sprite tôi muốn mà không có gpu bao giờ vượt quá 50% phải không?
GigaBass

Đúng, tốt hơn là sử dụng glDrawArrays và gửi tất cả dữ liệu đỉnh trong một lần. Nhưng tôi cho rằng sự khác biệt là khá ít, đặc biệt là khi bạn chỉ giao dịch với 4 đỉnh.
dan369

Giả sử tôi đang vẽ 500x500 hình ảnh, 20 trong số chúng, mọi khung hình, trên màn hình 1000x1000 pixel? Sự khác biệt sẽ là đáng chú ý? Chỉ để tôi hiểu được nó tốt hơn bao nhiêu
GigaBass

Không, tôi không nghĩ rằng nó sẽ được chú ý trong trường hợp đó. Hãy nhớ rằng bạn không nên lo lắng quá nhiều về tối ưu hóa cho đến khi bạn thực sự gặp vấn đề. Đó là một cạm bẫy phổ biến.
dan369

Tôi đã bị sốc khi thấy rằng nó đã chiếm 20% CPU của tôi và ngay lập tức tôi nghĩ rằng tôi phải làm gì đó để sửa nó ... trên một số máy tính của bạn tôi, nó không thể chạy ở tốc độ bình thường!
GigaBass

0

SDL có cần thiết cho bạn không? SFML thay thế cho SDL sử dụng OpenGL để kết xuất. Nó cũng có thể dễ dàng hơn cho người mới bắt đầu, vì API hướng đối tượng.


downvote vì câu trả lời của bạn không giải quyết được vấn đề của anh ấy. Anh ấy muốn biết cách làm việc với OpenGL. Ông không sử dụng cho một giải pháp thay thế.
Ali1S 232

Vâng, tôi muốn tránh việc chuyển từ SDL sang SFML, tôi thích nó khá là ... quen với hoạt động của nó. Ý bạn là SFML có thể thực hiện bản vẽ dễ dàng SDL có thể làm với blits, sử dụng OpenGL để kết xuất? Điều đó thực sự sẽ rất tốt.
GigaBass

2
@ user1896797: Có SFML sử dụng OpenGL cho tất cả các công cụ đồ họa.
szotp

Thật tuyệt nếu như bạn nói, tôi sẽ cho nó một vòng quay! Sẽ upvote nếu tôi có thể!
GigaBass

Khẳng định, thực sự sử dụng OpenGL. Mặc dù không thể chấp nhận của bạn, chỉ vì câu trả lời phải liên quan đến câu hỏi. Nhưng một lời cảm ơn lớn!
GigaBass
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.