我在遵循旨在教授如何在 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 后着色器程序正在使用
取消注释第二个代码块中的代码解决了我的问题。我必须调用 glBindBuffer 以确保 OpenGL 对 glVertexAttribPointer() 的后续调用 应该使用 triangleVBO。 我最初认为只有在将数据从应用程序复制到 GPU 时才需要绑定缓冲区。