基于Ubuntu搭建OpenGL开发环境

1. 引言

笔者这里基于Ubuntu 20.04.3 LTS系统,搭建OpenGL开发环境,主要使用的库有GLFW和GLAD

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

由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用,取得地址的方法代码非常复杂,而且很繁琐,GLAD是一个开源的库,能解决这个繁琐的问题

2. 编译GLFW

结合GLFW官网的编译指南:GLFW: Compiling GLFW ,使用CMake进行编译

  • Ubuntu也可以直接安装libglfw3-dev

    $ sudo apt-get install libglfw3-dev
    

2.1 安装依赖

根据系统与窗体系统进行选择依赖并安装

Linux上的窗体系统主要有X11和Wayland两种,判断Linux系统的窗体系统可以使用以下方式:

在X11系统上

$ echo $XDG_SESSION_TYPE
x11

在某些Wayland系统上

$ echo $XDG_SESSION_TYPE
wayland

资料参考:linux - How to know whether Wayland or X11 is being used - Unix & Linux Stack Exchange

Ubuntu 20.04.3 LTS系统也可以在设置-关于里查看:

image-20220630181430972

如图,笔者这里是X11,按照编译指南,笔者这里安装xorg-dev

$ sudo apt install xorg-dev

2.2 源码下载

GLFW提供了Github地址:glfw/glfw: A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input (github.com)

这里笔者使用Git进行clone

首先下载Git:

$ sudo apt install git

然后下载源代码:

$ git clone https://github.com/glfw/glfw
  • 当然也可以直接去下载源代码压缩包

2.3 代码编译

首先安装CMake:

$ sudo apt install cmake

然后切换到源代码文件并进行构建(到build目录)

$ cd glfw
$ cmake -S . -B build

切换到build目录进行编译

$ cd build
$ make

安装到系统目录

$ sudo make install
[ 24%] Built target glfw
[ 26%] Built target boing
[ 28%] Built target gears
[ 30%] Built target heightmap
[ 32%] Built target sharing
[ 35%] Built target triangle-opengles
[ 39%] Built target particles
[ 41%] Built target splitview
[ 43%] Built target triangle-opengl
[ 45%] Built target offscreen
[ 47%] Built target wave
[ 49%] Built target windows
[ 51%] Built target window
[ 53%] Built target triangle-vulkan
[ 55%] Built target title
[ 57%] Built target tearing
[ 59%] Built target allocator
[ 62%] Built target clipboard
[ 64%] Built target joysticks
[ 68%] Built target events
[ 71%] Built target msaa
[ 74%] Built target glfwinfo
[ 77%] Built target iconify
[ 79%] Built target reopen
[ 81%] Built target gamma
[ 84%] Built target monitors
[ 86%] Built target timeout
[ 89%] Built target inputlag
[ 92%] Built target threads
[ 94%] Built target cursor
[ 97%] Built target empty
[100%] Built target icon
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/libglfw3.a
-- Installing: /usr/local/include/GLFW
-- Installing: /usr/local/include/GLFW/glfw3.h
-- Installing: /usr/local/include/GLFW/glfw3native.h
-- Installing: /usr/local/lib/cmake/glfw3/glfw3Config.cmake
-- Installing: /usr/local/lib/cmake/glfw3/glfw3ConfigVersion.cmake
-- Installing: /usr/local/lib/cmake/glfw3/glfw3Targets.cmake
-- Installing: /usr/local/lib/cmake/glfw3/glfw3Targets-noconfig.cmake
-- Installing: /usr/local/lib/pkgconfig/glfw3.pc

编译GLFW完成

3. 配置GLAD

配置GLAD需要设置OpenGL版本,可以通过glxinfo查看

有关glxinfo,可以参考:Linux下的OpenGL——Mesa和GLX简介 - SZ神庙-SZ神庙 (sztemple.cc)

安装glxinfo:

$ sudo apt install mesa-utils

查看OpenGL版本:

