zoukankan      html  css  js  c++  java
  • OpenGL 笔记<1> 固定管线实例 + 双缓存测试实例

    欲以此分类来记录opengl的学习历程,此为第一篇,所以先来一个固定管线的例子,以及对双缓存的测试。

    一、配置环境

    写之前,先进行配置,然后再讲内容。

    注:第一部分涉及的代码均忽略。

    【环境配置传送门】

    二、所需知识

    1. opengl程序结构

        main函数结构大体上由如下几个步骤:

    1) glutInit(&argc, argv);
        读取命令行参数,初始化glut
    
    2) glutInitDisplayMode(unsigned int mode);
        设置显示模式(或窗口类型) (本节涉及参数如下)
        GLUT_RGB    GLUT_RGBA    GLUT_DOUBLE
    
    3) glutInitWindowSize(int, int);
        设置窗口规格
    
    4) glutInitWindowPosition(int, int);
        设置窗口初始位置
    
    5) glutCreateWindow(char*);
    
    6) if(glewInit()) ....
        判断glew是否初始化成功
    
    7) init()
        初始化数据 ,函数体自己写
    
    8) glutDisplayFunc(函数指针);
        系统自带的显示回调宏,在glut每次更新窗口内容的时候自动调用。
    
    9) glutMainLoop();
        无限循环,一直处理窗口消息,如:判断是否需要进行重绘,然后自动调用glutDisplayFunc()中注册的函数(即参数)。

    2. 初始化数据

    glGen*  系列函数,用于OpenGL 分配不同类型的对象名称。

    glBind*  系列函数,将已分配的对象名称进行绑定,设定为当前活动对象。

    以VBO(Vertex Buffer Object  顶点缓冲对象)为例,来理解上面两个函数的理念,其中VBO是一个GLuint对象,即无符号整型。

    我们程序员想要操控缓冲区,怎么办呢,缓冲区位于系统硬件中,对编程人员是不可见的。所以,opengl建立了一个映射机制,以一个GLuint的数据对象来代表某一缓存区。

    其中,缓存区为映射的一端,VBO为另一端,我们首先要创建所需的VBO对象,然后通过glGenBuffers(VBO数量,VBO取址);来激活VBO对象作为某一映射的映射端。

    因为程序员创建的GLuint对象,系统默认为一个普通的对象,只有通过glGenBuffers(),才能使系统将其认定为缓存区映射的对象。

    而glBindBuffer(分配缓冲区类型,已激活的VBO对象);用于建立此映射,将VBO绑定到一个缓冲区,将当前VBO代表的缓冲区作为当前活动对象。尔后的所有关于缓冲区的操作均对当前VBO对象代表的缓冲区进行操作。

    glBufferData(缓冲区类型,大小,数据,数据的读写方式);

    刚刚说到VBO映射到一块缓冲区,但是里面并没有信息数据,所以要将数据传到缓冲区中,就是上述函数的作用。

    我们可以通过glBufferData将一组顶点位置坐标信息传入到VBO1代表的缓冲区中,然后将顶点的颜色信息传入到VBO2代表的缓冲区中,当我们渲染的时候,需要颜色信息对颜色信息进行处理加工的时候,我们就通过GLBindBuffer,将VBO2绑定为当前活动对象,反之,同理。

    上述,以VBO为例讲述了相关的一些概念,其他类似的函数同理。

    3. 渲染

    glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer)

    参数解析表
    参数名 数值 解释
    index GLuint     如:0 顶点着色器中输入变量的location值,就是属性的索引
    size GLint       如:2 每个顶点的属性数量,如:x、y
    type GLenum  如:GL_FLOAT 顶点属性变量的数值类型
    normalized GLboolean  如:GL_FALSE 设定了顶点数据存储前是否进行归一化
    stride GLsizei     如:0 相邻属性变量之间间隔的比特长度
    pointer GLvoid*    如:BUFFER_OFFSET(0) 数据读取时,开始位置的偏移量

    通过该函数告诉管线怎样解析buffer中的数据

     

    glDrawArrays(绘制方式,第一个顶点的索引,顶点数量);

    void glFlush(void);

    强制所有进行中的OpenGL命令立即完成并传输到OpenGL服务端处理。这样就可以保证它们在一定时间内全部完成。

    但是,该函数只是强制所有运行中的命令送入服务端而已,它会立即返回,它并不会等待所有的命令完成,而等待确实我们需要做的。。。

    glFinish();

    它会一直等待所有当前的OpenGL命令立即执行,等待他们全部完成。但是可想而知,它会拖累程序整体性能。

     

    三、代码

      1 //配置代码
      2 #if _MSC_VER>=1900
      3 #include "stdio.h"
      4 _ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);
      5 #ifdef __cplusplus
      6 extern "C"
      7 #endif
      8 FILE* __cdecl __iob_func(unsigned i) {
      9     return __acrt_iob_func(i);
     10 }
     11 #endif /* _MSC_VER>=1900 */
     12 
     14 #include <iostream>
     15 using namespace std;
     16 
     17 //我们需要包含 "val.h"  和  "LoadShaders.h"
     18 //如果你按照之前配置环境那样做了,需要:
     19 //#include "vgl.h"
     21 
     22 //我这里是自己将两个文件放到VS库目录里面了,总之,只要正确引用两个文件即可
     23 #include <vgl.h>
     26 
     27 //顶点缓冲对象初始下标、缓冲对象数量、顶点属性数量、顶点数量
     28 enum {Arraybuffers, Numbuffers, AttriNum = 3, VerNum}; 
     29 
     30 GLuint buffers[Numbuffers]; //顶点缓冲对象数组  the array of VBOs
     31 
     32 void init();
     33 void Display();
     34 
     35 int main(int argc, char** argv)
     36 {
     37     //命令行初始化glut
     38     glutInit(&argc, argv);      
     39 
     40     //初始化显示模式
     41     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);  
     42 
     43     //初始化windows
     44     glutInitWindowSize(900, 600);
     45     glutInitWindowPosition(20, 20);
     46     glutCreateWindow("my work 1");
     47 
     48     //检查glew是否就绪
     49     if (glewInit())
     50     {
     51         cout << "glew didn't go work!" << glewGetErrorString(glewInit()) << endl;
     52         exit(EXIT_FAILURE);
     53     }
     54 
     55     //初始化数据
     56     init();
     57 
     58     //渲染
     59     glutDisplayFunc(Display);
     60 
     61     glutMainLoop();
     62 
     63     return 0;
     64 }
     65 
     66 void init()
     67 {
     68     //顶点数据
     69     GLfloat vertices[VerNum][AttriNum]
     70     {
     71         { 0.8,0.8,0 },
     72         { -0.1,0,0},
     73         {0.8,-0.8,0},
     74         {-0.8,0,0},
     75     };
     76 
     77     //创建缓冲器
     78     glGenBuffers(Numbuffers, buffers);
     79     //绑定缓冲器
     80     glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]);
     81     //向缓冲区传递数据
     82     glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
     83 
     84     //设置清除颜色
     85     glClearColor(0, 0, 0, 0);
     86 }
     87 
     88 void Display()
     89 {
     90     //清空颜色缓存
     91     glClear(GL_COLOR_BUFFER_BIT);
     92 
     93     //开启顶点属性数组
     94     glEnableVertexAttribArray(0);
     95 
     96     glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]);
     97 
     98     glVertexAttribPointer(0, AttriNum, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
     99 
    100     //绘制 两个三角形
    101     glColor4f(1, 0, 0, 0.3);    //设置颜色
    102     glDrawArrays(GL_TRIANGLES, 0, VerNum);
    103     glColor4f(0, 0, 1, 0.8);
    104     glDrawArrays(GL_TRIANGLES, 1, VerNum); 
    105     //1. 将绘制好的两个三角形放到屏幕前面
    106     glutSwapBuffers();
    107 
    108     //在后面的帧缓存中继续绘制 一个四边形 边框
    109     glColor4f(1, 0.1, 0.8, 0.0);
    110     glDrawArrays(GL_LINE_LOOP, 0, VerNum);
    111 
    112     //2. 将后面的四边形边框帧缓存放到屏幕前面
    113     glutSwapBuffers();
    114 
    115     //此时,理论上讲,后台的帧缓存应该为原来绘制的两个三角形
    116     glColor4f(1, 0.1, 0.8, 0.0);
    117     //我们在其基础上,加上边框
    118     glDrawArrays(GL_LINE_LOOP, 0, VerNum);
    119 
    120     //3. 显示的是两个三角形+边框
    121     glutSwapBuffers();
    122 
    123     //禁用顶点属性数组           这个要最后禁用
    124     glDisableVertexAttribArray(0);
    125 
    126     glFlush();
    127 }

    四、效果

    标号为1.处得到的效果:(将107-122注释掉)

    标号2.处得到的效果(将114-122注释)

    标号3.处的效果,即将后面帧缓存中的效果添加到原来帧缓存的图形中得到的效果

     

     

    通过这一节的测试,我们真正的看到了双缓存的工作过程,以及内部数据信息。

     

    感谢您的阅读,生活愉快~

  • 相关阅读:
    IP寻址方式三
    IP通信基础4
    IP通信基础3
    IP通信基础2
    IP通信基础 1
    IP通信基础
    IP通信原理第二周
    设备选型
    常用virsh命令记录
    [转]enable spice html5 console access in openstack kilo(centos)
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/9221504.html
Copyright © 2011-2022 走看看