OpenGL Chan视频学习-10 Dealing with Errors in OpenGL

bilibili视频链接:

【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p=5\&vd_source=44b77bde056381262ee55e448b9b1973

函数网站:

docs.gl

说明:

1.之后就不再单独整理网站具体函数了,网站直接翻译会更直观也会有更多注意点。直接通过csdn索引查找反而会慢。

2.代码区域会单独注释功能参数返回值和相关注意事项。

3.课程学习从4-本节,如果有些函数没有注释可以看专栏里面的前面发表的文章,一般有解释。

4.如果觉得代码注释白色字体不太直观可以直接copy到相应软件看

5.有两种版本的可供查看:注释全面的和注释简洁版的,可以在索引里面找到相关代码查看。

6.希望能帮到你。

7.有错误请跟我说明一下,可能整理的时候没有检查好

一、知识点整理

1.1 检查OpenGL错误

1.1.1方法一 glGetError

1.1.1.1网址

glGetError - OpenGL 2 - docs.glhttps://docs.gl/gl2/glGetError

1.1.1.2示例
cpp 复制代码
static void GLClearError()
{
    //功能:检测OpenGL错误
    //glGetError()函数返回最后一次发生的错误代码,如果没有错误发生,则返回GL_NO_ERROR。
    //注意:在调用glGetError()函数之前,必须先调用glClearError()函数,否则会导致错误计数器不清零。
    while (glGetError() != GL_NO_ERROR);
}


static void GLCheckError()
{
    //功能:检测OpenGL错误,输出错误信息
    //while循环,直到glGetError()返回GL_NO_ERROR,表示没有错误发生。
    while (GLenum error = glGetError())
    {
        std::cout << "[OpenGL Error] (" << error << "): " << std::endl;
    }
}

为什么要在while里面调用?

在代码中,glGetError()函数用于检测OpenGL错误,它会返回最后一次发生的错误代码,并且每次调用该函数时会清除之前的错误。因此,如果只是调用一次glGetError(),可能无法捕获所有累积的错误,因为之前的错误会被清除。

通过将glGetError()放在一个while循环中,可以不断地检查和清除OpenGL错误,直到返回GL_NO_ERROR为止。这样可以确保在执行OpenGL操作之前,所有的错误都被捕获和处理,从而帮助开发者调试和确保程序的正确性。

请注意,这个循环通常会消耗CPU资源,因为它会一直检查错误直到没有错误为止,所以在实际应用中可能需要谨慎使用。

1.1.1.3运行结果
1.1.1.4解决方法

1.log

2.将十进制转换成十六进制。右键点击error

3.进入#include <GL/glew.h>搜索500

无效的枚举

1.1.1.5注意

应该在循环中调用确保得到所有错误

1.1.1.6缺点

不显示错误行,必须自行在每个函数之前调用并检测错误

1.1.2方法二

1.1.2.1代码

ASSERT宏

cpp 复制代码
//功能:定义宏,用于在调试过程中进行条件断言,检测OpenGL错误
//这个宏接受一个参数 x,它是一个条件表达式。
//if(!(x)) __debugbreak();: 这是宏的实现部分。
// 它检查参数 x 是否为 false。
// 如果是,__debugbreak(); 会被调用,这通常会导致程序在当前位置中断,进入调试器。
#define ASSERT(x) if(!(x)) __debugbreak();

函数

cpp 复制代码
static void GLClearError()
{
    //功能:检测OpenGL错误
    //glGetError()函数返回最后一次发生的错误代码,如果没有错误发生,则返回GL_NO_ERROR。
    //注意:在调用glGetError()函数之前,必须先调用glClearError()函数,否则会导致错误计数器不清零。
    while (glGetError() != GL_NO_ERROR);
}


static bool GLLogError()
{
    //功能:检测OpenGL错误,输出错误信息
    //while循环,直到glGetError()返回GL_NO_ERROR,表示没有错误发生。
    while (GLenum error = glGetError())
    {
        std::cout << "[OpenGL Error] (" << error << "): " << std::endl;
        return false;
    }
    return true;
}

int main修改

cpp 复制代码
GLClearError();
//功能:绘制三角形
glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);
ASSERT(GLLogError());
1.1.2.2运行结果

1.1.3方法二改进

1.1.3.1代码

