OpenGL程序调试输出

简介: OpenGL程序调试输出 前言:调试输出是OpenGL4.3版本中增加的一种用于调试的扩展工具。它不仅比glGetError接口提供更多的错误信息,而且还允许通过debugger去定位错误源。 创建调试环境:环境的创建是与平台相关的任务,一般由各种封装库提供接口进行创建。

OpenGL程序调试输出

前言:调试输出是OpenGL4.3版本中增加的一种用于调试的扩展工具。它不仅比glGetError接口提供更多的错误信息,而且还允许通过debugger去定位错误源。

创建调试环境:环境的创建是与平台相关的任务,一般由各种封装库提供接口进行创建。常见的创建方式如下:
1.GLFW创建方式:需要在创建OpenGL环境之前进行调试环境的创建。创建代码如下所示:

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
1
2.WGL创建方式:需要在创建OpenGL环境之后进行调试环境的创建。创建代码如下:

HGLRC CreateDebugContext(HDC hDC, HGLRC hShareContext, int major, int minor)
{
const int attriblist[] = 
{
// 环境的主版本
WGL_CONTEXT_MAJOR_VERSION_ARB, major,
// 环境的次版本
WGL_CONTEXT_MINOR_VERSION_ARB, mior,
// 总是选择核心优化
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
// 打开调试环境
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
0
};
return wglCreateContextAttribsARB(hDC, hShareContext, attriblist);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3.GLX创建方式:无需先创建OpenGL环境就可以进行调试环境创建。创建代码如下:

GLXContext CreateDebugContext(Display* dpy, GLXFBConfig* config, GLXContext shareContext, int major, int minor)
{
const int attriblist[] = 
{
// 环境的主版本
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
// 环境的次版本
GLX_CONTEXT_MINOR_VERSION_ARB, mior,
// 总是选择核心优化
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
// 打开调试环境
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
0
};
return glXCreateContextAttribsARB(dpy, config, shareContext, attriblist);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
检查调试环境:要检查是否成功地初始化了调试环境,我们可以对OpenGL进行查询。检查代码如下所示:

GLint flags; 
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
    // TODO 初始化调试输出成功
}
1
2
3
4
5
6
开关调试消息:传递调试消息默认是启动的,当然我们也可以禁止。通常使用GL_DEBUG_OUTPUT或者GL_DEBUG_OUTPUT_SYNCHRONOUS来调用glEnable接口进行启用,或者调用glDisable接口来进行禁用。

传递调试消息:调试环境存在两种方式将获取的调试消息传递给开发者。第一种方式就是设置回调函数。第二种方式就是通过远程渲染方式利用调试环境获取调试消息日志。
常用接口如下:
1.void glDebugMessageCallback(DEBUGPROC callback, void* userParam):设置一个新的调试消息回调函数callback给调试环境。当调试消息生成的时候就会触发这个回调函数,并将调试消息以及用户自定义参数userParam传递给回调函数callback。
其中DEBUGPROC声明如下所示:
void DEBUGPROC(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, void *userParam):
.source表示消息来源。通常是GL_DEBUG_SOURCE_API(OpenGL API),GL_DEBUG_SOURCE_WINDOW_SYSTEM(窗口系统),GL_DEBUG_SOURCE_SHADER_COMPILER(着色器编译器),GL_DEBUG_SOURCE_THIRD_PARTY(第三方库),GL_DEBUG_SOURCE_APPLICATION(应用程序),GL_DEBUG_SOURCE_OTHER(其他)当中的一种。
.type表示消息类型。通常是GL_DEBUG_TYPE_ERROR(错误生成),GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR(过时功能),GL_DEBUG_TYPE_UNSINGNED_BEHAVIOR(未定义功能),GL_DEBUG_TYPE_PERFORMANCE(性能不优),GL_DEBUG_TYPE_PORTABILITY(不能移植),GL_DEBUG_TYPE_MARKER(注解),GL_DEBUG_TYPE_PUSH_GROUP(调用glPushDebugGroup),GL_DEBUG_TYPE_POP_GROUP(调用glPopDebugGroup),GL_DEBUG_TYPE_OTHER(其他)当中的一种。
.id表示消息标志。
.severity表示消息等级。通常是GL_DEBUG_SEVERITY_HIGH(致命消息。如:OpneGL错误,着色器编译失败等),GL_DEBUG_SEVERITY_MEDIUM(不致命消息。如:移植性能警告),GL_DEBUG_SEVERITY_LOW(没危害消息。如:冗余的状态切换),GL_DEBUG_SEVERITY_NOTIFICATION(普通通知消息)当中的一种。
.message表示调试消息。
.userParam表示用户自定义参数。与设置回调时传入的自定义参数相关联。

有了这一大堆的数据,我们可以创建一个非常有用的错误打印工具。代码如下所示:

void glDebugOutput(GLenum source, 
                            GLenum type, 
                            GLuint id, 
                            GLenum severity, 
                            GLsizei length, 
                            const GLchar *message, 
                            void *userParam)
{
    // 忽略一些不重要的错误/警告代码
    if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return; 

    std::cout << "---------------" << std::endl;
    std::cout << "Debug message (" << id << "): " <<  message << std::endl;

    switch (source)
    {
        case GL_DEBUG_SOURCE_API:             std::cout << "Source: API"; break;
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM:   std::cout << "Source: Window System"; break;
        case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cout << "Source: Shader Compiler"; break;
        case GL_DEBUG_SOURCE_THIRD_PARTY:     std::cout << "Source: Third Party"; break;
        case GL_DEBUG_SOURCE_APPLICATION:     std::cout << "Source: Application"; break;
        case GL_DEBUG_SOURCE_OTHER:           std::cout << "Source: Other"; break;
    } std::cout << std::endl;

    switch (type)
    {
        case GL_DEBUG_TYPE_ERROR:               std::cout << "Type: Error"; break;
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cout << "Type: Deprecated Behaviour"; break;
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:  std::cout << "Type: Undefined Behaviour"; break; 
        case GL_DEBUG_TYPE_PORTABILITY:         std::cout << "Type: Portability"; break;
        case GL_DEBUG_TYPE_PERFORMANCE:         std::cout << "Type: Performance"; break;
        case GL_DEBUG_TYPE_MARKER:              std::cout << "Type: Marker"; break;
        case GL_DEBUG_TYPE_PUSH_GROUP:          std::cout << "Type: Push Group"; break;
        case GL_DEBUG_TYPE_POP_GROUP:           std::cout << "Type: Pop Group"; break;
        case GL_DEBUG_TYPE_OTHER:               std::cout << "Type: Other"; break;
    } std::cout << std::endl;

    switch (severity)
    {
        case GL_DEBUG_SEVERITY_HIGH:         std::cout << "Severity: high"; break;
        case GL_DEBUG_SEVERITY_MEDIUM:       std::cout << "Severity: medium"; break;
        case GL_DEBUG_SEVERITY_LOW:          std::cout << "Severity: low"; break;
        case GL_DEBUG_SEVERITY_NOTIFICATION: std::cout << "Severity: notification"; break;
    } std::cout << std::endl;
    std::cout << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
过滤调试消息:可以过滤出需要的调试消息。使用接口如下所示:
void glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled):
.source表示消息来源。
.type表示消息类型。
.severity表示消息等级。
.count表示消息标志符的数目。
.ids表示消息标志符的数组。
.enabled表示是否启用,为GL_FALSE时表示丢弃消息。

自定义调试消息:可以自定义调试消息传送给调试环境。使用接口如下:
void glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf):
.source表示消息来源。
.type表示消息类型。
.id表示消息标志。
.severity表示消息等级。
.length表示自定义消息的长度。
.buf表示自定义的消息内容。

