OpenGL以编程方式创建纹理

时间:2018-03-07 11:18:04

标签: c++ opengl glsl sdl-2

使用OpenGL核心配置文件,我正在尝试创建一个填充屏幕的纹理,并在纹理中间显示一个白色方块。

#include <SDL2/SDL.h>
#include "glad/glad.h"

#define SIMPLE_VERTEX_SHADER "#version 330 core \n \
layout (location = 0) in vec3 aPos; \n \
layout (location = 1) in vec2 aTexCoord; \n \
out vec2 TexCoord; \n \
void main() { \n \
    gl_Position = vec4(aPos, 1.0f); \n \
    TexCoord = vec2(aTexCoord.x, aTexCoord.y); \n \
}\n\0"

#define SIMPLE_FRAGMENT_SHADER "#version 330 core \n \
out vec4 FragColor; \n \
in vec3 ourColor; \n \
in vec2 TexCoord; \n \
uniform sampler2D tex; \n \
void main() { \n \
    FragColor = texture(tex, TexCoord); \n \
}\n\0"

int main(int argv, char** args) {
    SDL_Window *window;
    SDL_GLContext glcontext;

    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Unable to initialise SDL: %s\n", SDL_GetError());
        SDL_Quit();
        exit(1);
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    int screen_width, screen_height;
    screen_height = screen_width = 500;

    window = SDL_CreateWindow("Texture Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!window) {
        printf("Unable to create window: %s\n", SDL_GetError());
        SDL_Quit();
        exit(1);
    }

    glcontext = SDL_GL_CreateContext(window);

    SDL_GL_SetSwapInterval(1);


    if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
    {
        printf("Failed to initialize GLAD\n");
    }

    const GLchar* vertexShaderSource = SIMPLE_VERTEX_SHADER;

    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
    }

    const GLchar* fragmentShaderSource = SIMPLE_FRAGMENT_SHADER;

    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
    }

    GLuint shaderProgram;

    shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    GLfloat vertices[] = {
            1.0f, 1.0f, 0.0f, 1.0, 0.0f,
            1.0f, -1.0f, 0.0f, 1.0, 1.0f,
            -1.0f, -1.0f, 0.0f, 0.0, 1.0f,
            -1.0f, 1.0f, 0.0f, 0.0, 0.0f
    };

    GLfloat indices[] = {
            0, 1, 3,
            1, 2, 3
    };

    bool running;
    running = true;
    GLuint VAO, VBO, EBO;
    SDL_Surface* surface;
    SDL_Event e;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);

    GLuint texture;

    glGenTextures(1, &texture);
    surface = SDL_CreateRGBSurface(0, screen_width, screen_height, 32, 0, 0, 0, 0);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    SDL_GL_SwapWindow(window);


    while(running) {
        while(SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                running = false;
            }
            if (e.type == SDL_KEYDOWN)
            {
                switch (e.key.keysym.sym)
                {
                    case SDLK_ESCAPE:
                        running = false;
                        break;
                    default:
                        break;
                }
            }
        }

        if (SDL_MUSTLOCK(surface)) {
            SDL_LockSurface(surface);
        }
        uint8_t* pixel_data = (uint8_t*)surface->pixels;
        for (int y = screen_height * 0.25; y < screen_height * 0.75; ++y) {
            for (int x = screen_width * 0.25; x < screen_width * 0.75; ++x) {
                pixel_data[4 * (y * surface -> w + x) + 0] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 1] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 2] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 3] = 0xFF;
            }
        }
        if (SDL_MUSTLOCK(surface)) {
            SDL_UnlockSurface(surface);
        }

        glBindTexture(GL_TEXTURE_2D, texture);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glBindTexture(GL_TEXTURE_2D, 0);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        glUniform1i(glGetUniformLocation(shaderProgram, "tex"), 0);

        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glUseProgram(0);

        SDL_GL_SwapWindow(window) ;
    }

    SDL_GL_DeleteContext(glcontext);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

打开时显示白色屏幕(好像我将清晰颜色设置为白色),然后几乎立即变为黑屏,然后保持这样。

我显然做错了什么,但我无法解决问题。我觉得我的着色器是问题所在。但我不确定。

是否有人能够指出我做错了什么?

感谢。

2 个答案:

答案 0 :(得分:0)

我在评论中添加了一个基于keltar答案的答案,将这个问题从未答复的标签中删除。如果凯尔塔答案我将删除我的答案。

问题是顶点属性在行中被限定为浮点数:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

但是纹理期望无符号字节:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);

因此,更改顶点属性可以解决问题。

答案 1 :(得分:0)

指数定义为

GLfloat indices[] = {
        0, 1, 3,
        1, 2, 3
};

但是,索引必须是整数。后来在绘图时,据说索引是GLuint:

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

并且浮点位被解释为uint,给出无效值,如1065353216,1077936128,...,这大大超过顶点缓冲区大小。

将索引定义为GLuint(或uint32_t)。