cpp 复制代码
//功能:定义宏,用于在调试过程中进行条件断言,检测OpenGL错误
//这个宏接受一个参数 x,它是一个条件表达式。
//if(!(x)) __debugbreak();: 这是宏的实现部分。
// 它检查参数 x 是否为 false。
// 如果是,__debugbreak(); 会被调用,这通常会导致程序在当前位置中断,进入调试器。
#define ASSERT(x) if(!(x)) __debugbreak();
//功能:定义了一个宏 GLCall(x),用于调试 OpenGL 应用程序时检查和处理 OpenGL 错误。
//x 是该宏接受的一个参数,通常是一个 OpenGL 函数调用。
//GLClearError();: 宏展开后首先会调用 GLClearError() 函数,清除 OpenGL 错误缓冲中的所有错误。
//x;: 接着是传入的 OpenGL 函数调用。
// 例如,如果宏被调用为 GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));,
// 那么这里将展开为实际的 OpenGL 函数调用 glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);。
//ASSERT(GLLogError(#x, __FILE__, __LINE__));: 
// #x 将 OpenGL 函数调用转换为字符串。
// __FILE__ 和 __LINE__ 是预定义的宏,分别包含当前源文件名和行号。
// GLLogError() 函数会输出任何检测到的错误信息。如果错误发生,ASSERT 宏将导致程序中断并进入调试器。


// 整体思路:
//1.错误清除:
//GLClearError() 函数通过循环调用 glGetError() 清除 OpenGL 错误缓冲中的所有错误,直到 glGetError() 返回 GL_NO_ERROR。
//2.OpenGL 函数调用:
//x; 是传入的实际 OpenGL 函数调用,比如 glDrawElements、glBindBuffer 等。
//3.错误检查和断言:
//GLLogError() 函数再次调用 glGetError() 来检查是否有新的错误发生。如果检测到错误,它会将错误代码和错误信息输出到标准输出,并返回 false。
//ASSERT(GLLogError()); 宏用于验证 GLLogError() 的返回值。如果返回值为 false(即有错误发生),程序将中断并进入调试器,这样开发者可以更容易地找到并修复问题。
#define GLCall(x) GLClearError();\
    x;\
    ASSERT(GLLogError(#x,__FILE__,__LINE__));

函数

cpp 复制代码
static void GLClearError()
{
    //功能:检测OpenGL错误
    //glGetError()函数返回最后一次发生的错误代码,如果没有错误发生,则返回GL_NO_ERROR。
    //注意:在调用glGetError()函数之前,必须先调用glClearError()函数,否则会导致错误计数器不清零。
    while (glGetError() != GL_NO_ERROR);
}

//参数:1.function: 发生错误的函数名
//     2.file: 发生错误的文件名
//     3.line: 发生错误的行号
//功能:输出OpenGL错误信息
static bool GLLogError(const char* function, const char* file, int line)
{
    //功能:检测OpenGL错误,输出错误信息
    //while循环,直到glGetError()返回GL_NO_ERROR,表示没有错误发生。
    while (GLenum error = glGetError())
    {
        std::cout << "[OpenGL Error] (" << error << "): " << function << 
            " " << file << ":" << line << std::endl;
        return false;
    }
    return true;
}

int main调用修改

cpp 复制代码
//功能:绘制三角形
GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));
1.1.3.2运行结果
1.1.4方法三------glDebugMessageCallback
1.1.4.1网址

glDebugMessageCallback - OpenGL 4 - docs.glhttps://docs.gl/gl4/glDebugMessageCallback

二、完整代码

2.1完全注释代码

cpp 复制代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>

//功能:定义宏,用于在调试过程中进行条件断言,检测OpenGL错误
//这个宏接受一个参数 x,它是一个条件表达式。
//if(!(x)) __debugbreak();: 这是宏的实现部分。
// 它检查参数 x 是否为 false。
// 如果是,__debugbreak(); 会被调用,这通常会导致程序在当前位置中断,进入调试器。
#define ASSERT(x) if(!(x)) __debugbreak();
//功能:定义了一个宏 GLCall(x),用于调试 OpenGL 应用程序时检查和处理 OpenGL 错误。
//x 是该宏接受的一个参数,通常是一个 OpenGL 函数调用。
//GLClearError();: 宏展开后首先会调用 GLClearError() 函数,清除 OpenGL 错误缓冲中的所有错误。
//x;: 接着是传入的 OpenGL 函数调用。
// 例如,如果宏被调用为 GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));,
// 那么这里将展开为实际的 OpenGL 函数调用 glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);。
//ASSERT(GLLogError(#x, __FILE__, __LINE__));: 
// #x 将 OpenGL 函数调用转换为字符串。
// __FILE__ 和 __LINE__ 是预定义的宏,分别包含当前源文件名和行号。
// GLLogError() 函数会输出任何检测到的错误信息。如果错误发生,ASSERT 宏将导致程序中断并进入调试器。