调试组:就是用来存储调试状态的堆栈,且堆栈大小通常是64组,可以通过GL_MAX_DEBUG_GROUP_STACK_DEPTH参数来调用glGetIntegerv接口获取。常用接口如下:
1.void glPushDebugGroup(GLenum source, GLuint id, Glint length, const GLchar* message):将当前的调试状态压入OpenGL管理的堆栈。
.source限制为GL_DEBUG_SOURCE_APPLICATION或者GL_DEBUG_SOURCE_THIRD_PARTY。
.type限制为GL_DEBUG_TYPE_PUSH_GROUP。
.severity限制为GL_DEBUG_SEVERITY_NOTIFICATION。
.id表示消息标志。
.length表示消息长度。
.message表示消息内容。

2.void glPopDebugGroup(void):将当前堆栈上的调试状态弹出。

命名对象:就是对OpenGL管理的对象标志关联一个名称,从而可以使用名称来访问该对象。常用接口如下:
1.void glObjectLabel(GLenum identifier, GLuint name, Glsizei length, const GLchar* label):为OpenGL拥有的对象生成标签。
.identifier表示分配对象的名称空间。通常是GL_BUFFER,GL_SHADER,GL_PROGRAM等来源中的一种。
.name表示生成对象的唯一标识。
.length表示标签长度。
.label表示标签内容。

