OpenGL 加载流程 vs OpenGL ES 加载流程

2023年 8月 18日 34.5k 0

一、OpenGL 加载流程

OpenGL的加载过程涉及多个步骤,主要包括初始化OpenGL环境、创建窗口、设置着色器和渲染循环。以下是一般情况下OpenGL加载的基本步骤:

  • 初始化库和上下文: 在开始使用OpenGL之前,首先要初始化 OpenGL 库和创建 OpenGL 上下文。这可以通过调用特定的库函数(如GLFW、SDL等)来实现。这些库负责创建窗口、管理输入和OpenGL上下文等。

    //初始化GLFW和配置
    glfwInit();					
    //使用glfwWindowHint函数来配置GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//将主版本号(Major)设为3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//次版本号(Minor)设为3
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//我们同样明确告诉GLFW我们使用的是核心模式(Core-profile)。明确告诉GLFW我们需要使用核心模式意味着我们只能使用OpenGL功能的一个子集
    
  • 创建窗口和上下文: 使用选定的库,你可以创建一个窗口,将OpenGL上下文绑定到该窗口中。上下文是OpenGL用来管理和执行图形渲染的关键环境。

    //创建一个窗口对象,这个窗口对象存放了所有和窗口相关的数据,而且会被GLFW的其他函数频繁地用到
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    
    //将我们窗口的上下文设置为当前线程的主上下文
    glfwMakeContextCurrent(window);
    
  • 加载和编译着色器: 创建和编译顶点着色器和片段着色器,这些着色器将定义你的渲染效果。通常,你需要使用GLSL(OpenGL Shading Language)编写着色器代码,然后将其加载到OpenGL中。

    传入着色器的源文件,读取文件的缓冲内容到数据流中,编译着色器

    // 2. 编译着色器
    unsigned int vertex, fragment;
    
    // 顶点着色器
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);
    checkCompileErrors(vertex, "VERTEX");
    
    // 片段着色器
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);
    checkCompileErrors(fragment, "FRAGMENT");
    
  • 创建着色器程序: 使用已编译的顶点和片段着色器,创建一个着色器程序对象。这个程序对象将管理着色器的链接和使用。

    // 着色器程序
    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    if (geometryPath != nullptr)
    {
            glAttachShader(ID, geometry);
    }
    glLinkProgram(ID);
    
  • 设置顶点数据和缓冲区: 为你的渲染创建顶点数据,例如顶点坐标、法线、纹理坐标等。将这些数据存储在缓冲区对象中,这些缓冲区可以是顶点缓冲区、索引缓冲区等。

  • 设置顶点属性指针: 将顶点数据与着色器的输入变量(如顶点坐标、法线等)关联起来。通过使用glVertexAttribPointer函数,将顶点数据绑定到顶点着色器的属性变量。

    //初始化缓冲,最终使用Draw函数绘制网格
    glGenVertexArrays(1, &VAO);//任何随后的顶点属性调用都会储存在这个VAO中
    glGenBuffers(1, &VBO);//针对缓冲ID:VBO生成一个VBO对象
    glGenBuffers(1, &EBO);
    
    glBindVertexArray(VAO);//要想使用VAO,要做的只是使用glBindVertexArray绑定VAO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);//把创建的VBO缓冲对象绑定到GL_ARRAY_BUFFER目标上
    //我们使用的任何(GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)
    //glBufferData参数:(1)目标缓冲的类型(2)传输数据的大小(3)我们希望发送的实际数据(4)希望显卡如何管理给定的数据(* GL_STATIC_DRAW :数据不会或几乎不会改变。* GL_DYNAMIC_DRAW:数据会被改变很多。* GL_STREAM_DRAW :数据每次绘制时都会改变)
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);//把之前定义的顶点数据复制到缓冲的内存中
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
    
    // 顶点位置
    glEnableVertexAttribArray(0);
    //glVertexAttribPointer参数:(1)指定我们要配置的顶点属性,具体依据着色器中的定义layout(location = 0)我们希望把数据传递到这一个顶点属性中
    //(2)顶点属性的大小VEC3,大小就是3.(3)数据的类型(4)是否希望数据被标准化(Normalize),是的话就会映射到0-1之间
    //(5)Stride步长,顶点属性组之间的间隔(6)它表示位置数据在缓冲中起始位置的偏移量
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    // 顶点法线
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));//Normal在Vertex结构体中的偏移量
    // 顶点纹理坐标
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
    // vertex tangent
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
    // vertex bitangent
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));
    
    glBindVertexArray(0);
    
  • 启用着色器和缓冲区: 启用着色器程序,让OpenGL知道你要使用哪些着色器进行渲染。还要绑定相应的缓冲区对象,以供渲染使用。

    // 程序ID
    unsigned int ID;
    glUseProgram(ID);
    
  • 设置绘制参数: 设置绘制参数,如清除颜色、深度缓冲区,设置视口、投影矩阵等。

  • 渲染循环: 进入渲染循环,即不断地绘制场景并处理输入。在每一帧中,你需要设置相应的状态、更新数据,然后调用绘制函数来执行渲染操作。

    while (!glfwWindowShouldClose(window))
    {
    ...
    }
    
  • 交换缓冲区: 在渲染完成后,使用交换缓冲区操作,将渲染结果显示在屏幕上。

  • ```
    
    glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
    ```
    

    二、OpenGL ES 加载流程

    OpenGL ES(OpenGL for Embedded Systems)是用于嵌入式系统的一种轻量级的OpenGL API。它在很大程度上与标准的OpenGL相似,但考虑了资源受限的嵌入式环境。OpenGL ES的加载过程与标准的OpenGL加载过程类似,但有一些特定的步骤和差异。以下是OpenGL ES加载过程的基本步骤:

  • 初始化库和上下文: 与标准OpenGL一样,你需要使用特定的库函数(如EGL、GLFW、SDL等)来初始化OpenGL ES库和创建OpenGL ES上下文。这些库负责创建窗口、管理输入和OpenGL ES上下文等。

  • 创建窗口和上下文: 使用选定的库,创建一个窗口,并将OpenGL ES上下文绑定到该窗口中。上下文是OpenGL ES用来管理和执行图形渲染的关键环境。

  • 加载和编译着色器: 创建和编译顶点着色器和片段着色器,同样使用GLSL编写着色器代码,然后将其加载到OpenGL ES中。OpenGL ES 2.0和3.0支持GLSL ES(OpenGL ES Shading Language)。

  • 创建着色器程序: 使用已编译的顶点和片段着色器,创建一个着色器程序对象。这个程序对象将管理着色器的链接和使用,与标准OpenGL类似。

  • 设置顶点数据和缓冲区: 为你的渲染创建顶点数据,将这些数据存储在缓冲区对象中。OpenGL ES支持顶点缓冲区、索引缓冲区等。

  • 设置顶点属性指针: 将顶点数据与着色器的输入变量关联起来,通过使用glVertexAttribPointer函数。同样,将顶点数据绑定到顶点着色器的属性变量。

  • 启用着色器和缓冲区: 启用着色器程序,绑定相应的缓冲区对象,使OpenGL ES知道你要使用哪些着色器进行渲染。

  • 设置绘制参数: 设置绘制参数,如清除颜色、深度缓冲区,设置视口、投影矩阵等,与标准OpenGL类似。

  • 渲染循环: 进入渲染循环,即不断地绘制场景并处理输入。在每一帧中,设置状态、更新数据,然后调用绘制函数进行渲染。

  • 交换缓冲区: 在渲染完成后,使用交换缓冲区操作,将渲染结果显示在屏幕上。

  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论