// 整体思路:
//1.错误清除:
//GLClearError() 函数通过循环调用 glGetError() 清除 OpenGL 错误缓冲中的所有错误,直到 glGetError() 返回 GL_NO_ERROR。
//2.OpenGL 函数调用:
//x; 是传入的实际 OpenGL 函数调用,比如 glDrawElements、glBindBuffer 等。
//3.错误检查和断言:
//GLLogError() 函数再次调用 glGetError() 来检查是否有新的错误发生。如果检测到错误,它会将错误代码和错误信息输出到标准输出,并返回 false。
//ASSERT(GLLogError()); 宏用于验证 GLLogError() 的返回值。如果返回值为 false(即有错误发生),程序将中断并进入调试器,这样开发者可以更容易地找到并修复问题。
#define GLCall(x) GLClearError();\
    x;\
    ASSERT(GLLogError(#x,__FILE__,__LINE__));

static void GLClearError()
{
    //功能:检测OpenGL错误
    //glGetError()函数返回最后一次发生的错误代码,如果没有错误发生,则返回GL_NO_ERROR。
    //注意:在调用glGetError()函数之前,必须先调用glClearError()函数,否则会导致错误计数器不清零。
    while (glGetError() != GL_NO_ERROR);
}

//参数:1.function: 发生错误的函数名
//     2.file: 发生错误的文件名
//     3.line: 发生错误的行号
//功能:输出OpenGL错误信息
static bool GLLogError(const char* function, const char* file, int line)
{
    //功能:检测OpenGL错误,输出错误信息
    //while循环,直到glGetError()返回GL_NO_ERROR,表示没有错误发生。
    while (GLenum error = glGetError())
    {
        std::cout << "[OpenGL Error] (" << error << "): " << function << 
            " " << file << ":" << line << std::endl;
        return false;
    }
    return true;
}


//功能:定义ShaderProgramSource结构体,用于存储着色器代码
struct ShaderProgramSource
{
    std::string VertexSource;
    std::string FragmentSource;
};


//功能:解析着色器代码文件。
static ShaderProgramSource ParseShader(const std::string& filepath)
{
    //功能:打开文件流
    std::ifstream stream(filepath);

    //定义着色器类型
    enum  class ShaderType
    {
        NONE=-1,VERTEX=0,FRAGMENT=1
    };

    //该变量用于存储着色器代码
    std::string line;
    //该变量用于存储着色器类型
    std::stringstream ss[2];
    //该变量是当前着色器类型
    ShaderType type = ShaderType::NONE;
    //功能:读取文件中的每一行内容,直到文件结束
    while (getline(stream, line))
    {
        //如果当前行包含#shader,则说明接下来是着色器代码
        if (line.find("#shader") != std::string::npos)
        {
            //如果当前行包含vertex,则说明接下来是顶点着色器代码
            if (line.find("vertex") != std::string::npos)
            {
                type = ShaderType::VERTEX;
            }
            else if (line.find("fragment") != std::string::npos)
            {
                type = ShaderType::FRAGMENT;
            }
        }
        else
        {
            //否则,将当前行添加到对应着色器代码的stringstream中
            ss[(int)type] << line << '\n';
        }
    }
    //返回ShaderProgramSource结构体
    return { ss[0].str(), ss[1].str() };
}


//功能:编译着色器代码
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
    //功能:创建着色器对象
    unsigned int id = glCreateShader(type);
    //功能:设置着色器源代码.
    const char* src = source.c_str();
    //功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
    glShaderSource(id, 1, &src, nullptr);
    //功能:编译着色器对象的源代码
    glCompileShader(id);

    //设置返回着色器的对象ID
    int result;
    //功能:从着色器对象返回一个参数,表示编译是否成功。
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    //如果编译失败,则输出错误信息
    if (result == GL_FALSE)
    {
        int length;
        //功能:获取编译错误信息的长度
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        //分配内存,用于存储编译错误信息
        char* message = (char*)alloca(length*sizeof(char));
        //功能:获取编译错误信息
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
        std::cout << message << std::endl;
        //删除着色器对象
        glDeleteShader(id);
        return 0;
    }

    //TODO:错误处理ing
    return id;
}


//功能:创建着色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    //创建程序对象
    unsigned int program = glCreateProgram();
    //编译顶点着色器对象
    unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
    //编译片段着色器对象
    unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);

    //功能:将编译好的着色器对象附加到程序对象中
    glAttachShader(program, vs);
    glAttachShader(program, fs);

    //功能:链接程序对象
    glLinkProgram(program);

    //功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
    glValidateProgram(program);

    //删除着色器对象,因为它们已经被链接到程序对象中
    glDeleteShader(vs);
    glDeleteShader(fs);

    //返回着色器程序
    return program;
}


