OpenGL 打开绘制窗口 学习笔记


#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);


        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

以上代码是绘制窗口,也是OpenGL最基础的代码

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    //glewInit();

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
 glBegin(GL_TRIANGLES);
 glVertex2f(-0.5, -0.5f);
 glVertex2f(0.5, 0.5f);
 glVertex2f(0.5, -0.5f);
 glColor3f(1, 0, 0);
 glEnd();

画三角形,开始画三角,结束画三角,中间就是三角形三个顶点的位置,还有三角形绘制的颜色


缓冲区:


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"

using namespace std;

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[6] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量


    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

shader是只运行在GPU上的程序


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"

using namespace std;

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str(); 
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);

        return 0;
    }

    return id;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int program = glCreateProgram();//创建program
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[6] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
    string vertexShader = "#version 330 core\n"//在这里定义顶点着色器的着色信息
        "\n"
        "layout(location = 0) in vec4 position;\n"
        "void main(){\n"
        "   gl_Position = position;\n"
        "}\n";
    string fragmentShader = "#version 330 core\n"//在这里定义片段着色器的着色信息
        "\n"
        "layout(location = 0) out vec4 color;\n"
        "void main(){\n"
        "   color = vec4(1.0, 0.0, 0.0, 1.0);\n"
        "}\n";

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}

将shader写进文件


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "fstream"
#include "string"
#include "sstream"

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }
    
    return id;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[6] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}
#shader vertex
#version 330 core

layout(location = 0) in vec4 position;
void main(){
   gl_Position = position;
}

#shader fragment
#version 330 core

layout(location = 0) out vec4 color;
void main(){
   color = vec4(1.0, 0.0, 0.0, 1.0);
}


绘制长方形:用两个三角形拼接,所有几何体,都可以用三角形来拼接


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "fstream"
#include "string"
#include "sstream"

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }
    
    return id;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,

        -0.5, -0.5,
        -0.5, 0.5,
        0.5, 0.5
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        glDrawArrays(GL_TRIANGLES, 0, 6);//画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}

 改动1:

改动2:

改动3:

但是在改动1的情况下,我们重复记录了相同的顶点,这造成了内存浪费,所以也要在Slate编程一样的去记录引用缓冲

   float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,
        -0.5, 0.5,
    };

    unsigned int Indices[] = {
        0, 1, 2,
        0, 1, 3
    };

    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);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

存放顶点然后用引用缓冲进行绘制


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "fstream"
#include "string"
#include "sstream"

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }
    
    return id;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,
        -0.5, 0.5,
    };

    unsigned int Indices[] = {
        0, 1, 2,
        0, 1, 3
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    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);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
        /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}

差错:

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static void GLCheckError() {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << endl;
    }
}
    GLClearError();
    glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);//这里故意将GL_UNSIGNED_INT改成了GL_INT用于检查错误
    GLCheckError();

报错编号为1280,转为16进制就为500,500对应的枚举值为无效枚举

#define ASSERT(x) if(!x) __debugbreak();

static bool GLLogCall() {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << endl;
        return false;
    }

    return true;
}

ASSERT(GLLogCall());

将GLCheckError改成GLLogCall,调用改成ASSERT(GLLogCall());

    GLClearError();
    glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);
    ASSERT(GLLogCall());

再整体封装一遍:

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall())

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static bool GLLogCall() {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << endl;
        return false;
    }

    return true;
}

GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));

 ​​​​

再进行一次优化:

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

当前所有代码:


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "fstream"
#include "string"
#include "sstream"

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }

    return id;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,
        -0.5, 0.5,
    };

    unsigned int Indices[] = {
        0, 1, 2,
        0, 1, 3
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    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);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
        /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);X

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}

使用uniform去修改shader内值

#shader vertex
#version 330 core

layout(location = 0) in vec4 position;

void main(){
   gl_Position = position;
}

#shader fragment
#version 330 core

layout(location = 0) out vec4 color;

uniform vec4 u_Color;

void main(){
   color = u_Color;
}
    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    int location = glGetUniformLocation(shader, "u_Color");
    glUniform4f(location, 0.2, 0.4, 0.3, 1);

拿到shader内的u_Color变量,然后去设置vec4 u_Color的值


制作矩形颜色闪烁效果:

    float r = 0.2;
    float increment = 0.01;
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {   
        /* Render here */   
        glClear(GL_COLOR_BUFFER_BIT);

        glUniform4f(location, r, 0.4, 0.3, 1);

        if (r < 0)   increment = 0.01;
        else if (r > 1)  increment = -0.01;
        r += increment;
        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
        /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);X

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

