不为 OpenGL ES 3 + SDL2 + ANGLE + MSVC 绘制任何内容

问题描述 投票:0回答:1

我在遵循旨在教授如何在 Windows 桌面环境中主要使用 OpenGL ES 3.x 的教程后遇到问题。

如我的问题标题所述,我正在使用 MSVC、SDL2 进行编码,并将我的程序链接到 ANGLE 的库以模拟 OpenGL ES 3。

下面的代码旨在绘制一个简单的三角形,但根本没有绘制任何东西。事实上,我唯一能做的就是设置清除颜色并清除颜色缓冲区。

我进行的任何 gl* 函数调用之后都没有出现任何错误。此外,这些函数都是使用 sdl get proc address 功能加载的。

这里是作为入口点的初始化代码(sdl窗口和opengl上下文):

#include <SDL.h>
#include <cstdlib>

#include "../tuto_1/tuto_1.hpp"
#include "../tuto_2/tuto_2.hpp"

const unsigned int DISP_WIDTH = 640;
const unsigned int DISP_HEIGHT = 480;

auto SDL_main(int, char* []) -> int
{
    SDL_Window* window = nullptr;
    SDL_GLContext context = nullptr;

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        SDL_Log("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());

        return EXIT_FAILURE;
    }

    atexit(SDL_Quit);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    window = SDL_CreateWindow("OpenGL ES 3 + SDL2 tutorial",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        DISP_WIDTH, DISP_HEIGHT,
        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    if (window == nullptr)
    {
        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
            "Error",
            "Could not create the main window",
            nullptr);

        return EXIT_FAILURE;
    }

    context = SDL_GL_CreateContext(window);

    if (context == nullptr)
    {
        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
            "Error",
            "Could not create an OpenGL context",
            nullptr);

        return EXIT_FAILURE;
    }

    return tuto_1(window),
        tuto_2(window);
}

此代码启动上下文并以某种方式

invoke
tuto_1 和 tuto_2 函数。

tuto_1 很好,因为它只是改变背景的问题,效果很好。

下面是tuto_2.cpp的代码,根本不会画任何东西:

#include "tuto_2.hpp"
#include "shader.hpp"
#include "vbo.hpp"

#include <cstdlib>
#include <SDL.h>

struct Vertex
{
    float position[2];
};