int main(void)
{
    GLFWwindow* window;

    //初始化glfw
    if (!glfwInit())
        return -1;

    //创建一个窗口模式的窗口并设置OpenGL上下文
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)//如果窗口创建失败,则终止程序
    {
        glfwTerminate();//释放glfw资源
        return -1;
    }

    //设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
    glfwMakeContextCurrent(window);

    //初始化GLEW
    if (glewInit() != GLEW_OK)
        std::cout << "Error!" << std::endl;

    //打印OpenGL版本信息
    std::cout << glGetString(GL_VERSION) << std::endl;

    //准备数据
    float position[] = {
        -0.5f, -0.5f,
        0.5f, -0.5f,
        0.5f,0.5f,
        -0.5f,0.5f,
    };

    //定义顶点索引缓存,用于标定顶点顺序
    unsigned int indices[] = {
        0,1,2,
        2,3,0
    };

    
    //定义缓冲区对象
    unsigned int buffer;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &buffer);
    //功能:将缓冲区对象绑定到目标
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    //功能:将数据写入缓冲区
    glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(float), position, GL_STATIC_DRAW);

    //功能:配置顶点属性指针
    glEnableVertexAttribArray(0);
    //功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    

    //索引缓冲区对象
    unsigned int ibo;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &ibo);
    //功能:将缓冲区对象绑定到目标.没有绑定为数组缓冲区
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    //功能:将数据写入缓冲区
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), indices, GL_STATIC_DRAW);


    //解析着色器代码文件
    ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
    std::string vertexShader = source.VertexSource;
    std::string fragmentShader = source.FragmentSource;
    //创建着色器程序
    unsigned int shader = CreateShader(vertexShader, fragmentShader);
    //使用着色器程序
    glUseProgram(shader);

    //渲染循环,直到窗口被关闭
    while (!glfwWindowShouldClose(window))
    {
        //清除颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);
        
        //功能:绘制三角形
        GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));

        //刷新缓冲区并交换窗口
        glfwSwapBuffers(window);

        //处理窗口事件,如键盘输入、鼠标移动等
        glfwPollEvents();
    }

    //删除着色器程序
    //glDeleteProgram(shader);

    //释放 GLFW 库占用的所有资源。
    glfwTerminate();
    return 0;
}

2.2简洁注释代码

cpp 复制代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>