让矩形旋转,将四个位置乘以旋转矩阵,然后再将位置与引用进行重新绑定


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }

    return id;
}

#define PI 3.1415   

struct Pos {
    float x;
    float y;
};

Pos RotateMatrix(int Angle, float x, float y) {
    float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
    float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);

    Pos pos = Pos{ newX, newY };

    return pos;
}

void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
    for (int i = 0; i < 8; i += 2) {
        float tempX = Positions[i];
        float tempY = Positions[i + 1];
        Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
        Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
        //cout << tempX << " / " << tempY << endl;
    }
    glGenBuffers(1, &dataId);
    glBindBuffer(GL_ARRAY_BUFFER, dataId);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    glGenBuffers(1, &id);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);//定义缓冲区类型
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
    Angle++;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

void outputVertex(float Positions[]) {
    for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
        cout << Positions[i] << " \ " << Positions[i + 1] << endl;
    }
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(1);//屏幕刷新频率,此时为一帧刷新一次

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,
        -0.5, 0.5,
    };

    unsigned int Indices[] = {
        0, 1, 2,
        0, 1, 3
    };

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    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);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    int location = glGetUniformLocation(shader, "u_Color");
    glUniform4f(location, 0.2, 0.4, 0.3, 1);

    float r = 0.2;
    float increment = 0.01;
    int Angle = 0;
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {   
        /* Render here */   
        glClear(GL_COLOR_BUFFER_BIT);

        glUniform4f(location, r, 0.4, 0.3, 1);

        if (r < 0)   increment = 0.01;
        else if (r > 1)  increment = -0.01;
        r += increment;

        UpdateValue(Positions, Angle, ibo, Indices, a);

        outputVertex(Positions);
        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
        /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);X

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}


vao比vbo理论上速度要快,官方推荐用vao,之前上面实现方法为vbo

第一步:

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3

加上以上代码使用vao

第二步:

    unsigned int vao;
    glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
    glBindVertexArray(vao);

第三步:

glBindVertexArray(vao);

在while循环内进行绑定


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

static bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }

    return id;
}

#define PI 3.1415   

struct Pos {
    float x;
    float y;
};

Pos RotateMatrix(int Angle, float x, float y) {
    float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
    float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);

    Pos pos = Pos{ newX, newY };

    return pos;
}

void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
    for (int i = 0; i < 8; i += 2) {
        float tempX = Positions[i];
        float tempY = Positions[i + 1];
        Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
        Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
        //cout << tempX << " / " << tempY << endl;
    }
   
    Angle++;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

void outputVertex(float Positions[]) {
    for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
        cout << Positions[i] << " \ " << Positions[i + 1] << endl;
    }
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    float Positions[12] = {
        -0.5f, -0.5f,
        0.5f, 0.5f,
        0.5, -0.5f,
        -0.5, 0.5,
    };

    unsigned int Indices[] = {
        0, 1, 2,
        0, 1, 3
    };

    unsigned int vao;
    glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
    glBindVertexArray(vao);

    unsigned int a;
    glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
    //当生成多个缓冲区时: 
    //unsigned int b[3];
    //glGenBuffers(3, b);
    //cout << a << endl;
    //for (int i = 0; i < 3; i++) {
    //    cout << b[i] << endl;
    //}
    glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
    //第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
    //第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量

    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);//绑定完毕就要开始存放顶点数据了
    glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    ShaderProgramSource source = ParseShader("Shader.shader");
    cout << "Fragment: " << endl;
    cout << source.FragmentSource << endl;
    cout << "Vertex: " << endl;
    cout << source.VertexSource << endl;

    string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
    string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

    unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
    glUseProgram(shader);//使用刚创建的program

    int location = glGetUniformLocation(shader, "u_Color");
    glUniform4f(location, 0.2, 0.4, 0.3, 1);

    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glUseProgram(0);//使用刚创建的program

    float r = 0.2;
    float increment = 0.01;
    int Angle = 0;
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {   
        /* Render here */   
        glClear(GL_COLOR_BUFFER_BIT);

        glUniform4f(location, 0.2, 0.4, 0.3, 1);
        //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, a);
        glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
        glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
        glUseProgram(shader);//使用刚创建的program
        glUniform4f(location, r, 0.4, 0.3, 1);

        if (r < 0)   increment = 0.01;
        else if (r > 1)  increment = -0.01;
        r += increment;

        UpdateValue(Positions, Angle, ibo, Indices, a);

        outputVertex(Positions);
        /*glBegin(GL_TRIANGLES);
        glVertex2f(-0.5, -0.5f);
        glVertex2f(0.5, 0.5f);
        glVertex2f(0.5, -0.5f);
        glColor3f(1, 0, 0);
        glEnd();*/

        GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
        /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
        //glColor3f(1.f, 0, 0);X

        
        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glDeleteProgram(shader);
    glfwTerminate();
    return 0;
}

