欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenGL基础2:OpenGL简介

程序员文章站 2022-07-04 12:22:55
...

 

小朋友你是否有很多问号,不知道为什么需要这么多复杂的方法,也不知道为什么要这么设计,更不知道仅仅显示一个点都那么复杂,后面3D游戏中的那么精美的表现是否离自己很远很远……要不,再来一起看看openGL?

其实看到这里,你应该也像我一样,装好了环境,并且成功打开了第一个窗口,又或者说已经可以开始绘制一些非常基础的单元了,但是刚入门你应该也一样,对着一堆方法一脸懵逼,看着讲解和教程似乎也能理解,但是脱离教程就会发现自己一行代码都弄不出来,还是需要不断地去参考。

一、OpenGL简介

  • OpenGL 和显卡密切相关,那么当然,OpenGL 的开放商往往都是显卡的生产商,像我们平时玩不了某些游戏可能就会让你去更新显卡驱动,这些显卡驱动里面往往就带着了最新的 openGL
  • 与其说 OpenGL 是一个 API,包含了一系列可以操作图形图像的函数,不如说 OpenGL 是一个规范,它严格规定了每个函数该如何执行,以及它们的输出值
  • OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲,最后我们使用当前OpenGL上下文来渲染

OpenGL 现在最高版本已经到 4.6 了,但是我们只要确保是 3.3 以后的版本即可,为什么拿 3.3 版本做为分界?

早期的 OpenGL 使用立即渲染模式(Immediate mode,也就是固定渲染管线),这个模式下绘制图形很方便。OpenGL 的大多数功能都被库隐藏起来,开发者很少能控制 OpenGL 如何进行计算的*。

然开发者迫切希望能有更多的灵活性,随着时间推移,规范越来越灵活,开发者对绘图细节有了更多的掌控。立即渲染模式确实容易使用和理解,但是效率太低。因此从 OpenGL3.2 开始,规范文档开始废弃立即渲染模式,推出核心模式(Core-profile),这个模式完全移除了旧的特性。当使用 OpenGL 的核心模式时,OpenGL 迫使我们使用现代的函数。当我们试图使用一个已废弃的函数时,OpenGL 会抛出一个错误并终止绘图。

现代函数的优势是更高的灵活性和效率,然而也更难于学习。立即渲染模式从 OpenGL 实际运作中抽象掉了很多细节,因而它易于学习的同时,也很难去把握 OpenGL 具体是如何运作的。现代函数要求使用者真正理解 OpenGL 和图形编程,它有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。

 

二、再讲讲状态机

其实有个很好理解状态机的方法:

  1. 我要红色 → OK(给你换成了红色的颜料桶)
  2. 我要画条线 → OK(后面你要是给我3个点,我肯定不回给你画个三角形出来)
  3. 我想启用光照 → OK(尽管好像你只是画个线段,要光照干嘛)
  4. 我现在后悔了,想要绿色 → OK(没问题,给你换)

……………… 过了好久好久

  • 给了你顶点数据,开始画吧! → OK(一条绿色的线出现在屏幕中)

是的状态机即使如此,除非有新的命令,否则永远维持当前的状态,当然这些状态是有保存的,我们也可以随时查询

当使用OpenGL的时候,我们会遇到一些状态设置函数(State-changing Function),这类函数将会改变上下文,以及状态应用函数(State-using Function),这类函数会根据当前 OpenGL 的状态执行一些操作,只要知道 OpenGL 本质上是个大状态机,就能更容易理解它的大部分特性

很明显,glClearColor 函数就是一个状态设置函数,而 glClear 函数则是一个状态应用的函数

 

三、GLFW、GLEW

前面已经一句话介绍过了,考虑到 GLFW 其实就是 GLUT 的升级版,GLEW 就是 GLAD 的升级版,所以理论上我们只需要考虑 GLFW 和 GLEW 就可以了

GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入

然而由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询,这样特别的复杂和繁琐,我们在每次使用函数前都需要进行类似的操作,因此就需要GLEW来帮我们简化这个过程

 

四、打开一个可控制关闭的窗口

glfw 部分

  • glfwWindowHint:glfw 初始化的一部分,第一个参数代表名称,第二个参数为对应的值,用于对 glfw 进行配置,例如我们需要告诉 glfw 我们要使用的 OpenGL 版本是 3.3,这样 GLFW 会在创建 OpenGL 上下文时做出适当的调整,以及不允许用户调整窗口大小等
  • glfwCreateWindow:glfw 创建窗口,前两个参数表示窗口大小,第三个为窗口名称,后面两个参数暂时忽略,传空即可
  • glfwMakeContextCurrent(window)  通知 glfw 将我们窗口的上下文设置为当前线程的主上下文(当调用 OpenGL 的函数时,必须要有一个正确类型的当前上下文,并且在同一时间只有一个上下文可以被设置为一个单线程的当前上下文,每个线程在同一时间也只能拥有一个当前上下文
  • glViewport(0, 0, width, height)初始化视口,前两个参数为视口相对于窗口左下角的位置,后两个参数表示大小,视口可以是任意大小,一般来讲默认和窗口大小一致就好了
  • glfwWindowShouldClose:检查  glfw 是否被要求退出,样例中用作循环的判定
  • glfwPollEvents:检查是否有触发什么事件(比如键盘输入、鼠标移动等),然后调用对应的回调函数(可以通过回调方法手动设置),一般在游戏循环的开始调用事件处理函数
  • glfwTerminate:释放 glfw 分配的内存

#pragma comment(lib,"glew32.lib")
#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include<opengl/freeglut.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    std::cout << key << std::endl;
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

const GLuint WIDTH = 800, HEIGHT = 600;

int main()
{
    std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    if (glewInit() != GLEW_OK)
    {
        std::cout << "Failed to initialize GLEW" << std::endl;
        return -1;
    }

    // Define the viewport dimensions
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(1, 1, width, height);

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents();

        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Swap the screen buffers
        glfwSwapBuffers(window);
    }

    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
}

 

参考文献:https://learnopengl.com/#!Getting-started/OpenGL

相关标签: # openGL openGL