2.void glGetObjectLabel(GLenum identifier, GLuint name, Glsizei bufsize, Glsizei * length, GLchar* label):获取glObjectLabel接口分配的对象标签。
.identifier表示分配对象的名称空间。
.name表示生成对象的唯一标识。
.length表示标签长度。
.label表示标签内容。

3.void glObjectPtrLabel(void* ptr, Glsizei length, const GLchar* label):为OpenGL拥有的指针对象生成标签。
.ptr表示指针对象。
.length表示标签长度。
.label表示标签内容。

4.void glGetObjectPtrLabel(void* ptr, Glsizei bufsize, Glsizei* length, const GLchar* label):获取glObjectPtrLabel接口分配的对象标签。
.ptr表示指针对象。
.length表示标签长度。
.label表示标签内容。

回溯调试错误源:可以在调试消息回调函数中打断点,当调试消息生成并调用该回调时就会触发对应断点。可以从断点堆栈中找到OpenGL程序的执行过程,从而找出错误源。如图所示:


在线例子:以下提供一个包含调试输出的大部分接口的在线例子。

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <learnopengl/filesystem.h>
#include <learnopengl/shader.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;


GLenum glCheckError_(const char *file, int line)
{
    GLenum errorCode;
    while ((errorCode = glGetError()) != GL_NO_ERROR)
    {
        std::string error;
        switch (errorCode)
        {
            case GL_INVALID_ENUM:                  error = "INVALID_ENUM"; break;
            case GL_INVALID_VALUE:                 error = "INVALID_VALUE"; break;
            case GL_INVALID_OPERATION:             error = "INVALID_OPERATION"; break;
            case GL_STACK_OVERFLOW:                error = "STACK_OVERFLOW"; break;
            case GL_STACK_UNDERFLOW:               error = "STACK_UNDERFLOW"; break;
            case GL_OUT_OF_MEMORY:                 error = "OUT_OF_MEMORY"; break;
            case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
        }
        std::cout << error << " | " << file << " (" << line << ")" << std::endl;
    }
    return errorCode;
}
#define glCheckError() glCheckError_(__FILE__, __LINE__)