auto tuto_2(SDL_Window* const window) -> int
{
    GLuint shaderProg = shaderProgLoad("Simple2D.vert", "Simple2D.frag");

    if (shaderProg == 0)
        return EXIT_FAILURE;

    auto glUseProgram = reinterpret_cast<PFNGLUSEPROGRAMPROC>(SDL_GL_GetProcAddress("glUseProgram"));

    if (glUseProgram == nullptr)
    {
        SDL_Log("Could not load the glUseProgram function");

        return EXIT_FAILURE;
    }

    glUseProgram(shaderProg);

    auto glGetIntegerv = reinterpret_cast<PFNGLGETINTEGERVPROC>(SDL_GL_GetProcAddress("glGetIntegerv"));

    if (glGetIntegerv == nullptr)
    {
        SDL_Log("Could not load the glGetIntegerv function");

        return EXIT_FAILURE;
    }

    GLint program;
    glGetIntegerv(GL_CURRENT_PROGRAM, &program);

    if (program == 0)
    {
        SDL_Log("Could not get the current program or no program in use");

        return EXIT_FAILURE;
    }

    const Vertex vertices[] =
    {
        { .0f , -.9f },
        { .9f , .9f },
        { -.9f, .9f }
    };

    GLsizei vertSize = sizeof(vertices[0]);
    GLsizei numVertices = sizeof(vertices) / vertSize;

    GLuint triangleVBO = vboCreate(vertices, numVertices);

    if (triangleVBO == 0)
    {
        shaderProgDestroy(shaderProg);

        return EXIT_FAILURE;
    }

    const GLuint positionIdx = 0;

    // auto glBindBuffer = reinterpret_cast<PFNGLBINDBUFFERPROC>(SDL_GL_GetProcAddress("glBindBuffer"));

    // if (glBindBuffer == nullptr)
    // {
    //  SDL_Log("Could not load the glBindBuffer function");

    //  return EXIT_FAILURE;
    // }

    // glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);

    auto glVertexAttribPointer = reinterpret_cast<PFNGLVERTEXATTRIBPOINTERPROC>(SDL_GL_GetProcAddress("glVertexAttribPointer"));

    if (glVertexAttribPointer == nullptr)
    {
        SDL_Log("Could not load the glVertexAttribPointer function");

        return EXIT_FAILURE;
    }

    auto glGetError = reinterpret_cast<PFNGLGETERRORPROC>(SDL_GL_GetProcAddress("glGetError"));

    if (glGetError == nullptr)
    {
        SDL_Log("Could not load the glGetError function");

        return EXIT_FAILURE;
    }

    glVertexAttribPointer(positionIdx, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), static_cast<const void*>(0));
    const auto vertexAttribPointerError = glGetError();

    if (vertexAttribPointerError != GL_NO_ERROR)
    {
        SDL_Log("Error while setting up vertex attribute pointers");

        return EXIT_FAILURE;
    }

    auto glEnableVertexAttribArray = reinterpret_cast<PFNGLENABLEVERTEXATTRIBARRAYPROC>(SDL_GL_GetProcAddress("glEnableVertexAttribArray"));

    if (glEnableVertexAttribArray == nullptr)
    {
        SDL_Log("Could not load the glEnableVertexAttribArray function");

        return EXIT_FAILURE;
    }

    glEnableVertexAttribArray(positionIdx);
    const auto enableVertexAttribPointerError = glGetError();

    if (enableVertexAttribPointerError != GL_NO_ERROR)
    {
        SDL_Log("Error while enabling vertex attribute pointers");

        return EXIT_FAILURE;
    }

    auto glDrawArrays = reinterpret_cast<PFNGLDRAWARRAYSPROC>(SDL_GL_GetProcAddress("glDrawArrays"));

    if (glDrawArrays == nullptr)
    {
        SDL_Log("Could not load the glDrawArrays function");

        return EXIT_FAILURE;
    }
    auto glClear = reinterpret_cast<PFNGLCLEARPROC>(SDL_GL_GetProcAddress("glClear"));

    if (glClear == nullptr)
    {
        SDL_Log("Could not load the glClear function");

        return EXIT_FAILURE;
    }

    bool quit = false;

    while (!quit)
    {
        SDL_Event event;

        if (SDL_WaitEvent(&event) != 0)
        {
            if (event.type == SDL_QUIT)
            {
                vboFree(triangleVBO);
                shaderProgDestroy(shaderProg);
                quit = true;
            }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, numVertices);
        const auto drawArraysError = glGetError();

        if (drawArraysError != GL_NO_ERROR)
        {
            SDL_Log("Error while drawing arrays");

            return EXIT_FAILURE;
        }

        SDL_GL_SwapWindow(window);
    }

    return EXIT_SUCCESS;
}

static GLuint vboCreate(const Vertex* vertices, GLuint numVertices)
{
    GLuint vbo;
    const unsigned int nBuffer = 1;

    auto glGenBuffers = reinterpret_cast<PFNGLGENBUFFERSPROC>(SDL_GL_GetProcAddress("glGenBuffers"));

    if (glGenBuffers == nullptr)
    {
        SDL_Log("Could not load the glGenBuffer function");

        return 0;
    }

    glGenBuffers(nBuffer, &vbo);

    auto glBindBuffer = reinterpret_cast<PFNGLBINDBUFFERPROC>(SDL_GL_GetProcAddress("glBindBuffer"));

    if (glBindBuffer == nullptr)
    {
        SDL_Log("Could not load the glBindBuffer function");

        return 0;
    }

    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    auto glBufferData = reinterpret_cast<PFNGLBUFFERDATAPROC>(SDL_GL_GetProcAddress("glBufferData"));

    if (glBufferData == nullptr)
    {
        SDL_Log("Could not load the glBufferData function");

        return 0;
    }

    auto glGetError = reinterpret_cast<PFNGLGETERRORPROC>(SDL_GL_GetProcAddress("glGetError"));

    if (glGetError == nullptr)
    {
        SDL_Log("Could not load the glGetError function");

        return 0;
    }

    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), vertices, GL_STATIC_DRAW);
    GLenum err = glGetError();

    if (err != GL_NO_ERROR)
    {
        SDL_Log("Could not create an array buffer. Error: `%u`\n", err);

        vboFree(vbo);

        vbo = 0;
    }

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    return vbo;
}

static void vboFree(GLuint vbo)
{
    auto glDeleteBuffers = reinterpret_cast<PFNGLDELETEBUFFERSPROC>(SDL_GL_GetProcAddress("glDeleteBuffers"));

    if (glDeleteBuffers == nullptr)
    {
        SDL_Log("Could not load the glDeleteBuffers function");

        return;
    }

    glDeleteBuffers(1, &vbo);
}

这段代码也依赖shader.hpp来创建一个顶点和一个片段着色器:

#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif

#include "shader.hpp"

#include <memory>
#include <cstdio>
#include <cstdlib>
#include <SDL.h>
#include <SDL_opengles2.h>
#include <GLES3/gl3.h>
#include <filesystem>

