从0开始的OpenGL学习(一)-创建OpenGL窗口

在这里插入图片描述

1. 概述

为啥学习openGL,因为在开发QT 3D场景时,看见官方有个boxes的demo,想学习一下.

本文主要解决两个问题:

  1. OpenGL到底是什么鬼?
  2. 如何创建一个使用OpenGL的窗口?

2. OpenGL到底是什么鬼?

笔者也算是一个入门的C++程序员了,一下决心要学习OpenGL之后就直接上谷歌搜了OpenGL的官网(当然这是要翻越万里长城的),想下一个API就上手。然而在官网上溜了一大圈,楞是没找到一个下载API的地方,倒是在各种显卡厂商的官网上都转了一圈,灰头土脸。

在网上找了很多资料之后,终于明白了一点,这也是非常重要的一点,就是:OpenGL并不是一个API(API这个应该懂吧,搞编程的人都知道。什么?你说你不是搞编程的?那你看这篇文章,还不速速出门右转。)库,而是一组规范,这组规范是由Khronos Group来维护的。(别问我Khronos Group是什么鬼,对于只能写入门文字的笔者来说,这也是第一次看到。)

这组规范定义了一组函数,这组函数传入的是什么参数,传出的是什么结果。由于只是这样的一组规范,所以只要合乎规范,谁都能以不同的方式实现函数。这也就是在官网上找不到API库的原因了,通常这些API是由显卡厂商实现的。顺便说一句,如果装了VS,VS里自带有OpenGL的库(至少笔者的VS2013里有)。

状态机

OpenGL本身就是一个大状态机:有很多变量可以设置以便我们控制其操作。OpenGL的状态通常被称为上下文(context)。我们在操作OpenGL的时候就是通过改变其状态来改变其运行的上下文,这样OpenGL就能给我们想要的结果了。

3. 如何创建一个使用OpenGL的窗口?

3.1. 所需工具

GLFW库+Ubuntu16.04+GLAD源码

GLFW是一个开源的跨平台窗口库,它封装了与操作系统相关的创建窗口的过程,让我们的窗口创建只需要调用少量的函数就能实现。(妈妈再也不用担心我不会创建窗口了)

Ubuntu,基础运行系统平台,类似于Windows系统,属于一个操作系统,只不过Ubuntu是开源操作系统,不收取版权费用,最最关键的是它没有哪些烦人的打补丁操作,有时候运气不好打补丁失败还要回滚,运气差点还要重载系统…

GLAD源码是用来封装调用OpenGL库中的函数的,让我们调用OpenGL函数的时候只需要用熟悉的函数调用方式,不需要创建一个函数指针,然后加载dll中的函数地址,然后再调用。说的有点抽象啊,举个例子就知道了。原本我们的代码要是这个样子:

typedef void (*GL_GENBUFFERS)(GLsizei, GLuint*);
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
glGenBuffers(1, &buffer);   //这里才是调用函数的位置,上面只是获取函数地址

有了GLAD源码之后,我们就只需要这样子就行了:

glGenBuffers(1,&buffer);    //省去了获取函数地址的操作

3.2. 环境打造:

3.2.1 ubuntu 环境搭建

安装openGL库及依赖

sudo apt-get install build-essential
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libglu1-mesa-dev

3.2.2 GLFW库

第一步:下载GLFW

CSDN本地资源包:

  • 下载方式1:

CSDN本地资源包 : glfw-3.3.3.tar.gz

  • 下载方式2:

官网地址是:http://www.glfw.org/download.html(你需要翻墙才能访问)
选择下载源文件,文件包名为glfw-3.2.1.zip

第二步:下载CMake,编译glfw的源码

Ubuntu下安装CMake超级简单:

sudo apt-get install cmake

第三步:下载GLAD
下载方式1:

CSDN资源 : glad.zip

下载方式2:

GLFW的源码是需要通过CMake来编译的,所以我们刚才需要安装一个CMake.
官网地址:http://glad.dav1d.de/(继续翻),选择好需要的版本和模式
在这里插入图片描述

点击页面最下方右下角的GENERATE按钮,在随后弹出的页面中,点击glad.zip进行下载
在这里插入图片描述
第四步:编译并运行
gitee整合后代码:
https://gitee.com/pengrui2009/open-gl-study.git

