OpenGL学习笔记(二)

1. 状态机

OpenGL自身就是一个大型状态机(State Machine),它使用了一种状态模型来追踪所有的OpenGL状态变量。当一个状态值被设置之后,它就一直保持这个状态,直到其他函数对它进行修改为止。

当我们使用glGenBuffer声明buffer并使用glBufferData创建初始化buffer的时候,这个buffer其实是在显存中的,接下来是由GPU而非CPU访问。

而我们调用的OpenGL API,以及以后的shader,其实就是改变OpenGL状态机的状态,通过draw call告诉GPU如何从buffer取数据来进行绘制。
在我看来,这是一种数据-控制模型。

2. 顶点数组与顶点属性

通过声明、创建并初始化vertex array buffer,可以把数据存到到GPU中。

glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions) * sizeof(float), positions, GL_STATIC_DRAW);

开启并定义顶点属性

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, NULL);

在OpenGL中,vertex顶点和vertex position顶点位置是两种概念(因为顶点的位置会随着物体的变化而变化)
顶点还包含

  • 纹理
  • 坐标
  • 法线
  • 颜色
  • 按法线切线

3. 绘制

最后再在循环中调用glDrawArrays()进行draw call绘制

glDrawArrays(GL_TRIANGLES, 0, 3);

贴上完整代码

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    // 初始化GLFW库,对应的需要在退出时候调用glfwTerminate()销毁资源
    if (!glfwInit())
        return -1;

    // 创建window和OpenGL context,该window的context需要手动设置成current context
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    // 把window的context设置成current context
    glfwMakeContextCurrent(window);

    // 设置顶点的位置
    GLfloat positions[] = {
        -0.5f, -0.5f,
         0.0f,  0.5f,
         0.5f, -0.5f
    };

    // 用来存储缓冲对象名称
    unsigned int VBO;
    // 生成1个缓冲对象名称,并写到bufferObject
    glGenBuffers(1, &VBO);
    // 绑定顶点缓冲到bufferObject
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 创建并初始化缓冲对象的数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(positions) * sizeof(float), positions, GL_STATIC_DRAW);

    // 开启顶点着色器的属性,不然无法显示绘制
    glEnableVertexAttribArray(0);
    // 定义顶点数据的属性,其中一个位置有2个浮点数,不需要normalized,步进为sizeof(float)*2字节
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, NULL);

    // 检查window的关闭标志
    while (!glfwWindowShouldClose(window))
    {
        // 清除屏幕颜色
        glClear(GL_COLOR_BUFFER_BIT);

        // draw call,从0开始渲染3个索引
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // 交换window的前后buffer
        glfwSwapBuffers(window);

        // 处理事件
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
原文地址:https://www.cnblogs.com/jacobchen/p/14756055.html