//功能:定义宏,用于在调试过程中进行条件断言,检测OpenGL错误
#define ASSERT(x) if(!(x)) __debugbreak();
//功能:定义了一个宏 GLCall(x),用于调试 OpenGL 应用程序时检查和处理 OpenGL 错误。
#define GLCall(x) GLClearError();\
    x;\
    ASSERT(GLLogError(#x,__FILE__,__LINE__));

static void GLClearError()
{
    //功能:检测OpenGL错误
    while (glGetError() != GL_NO_ERROR);
}

//参数:1.function: 发生错误的函数名
static bool GLLogError(const char* function, const char* file, int line)
{
    //功能:检测OpenGL错误,输出错误信息
    //while循环,直到glGetError()返回GL_NO_ERROR,表示没有错误发生。
    while (GLenum error = glGetError())
    {
        std::cout << "[OpenGL Error] (" << error << "): " << function << 
            " " << file << ":" << line << std::endl;
        return false;
    }
    return true;
}


//功能:定义ShaderProgramSource结构体,用于存储着色器代码
struct ShaderProgramSource
{
    std::string VertexSource;
    std::string FragmentSource;
};


//功能:解析着色器代码文件。
static ShaderProgramSource ParseShader(const std::string& filepath)
{
    //功能:打开文件流
    std::ifstream stream(filepath);

    //定义着色器类型
    enum  class ShaderType
    {
        NONE=-1,VERTEX=0,FRAGMENT=1
    };

    //该变量用于存储着色器代码
    std::string line;
    //该变量用于存储着色器类型
    std::stringstream ss[2];
    //该变量是当前着色器类型
    ShaderType type = ShaderType::NONE;
    //功能:读取文件中的每一行内容,直到文件结束
    while (getline(stream, line))
    {
        //如果当前行包含#shader,则说明接下来是着色器代码
        if (line.find("#shader") != std::string::npos)
        {
            //如果当前行包含vertex,则说明接下来是顶点着色器代码
            if (line.find("vertex") != std::string::npos)
            {
                type = ShaderType::VERTEX;
            }
            else if (line.find("fragment") != std::string::npos)
            {
                type = ShaderType::FRAGMENT;
            }
        }
        else
        {
            //否则,将当前行添加到对应着色器代码的stringstream中
            ss[(int)type] << line << '\n';
        }
    }
    //返回ShaderProgramSource结构体
    return { ss[0].str(), ss[1].str() };
}


//功能:编译着色器代码
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
    //功能:创建着色器对象
    unsigned int id = glCreateShader(type);
    //功能:设置着色器源代码.
    const char* src = source.c_str();
    //功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
    glShaderSource(id, 1, &src, nullptr);
    //功能:编译着色器对象的源代码
    glCompileShader(id);

    //设置返回着色器的对象ID
    int result;
    //功能:从着色器对象返回一个参数,表示编译是否成功。
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    //如果编译失败,则输出错误信息
    if (result == GL_FALSE)
    {
        int length;
        //功能:获取编译错误信息的长度
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        //分配内存,用于存储编译错误信息
        char* message = (char*)alloca(length*sizeof(char));
        //功能:获取编译错误信息
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
        std::cout << message << std::endl;
        //删除着色器对象
        glDeleteShader(id);
        return 0;
    }

    //TODO:错误处理ing
    return id;
}


//功能:创建着色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    //创建程序对象
    unsigned int program = glCreateProgram();
    //编译顶点着色器对象
    unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
    //编译片段着色器对象
    unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);

    //功能:将编译好的着色器对象附加到程序对象中
    glAttachShader(program, vs);
    glAttachShader(program, fs);

    //功能:链接程序对象
    glLinkProgram(program);

    //功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
    glValidateProgram(program);

    //删除着色器对象,因为它们已经被链接到程序对象中
    glDeleteShader(vs);
    glDeleteShader(fs);

    //返回着色器程序
    return program;
}


int main(void)
{
    GLFWwindow* window;

    //初始化glfw
    if (!glfwInit())
        return -1;

    //创建一个窗口模式的窗口并设置OpenGL上下文
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)//如果窗口创建失败,则终止程序
    {
        glfwTerminate();//释放glfw资源
        return -1;
    }

    //设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
    glfwMakeContextCurrent(window);

    //初始化GLEW
    if (glewInit() != GLEW_OK)
        std::cout << "Error!" << std::endl;

    //打印OpenGL版本信息
    std::cout << glGetString(GL_VERSION) << std::endl;

    //准备数据
    float position[] = {
        -0.5f, -0.5f,
        0.5f, -0.5f,
        0.5f,0.5f,
        -0.5f,0.5f,
    };

    //定义顶点索引缓存,用于标定顶点顺序
    unsigned int indices[] = {
        0,1,2,
        2,3,0
    };

    
    //定义缓冲区对象
    unsigned int buffer;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &buffer);
    //功能:将缓冲区对象绑定到目标
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    //功能:将数据写入缓冲区
    glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(float), position, GL_STATIC_DRAW);

    //功能:配置顶点属性指针
    glEnableVertexAttribArray(0);
    //功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    

    //索引缓冲区对象
    unsigned int ibo;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &ibo);
    //功能:将缓冲区对象绑定到目标.没有绑定为数组缓冲区
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    //功能:将数据写入缓冲区
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), indices, GL_STATIC_DRAW);


    //解析着色器代码文件
    ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
    std::string vertexShader = source.VertexSource;
    std::string fragmentShader = source.FragmentSource;
    //创建着色器程序
    unsigned int shader = CreateShader(vertexShader, fragmentShader);
    //使用着色器程序
    glUseProgram(shader);

    //渲染循环,直到窗口被关闭
    while (!glfwWindowShouldClose(window))
    {
        //清除颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);
        
        //功能:绘制三角形
        GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));

        //刷新缓冲区并交换窗口
        glfwSwapBuffers(window);

        //处理窗口事件,如键盘输入、鼠标移动等
        glfwPollEvents();
    }

    //删除着色器程序
    //glDeleteProgram(shader);

    //释放 GLFW 库占用的所有资源。
    glfwTerminate();
    return 0;
}

2.3运行结果

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习