static size_t fileGetlength(FILE* file)
{
    size_t length;
    long curPos = ftell(file);

    fseek(file, curPos, SEEK_END);

    length = ftell(file);

    fseek(file, curPos, SEEK_SET);

    return length;
}

static void shaderDestroy(GLuint shader)
{
    auto glDeleteShader = reinterpret_cast<PFNGLDELETESHADERPROC>(SDL_GL_GetProcAddress("glDeleteShader"));

    if (glDeleteShader == nullptr)
    {
        SDL_Log("Can't load the glDeleteShader function");

        return;
    }

    glDeleteShader(shader);
}

static GLuint shaderLoad(const char* fileName, GLenum shaderType)
{
    const auto exe_base_path = SDL_GetBasePath();
    const auto filePath = std::filesystem::absolute(std::filesystem::path{ exe_base_path } / fileName);

    FILE* file = fopen(filePath.string().c_str(), "r");

    if (file == nullptr)
    {
        SDL_Log("Can't open file `%s`", fileName);

        return 0;
    }

    size_t length = fileGetlength(file);

    auto shaderSrc = std::make_unique < GLchar[] >(length + 1);

    fread(shaderSrc.get(), 1, length, file);

    fclose(file);

    auto glCreateShader = reinterpret_cast<PFNGLCREATESHADERPROC>(SDL_GL_GetProcAddress("glCreateShader"));

    if (glCreateShader == nullptr)
    {
        SDL_Log("Can't load the glCreateShader function");

        return 0;
    }

    GLuint shader = glCreateShader(shaderType);

    auto glShaderSource = reinterpret_cast<PFNGLSHADERSOURCEPROC>(SDL_GL_GetProcAddress("glShaderSource"));

    if (glCreateShader == nullptr)
    {
        SDL_Log("Can't load the glShaderSource function");

        return 0;
    }

    const auto* const v = shaderSrc.get();
    const auto* const pv = &v;
    glShaderSource(shader, 1, pv, nullptr);

    auto glCompileShader = reinterpret_cast<PFNGLCOMPILESHADERPROC>(SDL_GL_GetProcAddress("glCompileShader"));

    if (glCompileShader == nullptr)
    {
        SDL_Log("Can't load the glCompileShader function");

        return 0;
    }

    glCompileShader(shader);

    auto glGetShaderiv = reinterpret_cast<PFNGLGETSHADERIVPROC>(SDL_GL_GetProcAddress("glGetShaderiv"));

    if (glGetShaderiv == nullptr)
    {
        SDL_Log("Can't load the glGetShaderiv function");

        return 0;
    }

    GLint compileSucceeded = GL_FALSE;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSucceeded);

    if (!compileSucceeded)
    {
        SDL_Log("Error while compiling the `%s` shader file\n", fileName);

        GLint logLength = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);

        auto errLog = std::make_unique<GLchar[]>(logLength);

        auto glGetShaderInfoLog = reinterpret_cast<PFNGLGETSHADERINFOLOGPROC>(SDL_GL_GetProcAddress("glGetShaderInfoLog"));

        if (glGetShaderInfoLog == nullptr)
        {
            SDL_Log("Can't load the glGetShaderInfoLog function");

            return 0;
        }

        if (errLog)
        {
            glGetShaderInfoLog(shader, logLength, &logLength, errLog.get());

            SDL_Log("shader info log: `%s`", errLog.get());
        }

        shaderDestroy(shader);

        return 0;
    }

    return shader;
}

