openGL API glDebugMessageControl详解

本文介绍OpenGL 4.3版本新增的调试工具——调试输出功能。详细解释如何创建调试环境、检查调试环境、开关及传递调试消息、过滤及自定义调试消息、使用调试组、命名对象以及回溯调试错误源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

               openGL API glDebugMessageControl详解

Name

glDebugMessageControl — control the reporting of debug messages in a debug context

C Specification

void glDebugMessageControl(GLenum source,
 GLenum type,
 GLenum severity,
 GLsizei count,
 const GLuint *ids,
 GLboolean enabled);

 

Parameters

source

The source of debug messages to enable or disable.

type

The type of debug messages to enable or disable.

severity

The severity of debug messages to enable or disable.

count

The length of the array ids.

ids

The address of an array of unsigned integers contianing the ids of the messages to enable or disable.

enabled

A Boolean flag determining whether the selected messages should be enabled or disabled.

Description

glDebugMessageControl controls the reporting of debug messages generated by a debug context. The parameters sourcetype and severity form a filter to select messages from the pool of potential messages generated by the GL.

source may be GL_DEBUG_SOURCE_APIGL_DEBUG_SOURCE_WINDOW_SYSTEM_GL_DEBUG_SOURCE_SHADER_COMPILERGL_DEBUG_SOURCE_THIRD_PARTYGL_DEBUG_SOURCE_APPLICATIONGL_DEBUG_SOURCE_OTHER to select messages generated by usage of the GL API, the window system, the shader compiler, third party tools or libraries, explicitly by the application or by some other source, respectively. It may also take the value GL_DONT_CARE. If source is not GL_DONT_CARE then only messages whose source matches source will be referenced.

type may be one of GL_DEBUG_TYPE_ERRORGL_DEBUG_TYPE_DEPRECATED_BEHAVIORGL_DEBUG_TYPE_UNDEFINED_BEHAVIORGL_DEBUG_TYPE_PORTABILITYGL_DEBUG_TYPE_PERFORMANCEGL_DEBUG_TYPE_MARKERGL_DEBUG_TYPE_PUSH_GROUPGL_DEBUG_TYPE_POP_GROUP, or GL_DEBUG_TYPE_OTHER to indicate the type of messages describing GL errors, attempted use of deprecated features, triggering of undefined behavior, portability issues, performance notifications, markers, group push and pop events, and other types of messages, respectively. It may also take the value GL_DONT_CARE. If type is not GL_DONT_CARE then only messages whose type matches type will be referenced.

severity may be one of GL_DEBUG_SEVERITY_LOWGL_DEBUG_SEVERITY_MEDIUM, or GL_DEBUG_SEVERITY_HIGH to select messages of low, medium or high severity messages or to GL_DEBUG_SEVERITY_NOTIFICATION for notifications. It may also take the value GL_DONT_CARE. If severity is not GL_DONT_CARE then only messages whose severity matches severity will be referenced.

ids contains a list of count message identifiers to select specific messages from the pool of available messages. If count is zero then the value of ids is ignored. Otherwise, only messages appearing in this list are selected. In this case, source and type may not be GL_DONT_CARE and severity must be GL_DONT_CARE.

If enabled is GL_TRUE then messages that match the filter formed by sourcetypeseverity and ids are enabled. Otherwise, those messages are disabled.

Notes

Although debug messages may be enabled in a non-debug context, the quantity and detail of such messages may be substantially inferior to those in a debug context. In particular, a valid implementation of the debug message queue in a non-debug context may produce no messages at all.

GL_DEBUG_TYPE_MARKERGL_DEBUG_TYPE_PUSH_GROUPGL_DEBUG_TYPE_POP_GROUP, and GL_DEBUG_SEVERITY_NOTIFICATION are available only if the GL version is 4.3 or higher.

Errors

GL_INVALID_VALUE is generated if count is negative.

GL_INVALID_ENUM is generated if any of sourcetype or severity is not one of the accepted interface types.

GL_INVALID_OPERATION is generated if count is non-zero and either source or type is GL_DONT_CARE or if severity is not GL_DONT_CARE.

Version Support

 OpenGL Version
Function / Feature Name2.02.13.03.13.23.34.04.14.24.34.44.5
glDebugMessageControl---------

See Also

glDebugMessageInsertglDebugMessageCallbackglGetDebugMessageLog.

Copyright

Copyright © 2013-2014 Khronos Group. This material may be distributed subject to the terms and conditions set forth in the Open Publication License, v 1.0, 8 June 1999. http://opencontent.org/openpub/.

 

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

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

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

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);
}

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);
}

检查调试环境:要检查是否成功地初始化了调试环境,我们可以对OpenGL进行查询。检查代码如下所示:

GLint flags; 
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
    // TODO 初始化调试输出成功
}

开关调试消息:传递调试消息默认是启动的,当然我们也可以禁止。通常使用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;
}

过滤调试消息:可以过滤出需要的调试消息。使用接口如下所示:
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);
}

参考

https://www.khronos.org/registry/OpenGL-Refpages/gl4/

https://blog.csdn.net/zjz520yy/article/details/83047042

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值