分类管理:

IndexBuffer: 

#pragma once

class IndexBuffer {
private:
	unsigned int m_RendererID;
	unsigned int m_Count;

public:
	IndexBuffer(const unsigned int* data, unsigned int count);
	~IndexBuffer();

	void Bind() const;
	void UnBind() const;

	inline unsigned int GetCount() const { return m_Count; }
};
#include "IndexBuffer.h"
#include "Renderer.h"

IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count) : m_Count(count) {
	glGenBuffers(1, &m_RendererID);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);
}

IndexBuffer::~IndexBuffer() {
	glDeleteBuffers(1, &m_RendererID);
}

void IndexBuffer::Bind() const {
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
}

void IndexBuffer::UnBind() const {
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

VertexBuffer:

#pragma once

class VertexBuffer {
private:
	unsigned int m_RendererID;

public: 
	VertexBuffer(const void* data, unsigned int size);
	~VertexBuffer();

	void Bind();
	void UnBind();
};
#include "VertexBuffer.h"
#include "Renderer.h"

VertexBuffer::VertexBuffer(const void* data, unsigned int size) {
	glGenBuffers(1, &m_RendererID);
	glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
	glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

VertexBuffer::~VertexBuffer() {
	glDeleteBuffers(1, &m_RendererID);
}

void VertexBuffer::Bind() {
	glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
}

void VertexBuffer::UnBind() {
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

Renderer:

#pragma once

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

void GLClearError();

bool GLLogCall(const char* function, const char* file, int line);
#include "Renderer.h"

#include "iostream"

using namespace std;

void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

使用:很清晰能够看清使用更加舒服简化了

VertexBuffer vb(Positions, 8 * sizeof(float));
IndexBuffer ib(Indices, 8 * sizeof(unsigned int));
while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);

            glUniform4f(location, 0.2, 0.4, 0.3, 1);
            //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
            glBindVertexArray(vao);
            ib.Bind();
            glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), Positions,吧GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
            glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
            glUseProgram(shader);//使用刚创建的program
            glUniform4f(location, r, 0.4, 0.3, 1);

            if (r < 0)   increment = 0.01;
            else if (r > 1)  increment = -0.01;
            r += increment;

            //UpdateValue(Positions, Angle, ibo, Indices, a);

            outputVertex(Positions);
            /*glBegin(GL_TRIANGLES);
            glVertex2f(-0.5, -0.5f);
            glVertex2f(0.5, 0.5f);
            glVertex2f(0.5, -0.5f);
            glColor3f(1, 0, 0);
            glEnd();*/

            GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
            /*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
            //glColor3f(1.f, 0, 0);X


            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

所有代码:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"

#include "Renderer.h"

#include "VertexBuffer.h"
#include "IndexBuffer.h"

#include "iostream"

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }

    return id;
}

#define PI 3.1415   

struct Pos {
    float x;
    float y;
};

Pos RotateMatrix(int Angle, float x, float y) {
    float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
    float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);

    Pos pos = Pos{ newX, newY };

    return pos;
}

void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
    for (int i = 0; i < 8; i += 2) {
        float tempX = Positions[i];
        float tempY = Positions[i + 1];
        Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
        Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
        //cout << tempX << " / " << tempY << endl;
    }
   
    Angle++;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

void outputVertex(float Positions[]) {
    for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
        cout << Positions[i] << " \ " << Positions[i + 1] << endl;
    }
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    {
        float Positions[12] = {
            -0.5f, -0.5f,
            0.5f, 0.5f,
            0.5, -0.5f,
            -0.5, 0.5,
        };

        unsigned int Indices[] = {
            0, 1, 2,
            0, 1, 3
        };

        unsigned int vao;
        glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
        glBindVertexArray(vao);

        VertexBuffer vb(Positions, 8 * sizeof(float));
        glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
 

        IndexBuffer ib(Indices, 8 * sizeof(unsigned int));

        ShaderProgramSource source = ParseShader("Shader.shader");
        cout << "Fragment: " << endl;
        cout << source.FragmentSource << endl;
        cout << "Vertex: " << endl;
        cout << source.VertexSource << endl;

        string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
        string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

        unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
        //glUseProgram(shader);//使用刚创建的program

        int location = glGetUniformLocation(shader, "u_Color");
        glUniform4f(location, 0.2, 0.4, 0.3, 1);

        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glUseProgram(0);//使用刚创建的program

        float r = 0.2;
        float increment = 0.01;
        int Angle = 0;
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);

            glUniform4f(location, 0.2, 0.4, 0.3, 1);
            glBindVertexArray(vao);
            ib.Bind();
            glUseProgram(shader);//使用刚创建的program
            glUniform4f(location, r, 0.4, 0.3, 1);

            if (r < 0)   increment = 0.01;
            else if (r > 1)  increment = -0.01;
            r += increment;

            //UpdateValue(Positions, Angle, ibo, Indices, a);

            outputVertex(Positions);

            GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

        glDeleteProgram(shader);
    }
    glfwTerminate();
    return 0;
}

因为自己也是初学者,我刚开始看视频没太理解vao与vbo,看了这篇文章讲的比较通透:

(73条消息) 详解Opengl中VBO和VAO_代码乐的博客-CSDN博客_vbo vao


将VertexArray封装成类:

IndexBuffer:

#pragma once

class IndexBuffer {
private:
	unsigned int m_RendererID;
	unsigned int m_Count;

public:
	IndexBuffer(const unsigned int* data, unsigned int count);
	~IndexBuffer();

	void Bind() const;
	void UnBind() const;

	inline unsigned int GetCount() const { return m_Count; }
};
#include "IndexBuffer.h"
#include "Renderer.h"

IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count) : m_Count(count) {
	glGenBuffers(1, &m_RendererID);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);
}

IndexBuffer::~IndexBuffer() {
	glDeleteBuffers(1, &m_RendererID);
}

void IndexBuffer::Bind() const {
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
}

void IndexBuffer::UnBind() const {
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

Renderer:

#pragma once

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

void GLClearError();

bool GLLogCall(const char* function, const char* file, int line);
#include "Renderer.h"

#include "iostream"

using namespace std;

void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

VertexArray:

#pragma once

#include "VertexBuffer.h"
#include "VertexBufferLayout.h"

class VertexArray {
private:
	unsigned int m_RendererID;
public:
	VertexArray();
	~VertexArray();

	void Bind() const;
	void UnBind() const;

	void AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout);
};
#include "VertexArray.h"
#include "VertexBufferLayout.h"

VertexArray::VertexArray() {
	glGenVertexArrays(1, &m_RendererID);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
	glBindVertexArray(m_RendererID);
}

VertexArray::~VertexArray() {
	glDeleteVertexArrays(1, &m_RendererID);
}

void VertexArray::AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout) {
	vb.Bind();
	const auto& elements = layout.GetElement();
	unsigned int offset = 0;
	for (unsigned int i = 0; i < elements.size(); i++) {
		const auto& element = elements[i];
		glEnableVertexAttribArray(i);//启用第一组顶点属性数组,0代表数组下标为0
		glVertexAttribPointer(i, element.count, element.type, element.normalized, layout.GetStride(), (const void*)offset);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
		offset += element.count * VertexBufferElements::GetSizeOfType(element.type);
	}
	  
}

void VertexArray::Bind() const {
	glBindVertexArray(m_RendererID);
}

void VertexArray::UnBind() const {
	glBindVertexArray(0);
}

VertexBuffer:

#pragma once

class VertexBuffer {
private:
	unsigned int m_RendererID;
public: 
	VertexBuffer(const void* data, unsigned int size);
	~VertexBuffer();

	void Bind() const;
	void UnBind();
};
#include "VertexBuffer.h"
#include "Renderer.h"

VertexBuffer::VertexBuffer(const void* data, unsigned int size) {
	glGenBuffers(1, &m_RendererID);
	glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
	glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

VertexBuffer::~VertexBuffer() {
	glDeleteBuffers(1, &m_RendererID);
}

void VertexBuffer::Bind() const {
	glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
}

void VertexBuffer::UnBind() {
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

VertexBufferLayout:

#pragma once

#include "vector"
#include "Renderer.h"
#include "GL/glew.h"

struct VertexBufferElements {
	unsigned int type;
	unsigned int count;
	unsigned char normalized;

	static unsigned int GetSizeOfType(unsigned int type) {
		switch (type) {
			case GL_FLOAT:	return 4;
			case GL_UNSIGNED_INT: return 4;
			case GL_UNSIGNED_BYTE: return 1;
		}
		ASSERT(false);
		return 0;
	}
};

class VertexBufferLayout {
private:

	std::vector<VertexBufferElements> m_Elements;
	unsigned int m_Stride;

public:

	VertexBufferLayout() : m_Stride(0) {};

	template<typename T>
	void Push(unsigned int count) {
		static_assert(false);
	}

	template<>
	void Push<float>(unsigned int count) {
		m_Elements.push_back(VertexBufferElements{ GL_FLOAT, count, GL_FALSE });
		m_Stride += count * VertexBufferElements::GetSizeOfType(GL_FLOAT);
	}

	template<>
	void Push<unsigned int>(unsigned int count) {
		m_Elements.push_back(VertexBufferElements{ GL_UNSIGNED_INT, count, GL_FALSE });
		m_Stride += count * VertexBufferElements::GetSizeOfType(GL_UNSIGNED_INT);
	}

	template<>
	void Push<unsigned char>(unsigned int count) {
		m_Elements.push_back(VertexBufferElements{ GL_UNSIGNED_BYTE, count, GL_TRUE });
		m_Stride += count * VertexBufferElements::GetSizeOfType(GL_UNSIGNED_BYTE);
	}

	inline std::vector<VertexBufferElements> GetElement() const { return m_Elements; }
	inline unsigned int GetStride() const { return m_Stride; }
};

Application:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"

#include "Renderer.h"

#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "VertexArray.h"

#include "iostream"

using namespace std;

struct ShaderProgramSource {
    string VertexSource;
    string FragmentSource;
};

static ShaderProgramSource ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if(line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);
 
        return 0;
    }

    return id;
}

#define PI 3.1415   

struct Pos {
    float x;
    float y;
};

Pos RotateMatrix(int Angle, float x, float y) {
    float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
    float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);

    Pos pos = Pos{ newX, newY };

    return pos;
}

void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
    for (int i = 0; i < 8; i += 2) {
        float tempX = Positions[i];
        float tempY = Positions[i + 1];
        Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
        Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
        //cout << tempX << " / " << tempY << endl;
    }
   
    Angle++;
}

static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
    //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

void outputVertex(float Positions[]) {
    for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
        cout << Positions[i] << " \ " << Positions[i + 1] << endl;
    }
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次

    if (glewInit() != GLEW_OK) {
        cout << "ERROR" << endl;
    }

    {
        float Positions[12] = {
            -0.5f, -0.5f,
            0.5f, 0.5f,
            0.5, -0.5f,
            -0.5, 0.5,
        };

        unsigned int Indices[] = {
            0, 1, 2,
            0, 1, 3
        };

        VertexArray va;//这里把vao给声明好,并绑定好
        VertexBuffer vb(Positions, 8 * sizeof(float));//这里把顶点缓冲的数据也准备好了
        VertexBufferLayout layout;//声明顶点样式
        layout.Push<float>(2);//定义顶点样式,例如一个值组成一个顶点,从第几个顶点开始读,这里传进去的是2,证明两个浮点值组成一个顶点
        va.AddBuffer(vb, layout);//将layout数据进行处理并将vb进行绑定

        IndexBuffer ib(Indices, 8 * sizeof(unsigned int));

        ShaderProgramSource source = ParseShader("Shader.shader");
        cout << "Fragment: " << endl;
        cout << source.FragmentSource << endl;
        cout << "Vertex: " << endl;
        cout << source.VertexSource << endl;

        string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
        string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息

        unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
        glUseProgram(shader);//使用刚创建的program

        int location = glGetUniformLocation(shader, "u_Color");
        glUniform4f(location, 0.2, 0.4, 0.3, 1);

        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glUseProgram(0);//使用刚创建的program

        float r = 0.2;
        float increment = 0.01;
        int Angle = 0;
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            glClear(GL_COLOR_BUFFER_BIT);

            glUseProgram(shader);//使用刚创建的program
            glUniform4f(location, 0.2, 0.4, r, 1);

            va.Bind();
            ib.Bind();

            if (r < 0)   increment = 0.01;
            else if (r > 1)  increment = -0.01;
            r += increment;

            //UpdateValue(Positions, Angle, ibo, Indices, a);

            //outputVertex(Positions);

            GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

        glDeleteProgram(shader);
    }
    glfwTerminate();
    return 0;
}


将shader再一次进行封装处理:

#pragma once
#include "string"
#include "unordered_map"

using namespace std;

struct ShaderProgramSource {
	string VertexSource;
	string FragmentSource;
};

class Shader {

public:
	Shader(const string& filepath);
	~Shader();

	void Bind() const;
	void UnBind() const;

	//Set Uniforms
	void SetUniform4f(const string& name, float v0, float v1, float v2, float v3);

private:
	unsigned int m_RendererID;
	string m_FilePath;
	unordered_map<string, int> m_UniformLocationCache;

private:
	unsigned int CompileShader(const string& source, unsigned int type);
	int CreateShader(const string& vertexShader, const string& fragmentShader);
	ShaderProgramSource ParseShader(const string& filepath);
	int GetUniformLocation(const string& name);

};
#include "Shader.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "sstream"
#include "fstream"


Shader::Shader(const string& filepath) : m_FilePath(filepath), m_RendererID(0) {
	//CompileShader();
    ShaderProgramSource source = ParseShader(m_FilePath);
    m_RendererID = CreateShader(source.VertexSource, source.FragmentSource);//通过创建好的着色器创建program
}

Shader::~Shader() {
    glDeleteProgram(m_RendererID);
}

void Shader::Bind() const{
    glUseProgram(m_RendererID);
}

void Shader::UnBind() const {
    glUseProgram(0);
}

void Shader::SetUniform4f(const string& name, float v0, float v1, float v2, float v3) {
    glUniform4f(GetUniformLocation(name), v0, v1, v2, v3);
}

int Shader::GetUniformLocation(const string& name) {
    if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())   return m_UniformLocationCache[name];
    int location = glGetUniformLocation(m_RendererID, name.c_str());
    if (location == -1)  cout << "Warning: uniform '" << name << "' doesn't exist!" << endl;
    return location;
}

int Shader::CreateShader(const string& vertexShader, const string& fragmentShader) {
    //总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 
        //4、与program建立链接 5、验证program 6、删除shader
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

ShaderProgramSource Shader::ParseShader(const string& filepath) {
    ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    string line;
    stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {
        if (line.find("#shader") != string::npos) {
            if (line.find("vertex") != string::npos) {
                type = ShaderType::VERTEX;
            }
            else if (line.find("fragment") != string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else {
            ss[(int)type] << line << "\n";
        }
    }

    return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}

unsigned int Shader::CompileShader(const string& source, unsigned int type) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
        glGetShaderInfoLog(id, length, &length, message);
        cout << "FAILED TO COMPILE SHADER !" << endl;
        cout << message << endl;
        glDeleteShader(id);

        return 0;
    }

    return id;
}

将绘制进行封装:

#pragma once

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Shader.h"

#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))

using namespace std;

void GLClearError();

bool GLLogCall(const char* function, const char* file, int line);

class Renderer {
public:
	void GLDrawCall(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const;

	void GLClear() const;
};
#include "Renderer.h"

#include "iostream"

using namespace std;

void GLClearError() {
    while (glGetError() != GL_NO_ERROR);
}

bool GLLogCall(const char* function, const char* file, int line) {
    while (GLenum Enum = glGetError()) {
        cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
        return false;
    }

    return true;
}

void Renderer::GLDrawCall(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const {
    va.Bind();
    ib.Bind();
    shader.Bind();
    GLCALL(glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr));
}

void Renderer::GLClear() const {
    glClear(GL_COLOR_BUFFER_BIT);
}
 Renderer renderer;
        float r = 0.2;
        float increment = 0.01;
        int Angle = 0;
        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            renderer.GLClear();
            
           //shader.Bind();//使用刚创建的program
            renderer.GLDrawCall(va, ib, shader);
            shader.SetUniform4f("u_Color", 0.2, 0.4, r, 1);

            //va.Bind();
           // ib.Bind();

            if (r < 0)   increment = 0.01;
            else if (r > 1)  increment = -0.01;
            r += increment;

            //UpdateValue(Positions, Angle, ibo, Indices, a);

            //outputVertex(Positions);

            GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值