【问题标题】:OpenGL programmatically create textureOpenGL 以编程方式创建纹理
【发布时间】:2018-08-15 11:28:29
【问题描述】:

使用 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;
}

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

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

有人能指出我做错了什么吗?

谢谢。

【问题讨论】:

  • 你的程序显示什么?
  • 它打开时显示白屏(好像我将清除颜色设置为白色),然后几乎立即变为黑屏,然后保持不变。
  • @user2167177 你的索引定义为GLfloat 但draw 说它们是GL_UNSIGNED_INT。用于表面创建的位掩码也是错误的,我不确定它是否能保证工作。
  • @keltar 你是个超级明星。将我的索引更改为 GLuint 修复了它。如果你想写一个这样的答案,我会给你一个很大的答案。

标签: c++ opengl glsl sdl-2


【解决方案1】:

指数定义为

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

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

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

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

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

【讨论】:

    【解决方案2】:

    我将根据 keltar 在评论中的回答添加一个答案,以将此问题从未回答的选项卡中删除。如果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);
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多