void APIENTRY glDebugOutput(GLenum source, 
                            GLenum type, 
                            GLuint id, 
                            GLenum severity, 
                            GLsizei length, 
                            const GLchar *message, 
                            const void *userParam)
{
    if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return; // ignore these non-significant error codes

    std::cout << "---------------" << std::endl;
    std::cout << "Debug message (" << id << "): " <<  message << std::endl;

    switch (source)
    {
        case GL_DEBUG_SOURCE_API:             std::cout << "Source: API"; break;
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM:   std::cout << "Source: Window System"; break;
        case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cout << "Source: Shader Compiler"; break;
        case GL_DEBUG_SOURCE_THIRD_PARTY:     std::cout << "Source: Third Party"; break;
        case GL_DEBUG_SOURCE_APPLICATION:     std::cout << "Source: Application"; break;
        case GL_DEBUG_SOURCE_OTHER:           std::cout << "Source: Other"; break;
    } std::cout << std::endl;

    switch (type)
    {
        case GL_DEBUG_TYPE_ERROR:               std::cout << "Type: Error"; break;
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cout << "Type: Deprecated Behaviour"; break;
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:  std::cout << "Type: Undefined Behaviour"; break; 
        case GL_DEBUG_TYPE_PORTABILITY:         std::cout << "Type: Portability"; break;
        case GL_DEBUG_TYPE_PERFORMANCE:         std::cout << "Type: Performance"; break;
        case GL_DEBUG_TYPE_MARKER:              std::cout << "Type: Marker"; break;
        case GL_DEBUG_TYPE_PUSH_GROUP:          std::cout << "Type: Push Group"; break;
        case GL_DEBUG_TYPE_POP_GROUP:           std::cout << "Type: Pop Group"; break;
        case GL_DEBUG_TYPE_OTHER:               std::cout << "Type: Other"; break;
    } std::cout << std::endl;
    
    switch (severity)
    {
        case GL_DEBUG_SEVERITY_HIGH:         std::cout << "Severity: high"; break;
        case GL_DEBUG_SEVERITY_MEDIUM:       std::cout << "Severity: medium"; break;
        case GL_DEBUG_SEVERITY_LOW:          std::cout << "Severity: low"; break;
        case GL_DEBUG_SEVERITY_NOTIFICATION: std::cout << "Severity: notification"; break;
    } std::cout << std::endl;
    std::cout << std::endl;
}

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); // comment this line in a release build! 

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    glfwMakeContextCurrent(window);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // tell GLFW to capture our mouse
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // enable OpenGL debug context if context allows for debug context
    GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
    if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
    {
        glEnable(GL_DEBUG_OUTPUT);
        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // makes sure errors are displayed synchronously
        glDebugMessageCallback(glDebugOutput, nullptr);
        glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
    }

    // configure global opengl state
    // -----------------------------
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
 
    // OpenGL initial state
    Shader shader("debugging.vs", "debugging.fs");

    // configure 3D cube
    GLuint cubeVAO, cubeVBO;
    GLfloat vertices[] = {
         // back face
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, // Bottom-left
         0.5f,  0.5f, -0.5f,  1.0f,  1.0f, // top-right
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f, // bottom-right         
         0.5f,  0.5f, -0.5f,  1.0f,  1.0f, // top-right
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, // bottom-left
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f, // top-left
         // front face
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, // bottom-left
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f, // bottom-right
         0.5f,  0.5f,  0.5f,  1.0f,  1.0f, // top-right
         0.5f,  0.5f,  0.5f,  1.0f,  1.0f, // top-right
        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f, // top-left
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, // bottom-left
         // left face
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f, // top-right
        -0.5f,  0.5f, -0.5f, -1.0f,  1.0f, // top-left
        -0.5f, -0.5f, -0.5f, -0.0f,  1.0f, // bottom-left
        -0.5f, -0.5f, -0.5f, -0.0f,  1.0f, // bottom-left
        -0.5f, -0.5f,  0.5f, -0.0f,  0.0f, // bottom-right
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f, // top-right
         // right face
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f, // top-left
         0.5f, -0.5f, -0.5f,  0.0f,  1.0f, // bottom-right
         0.5f,  0.5f, -0.5f,  1.0f,  1.0f, // top-right         
         0.5f, -0.5f, -0.5f,  0.0f,  1.0f, // bottom-right
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f, // top-left
         0.5f, -0.5f,  0.5f,  0.0f,  0.0f, // bottom-left     
         // bottom face
        -0.5f, -0.5f, -0.5f,  0.0f,  1.0f, // top-right
         0.5f, -0.5f, -0.5f,  1.0f,  1.0f, // top-left
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f, // bottom-left
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f, // bottom-left
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, // bottom-right
        -0.5f, -0.5f, -0.5f,  0.0f,  1.0f, // top-right
         // top face
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f, // top-left
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f, // bottom-right
         0.5f,  0.5f, -0.5f,  1.0f,  1.0f, // top-right     
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f, // bottom-right
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f, // top-left
        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f  // bottom-left        
    };
    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    // fill buffer
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // link vertex attributes
    glBindVertexArray(cubeVAO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // load cube texture
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    int width, height, nrComponents;
    unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/wood.png").c_str(), &width, &height, &nrComponents, 0);
    if (data)
    {
        glTexImage2D(GL_FRAMEBUFFER, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);

    // set up projection matrix
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 10.0f);
    glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
    glUniform1i(glGetUniformLocation(shader.ID, "tex"), 0);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shader.use();
        GLfloat rotationSpeed = 10.0f;
        GLfloat angle = (float)glfwGetTime() * rotationSpeed;
        glm::mat4 model;
        model = glm::translate(model, glm::vec3(0.0, 0.0f, -2.5));
        model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 1.0f, 1.0f));
        glUniformMatrix4fv(glGetUniformLocation(shader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));

        glBindTexture(GL_TEXTURE_2D, texture);
        glBindVertexArray(cubeVAO);
            glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