GLuint shaderProgLoad(const char* vertFileName, const char* fragFileName)
{
    GLuint vertShader = shaderLoad(vertFileName, GL_VERTEX_SHADER);

    if (vertShader == 0)
    {
        SDL_Log("Cannot load the `%s` vertex shader file", vertFileName);

        return 0;
    }

    GLuint fragShader = shaderLoad(fragFileName, GL_FRAGMENT_SHADER);

    if (fragShader == 0)
    {
        SDL_Log("Cannot load the `%s` fragment shader file", vertFileName);

        shaderDestroy(vertShader);

        return 0;
    }

    auto glCreateProgram = reinterpret_cast<PFNGLCREATEPROGRAMPROC>(SDL_GL_GetProcAddress("glCreateProgram"));

    if (glCreateProgram == nullptr)
    {
        SDL_Log("Could not load the glCreateProgram function");

        return 0;
    }

    auto shaderProg = glCreateProgram();

    if (!shaderProg)
    {
        SDL_Log("Could not create a shader program");

        return 0;
    }

    auto glAttachShader = reinterpret_cast<PFNGLATTACHSHADERPROC>(SDL_GL_GetProcAddress("glAttachShader"));

    if (glAttachShader == nullptr)
    {
        SDL_Log("Could not load the glAttachShader function");

        return 0;
    }

    glAttachShader(shaderProg, vertShader);
    glAttachShader(shaderProg, fragShader);

    auto glLinkProgram = reinterpret_cast<PFNGLLINKPROGRAMPROC>(SDL_GL_GetProcAddress("glLinkProgram"));

    if (glLinkProgram == nullptr)
    {
        SDL_Log("Could not load the glLinkProgram function");

        return 0;
    }

    glLinkProgram(shaderProg);

    GLint linkingSucceeded = GL_FALSE;

    auto glGetProgramiv = reinterpret_cast<PFNGLGETPROGRAMIVPROC>(SDL_GL_GetProcAddress("glGetProgramiv"));

    if (glGetProgramiv == nullptr)
    {
        SDL_Log("Could not load the glGetProgramiv function");

        return 0;
    }

    glGetProgramiv(shaderProg, GL_LINK_STATUS, &linkingSucceeded);

    if (!linkingSucceeded)
    {
        SDL_Log("Shader program linking failed. (vertex shader: %s, fragment shader: %s\n)", vertFileName, fragFileName);

        GLint logLength = 0;
        glGetProgramiv(shaderProg, GL_INFO_LOG_LENGTH, &logLength);

        auto glGetProgramInfoLog = reinterpret_cast<PFNGLGETPROGRAMINFOLOGPROC>(SDL_GL_GetProcAddress("glGetProgramInfoLog"));

        if (glGetProgramInfoLog == nullptr)
        {
            SDL_Log("Could not load the glGetProgramInfoLog function");

            return 0;
        }

        auto errLog = std::make_unique<GLchar[]>(logLength + 1);
        glGetProgramInfoLog(shaderProg, logLength, &logLength, errLog.get());

        SDL_Log("Shader linking error: `%s`", errLog.get());
    }

    shaderDestroy(vertShader);
    shaderDestroy(fragShader);

    return shaderProg;
}

void shaderProgDestroy(GLuint shaderProg)
{
    auto glDeleteProgram = reinterpret_cast<PFNGLDELETEPROGRAMPROC>(SDL_GL_GetProcAddress("glDeleteProgram"));

    if (glDeleteProgram == nullptr)
    {
        SDL_Log("Could not load the glDeleteProgram function");

        return;
    }

    glDeleteProgram(shaderProg);
}

下面是片段着色器:

#version 300 es

#ifdef GL_ES
precision highp float;
#endif

in vec4 colour;
out vec4 fragColour;

void main()
{
  fragColour = colour;
}

这是顶点着色器:

#version 300 es

in vec2 vertPos;
out vec4 colour;

const vec4 white = vec4(1.0);

void main()
{
  colour = white;

  gl_Position = vec4(vertPos, 0.0, 1.0);
}

我不知道为什么屏幕上没有画任何东西,尽管背景颜色设置正确。

我最初认为问题可能出在 ANGLE 库上,所以我改为使用我的显卡供应商库进行链接,但没有发生任何变化。

最初我也有问题,即使是 tuto_1 中的背景颜色。该问题与直接使用标头中公开的 glClear 有关。我不得不使用

SDL_GL_GetProcAddress
动态加载此功能,问题就消失了。

我没有发现从 tuto_2 的标头中公开的更多直接函数调用,我认为问题不是基于此。


编辑1

如果重要的话,我可以创建一个公共的 github 存储库,其中包含完整的代码以及帮助设置的自述文件。如果您对这样的事情感兴趣,请在评论中告诉我。

我也忘了注明本教程的出处:GLES3-and-SDL2-Turorials.pdf

但是,代码很旧,完全损坏,需要我修复很多东西才能使其正常运行。我按原样提供此链接,以提供更多上下文。


编辑2

我更新了问题中的代码,添加了一个缺少的 glEnableVertexAttrib 调用和一堆 glGetError 调用。

没有捕获到错误,顶点属性启用不会改变任何东西。

我还确保在调用 glUseProgram 后着色器程序正在使用

c++ visual-c++ sdl-2 opengl-es-3.0 google-angle
1个回答
0
投票

取消注释第二个代码块中的代码解决了我的问题。我必须调用 glBindBuffer 以确保 OpenGL 对 glVertexAttribPointer() 的后续调用 应该使用 triangleVBO。 我最初认为只有在将数据从应用程序复制到 GPU 时才需要绑定缓冲区。

© www.soinside.com 2019 - 2024. All rights reserved.