zoukankan      html  css  js  c++  java
  • 为什么说使用 Linux 系统学习 OpenGL 更方便

    前言

    上一篇随笔介绍了我的电脑,同时也介绍了 Ubuntu 20.10 系统的安装和美化。这一篇,我将正式开始 OpenGL 之旅。使用 Ubuntu 来进行开发,不仅仅只是因为我对 Linux 桌面比较熟悉,其实我对 Windows 也很熟悉,主要还是因为在 Linux 系统下搭建 OpenGL 的开发环境确实是太方便了。在 Windows 下开发 OpenGL,每用到一个库,我们都要单独去搜索和下载,然后在 Visual Studio 中进行设置,很繁琐。在 Ubuntu 中,安装这些库,就是一条命令的事,下面详细论述。

    搭建 OpenGL 的开发环境

    学 OpenGL,C/C++ 应该是首选,所以先安装 C/C++ 的开发环境,无论是选择 GCC,还是选择 CLang,在 Ubuntu 中就是一条命令的事,我这里选 GCC。在 Ubuntu 中,可以直接安装 build-essential,更省事。命令如下:

    sudo apt install build-essential
    

    OpenGL 不提供和 GUI 相关的 API,所以 OpenGL 不能处理诸如创建窗口、处理用户的键盘鼠标输入这样的任务。这时,我们需要 GLFW。使用 GLFW 库,我们可以简化搭建 OpenGL 程序框架的任务,同时还可以轻松获得跨平台的功能。安装 GLFW 也是一条命令的事:

    sudo apt install libglfw3 libglfw3-dev
    

    除此之外,我们还需要 GLEW。有了GLEW 扩展库,就再也不用为找不到函数的接口而烦恼了,因为GLEW能自动识别平台所支持的全部 OpenGL 高级扩展涵数。安装命令如下:

    sudo apt install libglew2.1 libglew-dev
    

    另外,在写 OpenGL 程序的过程中,会经常需要进行向量、矩阵的计算,所以有一个顺手的数学库是很重要的,我这里选择 GLM。安装命令如下:

    sudo apt install libglm-dev
    

    学会了 OpenGL 的基本概念后,当然会忍不住想加载个 3D 模型看看效果,这时候,就可以考虑使用 Assimp 库了。安装命令如下:

    sudo apt install assimp-utils libassimp5 libassimp-dev
    

    assimp-utils 包提供了一个assimp命令,使用该命令可以显示 Assimp 库支持哪些格式的 3D 模型文件,也可以使用该命令显示 3D 模型文件的详细信息,如下图:

    当然,3D 的东西,还是应该用可视化的方式看起来更直观一些。好在,Linux 中可用的 3D 建模动画软件有 Blender。安装起来也只是一条命令的事:

    sudo apt install blender
    

    下面,让大家看一下我的老婆,用的就是 Blender:

    最简单的 OpenGL 程序框架

    下面,开始写我们的第一个 OpenGL 程序,如下:

    #include <iostream>
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    const int SCR_WIDTH = 1920;
    const int SCR_HEIGHT = 1080;
    
    int main(int argc, char** argv){
        glfwInit();
        GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", nullptr, nullptr);
        if (window == NULL)
        {
            std::cerr << "Failed to create GLFW window" << std::endl;
            glfwTerminate();
            return -1;
        }
        glfwMakeContextCurrent(window);
    
        if(glewInit() != GLEW_OK){
            std::cerr << "Failed to initalize GLEW" << std::endl;
            return -1;
        }
    
        while (!glfwWindowShouldClose(window))
        {
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    
        glfwDestroyWindow(window);
        glfwTerminate();
        return 0;
    }
    

    这段程序比较短,使用任何编辑器如 vim、gedit 等等都可以。当后面程序变长之后,我选择使用 Visual Studio Code。我们将这个文件保存为 FirstStep.cpp。编译执行的命令也很简单:

    g++ FirstStep.cpp -o FirstStep -lGL -lGLEW -lglfw
    ./FirstStep
    

    就可以看到我们的第一个 OpenGL 窗口了,目前,它还只是空洞洞的漆黑一片,如下图:

    因为我是 4K 屏,所以即使定义了SCR_WIDTH = 1920SCR_HEIGHT = 1080,窗口看起来也不是特别大。上面那个程序是纯 C 版的,等程序变大之后,会在 main() 函数之外遗留很多全局的变量和函数,不是那么清爽,所以常规会使用 C++ 封装一下,建立一个 App 类,以后要添加鼠标键盘输入的功能也在这个类里面加,建立新程序时,只需要继承这个类就可以了。App 类的内容如下:

    #ifndef __APP_HPP__
    #define __APP_HPP__
    
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    #include <iostream>
    
    class App{
        private:
            const int SCR_WIDTH = 1920;
            const int SCR_HEIGHT = 1080;
            
        public:  
        	static App* the_app;
        	
            App(){
    
            }
    
            virtual void init(){
                
            }
            
            virtual void display(){
                
            }
    
    
            virtual void run(App* app){
                if(the_app != NULL){ //同一时刻,只能有一个App运行
                    std::cerr << "The the_app is already run." << std::endl;
                    return;
                }            
                the_app = app;
                
                glfwInit();
                GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", NULL, NULL);
                if (window == NULL)
                {
                    std::cerr << "Failed to create GLFW window" << std::endl;
                    glfwTerminate();
                    return;
                }
                glfwMakeContextCurrent(window);
                if(glewInit() != GLEW_OK){
                    std::cerr << "Failed to initalize GLEW" << std::endl;
                    return;
                }
    
                init(); //用来准备各种数据
    
                while (!glfwWindowShouldClose(window))
                {
    
                    display(); //这里才是渲染图形的主战场 
                                   
                    glfwSwapBuffers(window);
                    glfwPollEvents();
                }
                glfwDestroyWindow(window);
    
                glfwTerminate();
                return;
            }
    
    };
    
    App* App::the_app = NULL;
    
    #define DECLARE_MAIN(a)                             
    int main(int argc, const char ** argv)              
    {                                                   
        a *app = new a;                                 
        app->run(app);                                  
        delete app;                                     
        return 0;                                       
    }
    
    #endif
    

    把这个文件保存在 include 目录下,命名为 app.hpp,然后,把之前的 FirstStep.cpp 改成如下内容:

    #include "../include/app.hpp"
    
    class MyApp : public App {
        private:
            
        public:
            void init(){
    
            }
    
            void display(){
    
            }
    
            ~MyApp(){
    
            }
    
    };
    
    
    DECLARE_MAIN(MyApp)
    

    编译运行,结果是一样的。以后,只需要把初始化数据的代码放到 init() 方法中,把渲染图形的代码放到 display() 方法中即可。程序运行时,init() 方法只调用一次,而 display() 方法每渲染一帧图像就调用一次。

    OK,到这里,我们的环境就搭建好了。在下一篇随笔中,我们争取使用 OpenGL 渲染一点有用的东西。

    版权申明

    该随笔由京山游侠在2021年01月27日发布于博客园,引用请注明出处,转载或出版请联系博主。QQ邮箱:1841079@qq.com

  • 相关阅读:
    bootstarp3
    Python高级编程技巧
    Python高级编程技巧
    Python面向对象编程
    Python面向对象编程
    Python面向对象编程
    Python面向对象编程
    文件读写
    Python函数-7 内置函数
    Python函数-6 装饰器
  • 原文地址:https://www.cnblogs.com/youxia/p/cg002.html
Copyright © 2011-2022 走看看