zoukankan      html  css  js  c++  java
  • OpenGL(一) 渲染循环创建窗口

    OpenGL(一) 渲染循环创建窗口

    注:本文仅供自己以及OPENGL初学者共同学习进步,并无实际教学意义,不过会对自己学习中遇到的关键点加上个人解释。应该会对初学者有所帮助,如有错误请指正!

    https://jveilcoo.github.io/XQ.github.io/categories/ 观看更清晰
    上次我们已经配置好了glfw + glad环境,接下来就是我们实践使用的时候了。


    首先,我们先将要使用的头文件加进来,注意,这里先后顺序不能错:

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

    然后我们开始进入main()函数,初始化glfw,并且声明版本号:

    int main()
    {
    	glfwInit(); //初始化glfw
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //版本号
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //代表glfw3.3
    }
    

    我这里使用的是3.3版本。
    然后我们用glfwCreateWindow()函数创建一个窗口对象:

    int main()
    {
    	glfwInit(); //初始化glfw
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //版本号
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //代表glfw3.3
    
    	//创建窗口
    	GLFWwindow * window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    	//判断是否创建成功
    	if (window == NULL)
    	{
    		std::cout << "Failed to create GLFW window" << std::endl;
    		glfwTerminate();
    		return -1;
    	}
        glfwMakeContextCurrent(window); //设置当前线程上下文 意思就是在切换下一个状态之前,进行的所有操作都是对 window这个对象进行的
    }
    

    在源码注释里,GLFWwindow是"brief Opaque window object",也就是简易窗口对象的意思。
    glfwCreateWindow()函数显而易见,第一个参数是宽度,第二个参数是高度,第三个是title,也就是窗口名称,后面两个参数现在用不到。当窗口创建失败时,window指针会指向NULL,我们可以利用这个来判断窗口是否创建成功。

    glfwTerminate()是释放资源的函数,当一切结束的时候,我们就要用到这个函数。
    glfwMakeContextCurrent(window)就如注释所说,OPENGL是讲状态的,只要我们不在当前线程设置其他上下文,它就会一直绑定当前设置的window窗口,之后的所有操作,就都是在这个window里进行.


    接下来我们初始化glad:

    int main()
    {
    	glfwInit(); //初始化glfw
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //版本号
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //代表glfw3.3
    
    	//创建窗口
    	GLFWwindow * window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    	//判断是否创建成功
    	if (window == NULL)
    	{
    		std::cout << "Failed to create GLFW window" << std::endl;
    		glfwTerminate();
    		return -1;
    	}
        glfwMakeContextCurrent(window); //设置当前线程上下文 意思就是在切换下一个状态之前,进行的所有操作都是对 window这个对象进行的
    
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    	{
    		std::cout << "Failed to initialize GLAD" << std::endl;
    		return -1;
    	}
    
        //开始渲染之前先告诉opengl渲染窗口的尺寸大小,以及坐标
    	//注意,opengl坐标范围为-1到1 ,与屏幕坐标之间存 映射关系
    	glViewport(0, 0, 800, 600); 
    	//注册该函数,告诉opengl每次window调整大小时都调用该函数
    	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 
    }
    

    glad是用来管理opengl的函数指针的,所以启用opengl任何函数之前需要初始化glad
    glViewport()是设置视口的,具体作用大概就是设置窗口的起始坐标,以及告诉opengl我们要渲染的窗口大小为800x600.
    glfwSetFramebufferSizeCallback()目的是为了当我们拖动窗口,造成窗口大小变化时,能够及时改变渲染的窗口尺寸,里面传入了我们自己设置的函数,可以看到函数内;我们在实时更改视口。

    void framebuffer_size_callback(GLFWwindow * window, int width, int height) //随用户调整窗口大小而变化视口大小
    {
    	glViewport(0, 0, width, height);
    }
    

    该准备的准备完了,可以开始渲染循环了。

    	while (!glfwWindowShouldClose(window)) // 检查glfw是否被要求退出
    	{
    		glfwSwapBuffers(window); //交换前后缓冲
    		glfwPollEvents(); //监视事件
    	}
    

    如果跟着前面打没有打错的话,至此一个完整的黑色背景窗口就能出现了。


    来解释一下glfwSwapBuffers(),因为OPENGL是双缓冲,那么双缓冲的作用是什么呢?假如是单缓冲,由于屏幕上的像素绘制是由左到右,从上到下一个一个绘制的,如果缓冲量过大,那么可能会出现图像闪烁,但是如果是双缓冲,它是由前缓冲全部绘制好,然后再跟后缓冲互换,然后前后工作交替进行,这样子就解决了闪烁问题。所以也能理解这个函数为什么叫这么个名字了吧。

    那么现在我们想给窗口背景改个色,该怎么弄呢,我们需要设置一个颜色缓冲。

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

    glClearColor()是设置清空屏幕所使用的颜色,意思就是使用这个函数后,之后每次清屏,默认颜色都是我们这个函数所设置的颜色。然后glClear()就是清除颜色缓冲,也就是清屏,那么我们为什么每次循环都要glClear()呢,因为有些人可能认为,我都画上去了,为什么要清除屏幕,再绘制一次呢,因为在渲染循环里,你是一个在不断绘制图像的过程,如果不清屏,那么每次画的图像就会叠加,导致跟我们预想的绘制内容会出现很大差别,比如你只是要画一只鸭子,但你如果不使用glClear(),那可能就是成千上万只鸭子绘制在同一个地方,内容不断叠加。

    最后我们再加入一个退出事件的函数:

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

    可以看到一旦检测到我们按下ESC键,那么就会利用glfwSetWindowShouldClose()函数,传入true,使window窗口关闭,可以看到我们循环的条件是while (!glfwWindowShouldClose(window))

    接下来是完整源码:

    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
    #include <iostream>
    void framebuffer_size_callback(GLFWwindow * window, int width, int height);
    void processInput(GLFWwindow * window);
    
    int main()
    {
    	glfwInit(); //初始化glfw
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //版本号
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //代表glfw3.3
    
    	//创建窗口
    	GLFWwindow * window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    	//判断是否创建成功
    	if (window == NULL)
    	{
    		std::cout << "Failed to create GLFW window" << std::endl;
    		glfwTerminate();
    		return -1;
    	}
        glfwMakeContextCurrent(window); //设置当前线程上下文 意思就是在切换下一个状态之前,进行的所有操作都是对 window这个对象进行的
    
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    	{
    		std::cout << "Failed to initialize GLAD" << std::endl;
    		return -1;
    	}
    
        //开始渲染之前先告诉opengl渲染窗口的尺寸大小,以及坐标
    	//注意,opengl坐标范围为-1到1 ,与屏幕坐标之间存 映射关系
    	glViewport(0, 0, 800, 600); 
    	//注册该函数,告诉opengl每次window调整大小时都调用该函数
    	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 
    
        while (!glfwWindowShouldClose(window)) // 检查glfw是否被要求退出
    	{
            processInput(window);
    
    		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    		glClear(GL_COLOR_BUFFER_BIT);
    
    		glfwSwapBuffers(window); //交换前后缓冲
    		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);
    }
    

    这样,一个基本完整的窗口就完成啦。

  • 相关阅读:
    python之scrapy篇(三)
    python之scrapy篇(二)
    python之scrapy篇(一)
    matlib调用python时转py格式为matlib格式
    ubuntu18.40 rtx2080ti安装显卡驱动/cuda/cudnn/tensorflow-gpu
    pytorch导入错误so: undefined symbol: _Z11libshm_initPKc
    yolo_v3训练自己的模型(人脸及deep-sort)(或自己数据集)
    python-图像处理(映射变换)
    python编译pyc工程--导包问题解决
    python(leetcode)-14最长公共前缀
  • 原文地址:https://www.cnblogs.com/xiangqi/p/14608068.html
Copyright © 2011-2022 走看看