$ glxinfo | grep "OpenGL version"
OpenGL version string: 4.1 (Compatibility Profile) Mesa 21.0.3

可以看到笔者的是4.1

进入GLAD官网:https://glad.dav1d.de

设置好相应参数

image-20220630185522061

点击GENERRATE生成对应的zip文件并下载

解压这个zip文件,可以一个包含includesrc的文件夹,将include下的文件移动到系统目录下:

$ sudo mv include/* /usr/local/include

src目录下的glad.c文件稍后放置在工程文件中

4. 测试环境

新建一个目录并且创建CMakeLists.txtmain.cpp,并且将GLAD中的glad.c文件移动过来

$ mkdir code
$ touch CMakeLists.txt main.cpp
$ mv <glad_path>/src/glad.c glad.c

编写代码:

main.cpp (复制自:OpenGL画三角形_YY_oot的博客-CSDN博客_opengl画三角形)

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 顶点着色器,GLSL语言
const char *vertexShaderSource = "#version 330 core\n" 
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" 
    "}\0";
// 片元着色器
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

int main()
{
    // glfw: initialize and configure
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // glfw window creation
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // glad: load all OpenGL function pointers
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }


    // build and compile our shader program
    // ------------------------------------
    // vertex shader
    int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 把这个着色器源码附加到着色器对象。着色器对象,源码字符串数量,VS真正的源码
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader
    int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    int shaderProgram = glCreateProgram(); // shaderProgram 是多个着色器合并之后并最终链接完成的版本
    glAttachShader(shaderProgram, vertexShader); // 附加
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    float vertices[] = {
        -0.5f, -0.5f, 0.0f, // left  
         0.5f, -0.5f, 0.0f, // right 
         0.0f,  0.5f, 0.0f  // top   
    }; 

    unsigned int VBO, VAO;
	//创建VAO对象
    glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);
	//创建VBO对象,把顶点数组复制到一个顶点缓冲中,供OpenGL使用
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // 缓冲绑定到GL_ARRAY_BUFFER
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 顶点数据复制到缓冲的内存中
 
	//解释顶点数据方式
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 顶点数据的解释
    glEnableVertexAttribArray(0);

    // 解绑VAO
	glBindVertexArray(0); 
	// 解绑VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // draw our first triangle
        glUseProgram(shaderProgram); // 激活shaderProgram,怎么画
        glBindVertexArray(VAO); // 画什么
        glDrawArrays(GL_TRIANGLES, 0, 3); // 开始画

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // optional: de-allocate all resources
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);
    glfwTerminate();
    
    return 0;
}

//键盘按键回调函数  
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

//调整窗口大小回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)

project(test)

find_package(glfw3 REQUIRED)

file(GLOB project_file glad.c main.cpp)
add_executable(${PROJECT_NAME} ${project_file})

target_link_libraries(${PROJECT_NAME} glfw)

创建构建目录build并编译

$ mkdir build
$ cd build
$ cmake ..
$ make

如果一切顺利的话将会产生可执行文件test

运行test:

$ ./test

产生的结果图:

image-20220630234221551

5. 参考资料

[1]Ubuntu下搭建OpenGL开发环境(GLFW_3.3.1 + GLM_0.9.9 + GLAD)_小强的机器人工坊的博客-CSDN博客

[2]OpenGL画三角形_YY_oot的博客-CSDN博客_opengl画三角形

[3]创建窗口 - LearnOpenGL CN (learnopengl-cn.github.io)

[4]juliettef/GLFW-CMake-starter: Use CMake to create a project with GLFW - Multi-platform Windows, Linux and MacOS. (github.com)

[5]Linux下的OpenGL——Mesa和GLX简介 - SZ神庙-SZ神庙 (sztemple.cc)

[6]glfw/glfw: A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input (github.com)

[7]linux - How to know whether Wayland or X11 is being used - Unix & Linux Stack Exchange

posted @ 2022-06-30 23:48  当时明月在曾照彩云归  阅读(4193)  评论(2编辑  收藏  举报