zoukankan      html  css  js  c++  java
  • OpenGL教程(2)——第一个窗口

    注:本文可转载,转载请注明出处:http://www.cnblogs.com/collectionne/p/6618419.html

    OpenGL环境终于配置好了,现在我们可以开始学习OpenGL了。

    首先,创建一个.cpp文件,然后打上几行#include指令:

    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>

    先从<iostream>说起。其实<iostream>不是必须的,这里包含它,是因为后面可能需要在控制台上打印信息,提醒用户。glew.h和glfw3.h是我们上一篇教程里所下载的头文件,注意一定要先包含glew.h,再包含glfw3.h(因为glfw3.h会包含gl.h,而这是glew.h不允许的)。最后,如果你使用的是静态版的GLEW,需要在包含glew.h前加上下面的#define指令:

    #define GLEW_STATIC

    然后我们进入main()函数:

    int main()
    {

    GLFW

    首先我们需要初始化GLFW:

    if (!glfwInit())
    {
        cout << "Failed to initialize GLFW!
    ";     
        return -1;
    }

    glfwInit()函数用于初始化GLFW,在调用大部分其它GLFW函数前,都需要初始化GLFW。glfwInit()如果成功,将会返回GLFW_TRUE,否则返回GLFW_FALSE(GLFW_TRUE和GLFW_FALSE是GLFW定义的常量,被定义为于1和0)。也就是说,如果返回GLFW_FALSE,就说明初始化失败,这时我们将打印一条信息告知用户GLFW初始化失败,并且返回(注意,你可能无法看到打印的信息,这时可以在return -1前加上一句cin.get()或system("pause")暂停程序)。不过,检查返回值也不是必须的。

    然后我们需要使用glfwWindowHint()函数设置hint:

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    Hint直接翻译成中文是“线索”,这里大致指“选项”。使用glfwWindowHint()可以设置一些关于窗口的选项。glfwWindowHint()接受两个参数,第一个是我们要设置的hint的名字,使用GLFW常量(以GLFW_开头)指定;第二个是我们要把该hint设置成的值,该值随要设置的hint而异。

    Hint也有很多种,这里我们只设置了4种,分别是OpenGL主版本号(GLFW_CONTEXT_VERSION_MAJOR)、OpenGL副版本号(GLFW_CONTEXT_VERSION_MINOR)、OpenGL模式(GLFW_OPENGL_PROFILE)、窗口是否可调整大小(GLFW_RESIZABLE)。这4个hint,我们分别设置为3、3、GLFW_CORE_PROFILE、GLFW_FALSE。

    因为我们要使用OpenGL 3.3,所以我们把GLFW_CONTEXT_VERSION_MAJOR和GLFW_CONTEXT_VERSION_MINOR对应的hint都设置为3。因为我们要使用OpenGL核心模式(这个后面会提到更多),所以我们把GLFW_OPENGL_PROFILE对应的hint设置为GLFW_OPENGL_CORE_PROFILE,表示使用OpenGL核心模式。最后,把GLFW_RESIZABLE对应的hint设置为GLFW_FALSE,表示窗口不允许用户调整大小。之所以这样做是因为如果允许用户调整大小,大小发生变化后,窗口的绘制区域默认不变(依然是原来窗口的区域),也就是说窗口上绘制的图像的大小、位置不会发生改变。为了避免这种现象发生,我们就简单地不让用户调整窗口大小(当然也有更好的方法,就是用GLFW设置一个窗口大小的回调函数,但这样比较简单)。

    注意,如果你使用Mac OS X,你需要再加上下面这句调用:

    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

    然后就该创建窗口了:

    GLFWwindow * window = glfwCreateWindow(800, 600, "First window", nullptr, nullptr);
    if (window == nullptr)
    {
        cout << "Failed to create window using GLFW!
    ";
        return -1;
    }

    glfwCreateWindow()接受5个参数。第一个、第二个是窗口的宽和高,以像素为单位,这里分别是800和600;第三个是窗口标题,这里是"First window";第四个和第五个参数可以忽略,直接传入nullptr。

    glfwCreateWindow()将会使用前面glfwWindowHint()所设置的hint创建窗口,返回一个GLFWwindow指针,我们把这个指针叫做窗口句柄(window handle)。简单说来,就是从此以后我们都用它来代表我们的窗口,后面会需要对窗口进行设置、询问一些关于窗口的信息,就需要传入这个指针。如果创建窗口出现问题,将返回NULL(C++里就是nullptr),因此如果window为nullptr,说明创建窗口失败,打印错误信息,返回-1。

    创建完毕之后,需要让当前窗口的环境在当前线程上成为当前环境(说法有点复杂,不太严谨地说,就是接下来的画图都会画在我们刚刚创建的窗口上):

    glfwMakeContextCurrent(window);

    GLEW

    GLFW设置完毕后,还需要初始化GLEW:

    glewExperimental = GL_TRUE;
    if (glewInit())
    {
        cout << "Failed to init GLEW!
    ";
        return -1;
    }

    首先我们把glewExperimental设置为GL_TRUE,这样GLEW就会使用更加新的方法管理OpenGL,减少错误。然后调用glewInit()初始化GLEW。注意glewInit()成功返回0,失败返回1,与GLFW相反。如果失败则输出错误信息,并返回-1。

    游戏循环

    和控制台程序不同,我们希望这个程序可以一直运行,直到用户关闭窗口。这样我们就需要创建一个循环,叫做游戏循环(game loop)。

    while (!glfwWindowShouldClose(window))
    {
    glfwSwapBuffers(window); glfwPollEvents(); }

    glfwWindowShouldClose()检查窗口是否需要关闭。如果是,游戏循环就结束了,接下来我们将会清理资源,结束程序。

    glfwSwapBuffers()用来交换窗口的两个颜色缓冲(color buffer)。这个概念叫做双缓冲(double buffer)。如果不使用双缓冲,就可能会出现闪屏现象,因为绘制一般不是一下子就绘制完毕的,而是从左到右、从上到下地绘制。为了避免这个问题,一般会使用双缓冲,前缓冲(front buffer)是最终的图像,而程序会在后缓冲(back buffer)上绘制。后缓冲绘制完毕后,就交换两个缓冲,这样就不会有闪屏的问题了。

    glfwPollEvents()用来检查是否有事件被触发,例如点击关闭按钮、点击鼠标、按下键盘,等等。如果有,GLFW将会对这些事件进行处理。更严谨地说(以键盘、鼠标键为例),GLFW自己会记录每个键、鼠标键的状态(按下/没有按下),但当某个按键松开或被按下时,GLFW不会自动更新状态,必须调用glfwPollEvents()才能更新。调用glfwPollEvents()时会检查状态是否有变化(如按下的是否松开,没有按下的是否被按下),如果有就会更新该状态。如果设置了回调函数(这个将在以后讲),还会调用相应的回调函数。如果不调用这个函数,不仅无法检测输入(后文会需要这样),我们在点击窗口右上角的X时,GLFW也不会知道需要关闭窗口。所以必须在每一轮游戏循环中调用这个函数。

    最后,当循环执行完毕后,我们需要释放前面所申请的资源:

    glfwTerminate();
    return 0;
    }

    glfwTerminate()将会释放所有GLFW资源,关闭当前窗口。然后程序就成功退出了。

    现在运行你的程序,如果你得到了一个黑色窗口,恭喜你,成功了!如果没有,请参考结尾的代码,对照自己的代码。

    额外的东西

    现在我们已经成功创建窗口,并且在用户点击右上角的X时退出。但是还不够——你可能会问,可不可以让用户按ESC键时退出,或者换一个窗口背景颜色?这里我们就来实现这两项。

    关于第一个功能,可以这样写(在游戏循环里):

    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GLFW_TRUE);

    glfwGetKey()用来判断一个键是否按下。第一个参数是GLFW窗口句柄,第二个参数是一个GLFW常量,代表一个键。GLFW_KEY_ESCAPE表示Esc键。如果Esc键按下了,glfwGetKey将返回GLFW_PRESS(值为1),否则返回GLFW_RELEASE(值为0)。

    如果Esc被按下了,我们就会调用glfwSetWindowShouldClose()函数,为窗口设置关闭标志。第一个参数是窗口句柄,第二个参数表示是否关闭,这里为GLFW_TRUE,表示关闭该窗口。注意,这时窗口不会立即被关闭,但是glfwWindowShouldClose()将返回GLFW_TRUE,到了glfwTerminate()就会关闭窗口。

    关于第二个功能,可以在进入游戏循环之前,加一句:

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

    与其它glfw开头的函数(这些函数由GLFW提供)不同,这个函数是以gl开头的,是OpenGL的函数。glClearColor用来设置窗口被清除时的颜色,也就是背景颜色。前3个参数分别是背景颜色的R、G、B分量,范围是0~1;第4个是alpha值表示透明度,这里只是设为1.0f,表示不透明。(0.2, 0.3, 0.3)这一颜色大致是较暗的蓝绿色。

    然后在游戏循环中加一句:

    glClear(GL_COLOR_BUFFER_BIT);

    这将会清除当前窗口,把所有像素的颜色都设置为前面所设置的清除颜色。GL_COLOR_BUFFER_BIT是OpenGL定义的常量,表示清除颜色缓存。后面会学到,还有GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。

    现在运行程序,你应该会得到下面的画面,并且按Esc时会关闭窗口:

    最终代码

    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    int main()
    { 
        // init GLFW
        if (!glfwInit())
        {
            cout << "Failed to init GLFW!
    ";
            return -1;
        }
    
        // set window hints
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    // create the window GLFWwindow * window = glfwCreateWindow(800, 600, "First window", nullptr, nullptr); if (window == nullptr) { cout << "Failed to create window using GLFW! "; return -1; } glfwMakeContextCurrent(window); // init GLEW glewExperimental = GL_TRUE; if (glewInit()) { cout << "Failed to init GLEW! "; return -1; } // set clear color glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // game loop while (!glfwWindowShouldClose(window)) { // if Esc is pressed, close the window if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); // clear the window glClear(GL_COLOR_BUFFER_BIT); // poll and swap glfwSwapBuffers(window);
    glfwPollEvents(); }
    // cleanup glfwTerminate(); return 0; }

    好啦,你已经学会了创建窗口的基本技巧,下一课,我们将会学习如何画我们的第一个三角形!

  • 相关阅读:
    一个转角--->程序猿
    一个转角--->程序猿
    科技申报项目总结
    科技申报项目总结
    mysql事务
    mysql事务
    浅谈SSM框架
    浅谈SSM框架
    Spring-IOC(解释依赖注入DI)
    Maven基础知识,如何搭建Maven环境,Maven常用命令,如何搭建一个Maven项目
  • 原文地址:https://www.cnblogs.com/collectionne/p/6618419.html
Copyright © 2011-2022 走看看