// renderQuad() renders a 1x1 XY quad in NDC
// -----------------------------------------
unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad()
{
    if (quadVAO == 0)
    {
        float quadVertices[] = {
            // positions        // texture Coords
            -1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
            1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
            1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
        };
        // setup plane VAO
        glGenVertexArrays(1, &quadVAO);
        glGenBuffers(1, &quadVBO);
        glBindVertexArray(quadVAO);
        glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    }
    glBindVertexArray(quadVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}
--------------------- 
作者:金朝 
来源:CSDN 
版权声明:本文为博主原创文章,转载请附上博文链接!
相关文章
|
1月前
|
存储 编解码 Windows
EasyX图形库学习(三、用easyX控制图形界面中的小球、图片-加载、输出)
EasyX图形库学习(三、用easyX控制图形界面中的小球、图片-加载、输出)
|
3月前
|
Python
Python 教程之控制流(6)打印金字塔图案的程序
Python 教程之控制流(6)打印金字塔图案的程序
36 0
|
10月前
|
存储 Linux C语言
嵌入式linux下的c语言简易日志log模块,带颜色显示(一)
嵌入式linux下的c语言简易日志log模块,带颜色显示(一)
codeblocks进行调试(debug)时查看二维数组的内容
codeblocks进行调试(debug)时查看二维数组的内容
codeblocks进行调试(debug)时查看二维数组的内容
|
Windows
【OpenGL】二十四、OpenGL 纹理贴图 ( 读取文件内容 | 桌面程序添加控制台窗口 | ‘fopen‘: This function may be unsafe 错误处理 )(二)
【OpenGL】二十四、OpenGL 纹理贴图 ( 读取文件内容 | 桌面程序添加控制台窗口 | ‘fopen‘: This function may be unsafe 错误处理 )(二)
120 0
【OpenGL】二十四、OpenGL 纹理贴图 ( 读取文件内容 | 桌面程序添加控制台窗口 | ‘fopen‘: This function may be unsafe 错误处理 )(二)
|
图形学 开发者
Unity Debug输出到屏幕并保存到本地
借鉴了往网上两位开发者的文章,自己整理了下http://www.gad.qq.com/lore/detail/10119http://blog.csdn.
1244 0
|
存储 缓存 JavaScript
《OpenGL编程指南(原书第9版)》——1.5 第一个程序:深入分析
本节书摘来自华章计算机《OpenGL编程指南(原书第9版)》一书中的第1章,第1.5节,作者:(美)约翰·克赛尼希(John Kessenich)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1927 0
《OpenGL编程指南(原书第9版)》——2.6 着色器子程序
本节书摘来自华章计算机《OpenGL编程指南(原书第9版)》一书中的第2章,第2.6节,作者:(美)约翰·克赛尼希(John Kessenich)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1249 0
|
监控 C语言
《OpenGL编程指南(原书第9版)》——2.5 着色器的编译
本节书摘来自华章计算机《OpenGL编程指南(原书第9版)》一书中的第2章,第2.5节,作者:(美)约翰·克赛尼希(John Kessenich)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1274 0