git clone https://gitee.com/pengrui2009/open-gl-study.git
cd open-gl-study/OpenGL
cd assimp-3.3.1 && mkdir build && cd build && cmake .. && make
cd glfw-3.3.3 && mkdir build && cd build && cmake .. && make
cd glm-0.9.8.0 && mkdir build && cd build && cmake .. && make
cd ../
mkdir third_party
mkdir third_party/include
mkdir third_party/library
cp OpenGL/glfw-3.3.3/build/src/libglfw3.a ./third-party/library
cp -a OpenGL/glfw-3.3.3/include/GLFW third-party/include
cp -a OpenGL/assimp-3.3.1/build/code/libassimp.so* third-party/library/
cp -a OpenGL/assimp-3.3.1/include/assimp third-party/include
cp -a OpenGL/glm-0.9.8.0/glm third-party/include
cp -a OpenGL/glad/include/* third-party/include
#将glad.c文件放置在工作根目录下
cp -a OpenGL/glad/src/glad.c .

完成之后,我们的OpenGL基础编译环境就搭建完成了.

第六步:创建一个测试验证文件
新建cpp文件,取名为main.cpp,在main函数中加入如下代码

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


void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
}

int main()
{
    glfwInit();
    //指定OpenGL的主版本号
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    //指定OpenGL的子版本号
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    //使用OpenGL的核心模式(可编程渲染管道的模式)
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //创建窗口
    GLFWwindow *window = glfwCreateWindow(1280, 720, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        //如果出错,则终止进程
        glfwTerminate();

        return -1;
    }

    //将窗口的上下文环境设置为当前主线程的上下文环境
    glfwMakeContextCurrent(window);

    //初始化glad
    if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    //注册窗口回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    //渲染循环
    //检测是否关闭窗口
    while(!glfwWindowShouldClose(window))
    {
        //处理输入事件
        processInput(window);

        glClearColor(1.0f, 1.0f, 0.0f, 1.0f);

        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    //终止进程
    glfwTerminate();

    return 0;
}

其中framebuffer_size_callback和processInput是两个处理消息的函数
framebuffer_size_callback函数:用于当窗口大小改变时,改变OpenGL视口的区域大小
processInput函数:处理输入事件

第七步: 编译
编写Makefile,内容如下

all:
	gcc -c -o glad.o glad.c third-party/library/libglfw3.a -Ithird-party/include -Ithird-party/library -lGL  -lm -ldl -lpthread -lX11
	g++ -c -o brave_world.o brave_world.cpp third-party/library/libglfw3.a -Ithird-party/include -Lthird-party/library/ -Iparty/include -lGL  -lm -ldl -lpthread -lX11 -std=c++11
	g++ -o brave_world brave_world.o glad.o third-party/library/libglfw3.a -Ithird-party/include -Lthird-party/library/ -lassimp -lGL  -lm -ldl -lpthread -lX11
clean:
	-rm -fr *.o

make all

第八步:运行

./brave_world

4. 运行效果

效果如下:
在这里插入图片描述

5. 总结

好了,到此为止,我们已经成功创建了一个使用OpenGL的窗口,万里长征终于走出了第一步。歇口气,休息一会再学下一章!

本章节工程源代码:

https://gitee.com/pengrui2009/open-gl-study/tree/master/chapter1

6. 参考资料:

1.learnopengl.com(这是一个非常不错的网站,笔者就是在这个网站上学的,这一系列的文章大部分是参考这里的内容,强烈推荐想学的小伙伴去这里学)
2. 这里主要参考了闪电的蓝熊猫的博客,只是适配了Ubuntu系统平台, 链接:https://www.jianshu.com/p/d83a519ae2d0

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
作为一个AI,我无法直接操作OpenGL,但我可以提供一些基本的代码帮助你创建两个窗口。以下是一个用glad创建两个窗口的示例: ```c++ #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; int main() { // 初始化GLFW glfwInit(); // 配置GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 创建第一个窗口 GLFWwindow* window1 = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Window 1", NULL, NULL); if (window1 == NULL) { std::cout << "Failed to create GLFW window1" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window1); // 初始化GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // 设置视口大小 glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // 注册窗口大小改变的回调函数 glfwSetFramebufferSizeCallback(window1, framebuffer_size_callback); // 创建第二个窗口 GLFWwindow* window2 = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Window 2", NULL, window1); if (window2 == NULL) { std::cout << "Failed to create GLFW window2" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window2); // 初始化GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // 设置视口大小 glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // 注册窗口大小改变的回调函数 glfwSetFramebufferSizeCallback(window2, framebuffer_size_callback); // 循环渲染 while (!glfwWindowShouldClose(window1) && !glfwWindowShouldClose(window2)) { // 处理输入 processInput(window1); processInput(window2); // 清除颜色缓冲区 glClear(GL_COLOR_BUFFER_BIT); // 交换缓冲区 glfwSwapBuffers(window1); glfwSwapBuffers(window2); // 检查并调用事件 glfwPollEvents(); } // 清理所有资源 glfwTerminate(); return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } ``` 这个示例中创建了两个窗口,第一个窗口为主窗口,第二个窗口作为第一个窗口的子窗口。两个窗口的渲染和输入处理是分开的,但它们共享OpenGL上下文。在这个示例中,同时按下Esc键会关闭两个窗口

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值