学习OpenGL tutorials笔记(一)(入门)

本文适合新手参阅和讨论,高手欢迎提出批评,指出错误,不喜勿看~
建议配合红宝书(新版本)配套学习
OpenGL tutorials 网站链接http://www.opengl-tutorial.org/
具体环境搭建的问题之前博客有部分解决方案,有问题的可以提出来交流。

在基于网站教程的基础上,我对前三次课程(不包括环境搭建)进行了一次总结,在这里结合彩色立方体这一课,总结说明一下整个程序。

第四课
彩色立方体

//**第一部分,编译环境的配置**

// Include standard headers
#include <stdio.h>
#include <stdlib.h>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <glfw3.h>

GLFWwindow* window;    //创建窗口句柄

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;

//将加载着色器的代码放在此文件中
#include <common/shader.hpp>



int main( void )
{

    //**第二部分,配置环境,设置窗口**

    //2.1初始化glfw库
    if( !glfwInit() )
    {
        fprintf( stderr, "Failed to initialize GLFW\n" );
        getchar();//暂停屏幕输出和程序运行,提供作者的浏览时间
        return -1;//通常返回-1表示程序出错
    }

    //2.2设置窗口和显示参数    

    //hint是线索的意思,这里意为选项Hint也有很多种,这里我们只设置了3种,分别是:
    glfwWindowHint(GLFW_SAMPLES, 4); //采用四倍抗锯齿
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); //选择OpenGL主版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); //选择OpenGL副版本
     //所以合起来就是OpenGL版本为2.1

    //2.3创建窗口,创建对应的context(上下文)
        //创建窗口,并设置大小和名称
        window = glfwCreateWindow( 1024, 768, "Tutorial 04 - Colored Cube", NULL, NULL);
        //保证窗口创建成功
    if( window == NULL ){
        fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
        getchar();
        glfwTerminate();   //若失败则需要终止glfw库
        return -1;
    } 
    //在使用OpenGL API之前,必须设置好当前的OpenGL上下文
    glfwMakeContextCurrent(window);

    //2.4初始化glew库
    if (glewInit() != GLEW_OK) {
        fprintf(stderr, "Failed to initialize GLEW\n");
        getchar();
        glfwTerminate();
        return -1;
    }

    //2.5设置相关参数

    //  确保我们可以捕捉下面按下的转义键,函数讲解见下文
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

    // 设置背景颜色为深蓝色(四个参数为red,green,blue,透明度)
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

    // 允许深度测试(消隐)
    glEnable(GL_DEPTH_TEST);
    //如果像素比之前的像素更接近相机,则接受当前像素 
    glDepthFunc(GL_LESS); 


      //**第三部分,传入数据,开始绘制**


     //3.1调用已经写好的顶点着色器和片元着色器
    //从着色器创建和编译GLSL程序
    GLuint programID = LoadShaders( "TransformVertexShader.vertexshader", "ColorFragmentShader.fragmentshader" );

    //3.2在C++中创建MVP矩阵
    //创建uniform MVP矩阵的句柄
    GLuint MatrixID = glGetUniformLocation(programID, "MVP");

    // 为缓冲对象创建顶点位置句柄
    GLuint vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
    // 为缓冲对象创建顶点颜色句柄
    GLuint vertexColorID = glGetAttribLocation(programID, "vertexColor");

    // P矩阵:创建投影矩阵:45?Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
    glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
    //V矩阵:创建视角矩阵
    glm::mat4 View       = glm::lookAt(
                                glm::vec3(4,3,-3), // Camera is at (4,3,-3), in World Space
                                glm::vec3(0,0,0), // and looks at the origin
                                glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
                           );
    // M矩阵:创建模型矩阵 : an identity matrix (model will be at the origin)
    glm::mat4 Model      = glm::mat4(1.0f);
    // 计算得到MVP矩阵 : multiplication of our 3 matrices
    glm::mat4 MVP        = Projection * View * Model; // Remember, matrix multiplication is the other way around

     //3.3 在C++中设置顶点数据的参数
    // 以下是我们的顶点数据,三个浮点数代表着3D的点坐标,每三个点构成一个三角形
    // 一个立方体有六个面,每个面可以由两个三角形组成,所以一共是6*2=12个三角形,12*3=36个点(有重复的点)
        static const GLfloat g_vertex_buffer_data[] = { 
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f, 1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
         1.0f,-1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f,-1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f,-1.0f, 1.0f
    };

    // 为每个点设置颜色,参数是随机生成的
    static const GLfloat g_color_buffer_data[] = { 
        0.583f,  0.771f,  0.014f,
        0.609f,  0.115f,  0.436f,
        0.327f,  0.483f,  0.844f,
        0.822f,  0.569f,  0.201f,
        0.435f,  0.602f,  0.223f,
        0.310f,  0.747f,  0.185f,
        0.597f,  0.770f,  0.761f,
        0.559f,  0.436f,  0.730f,
        0.359f,  0.583f,  0.152f,
        0.483f,  0.596f,  0.789f,
        0.559f,  0.861f,  0.639f,
        0.195f,  0.548f,  0.859f,
        0.014f,  0.184f,  0.576f,
        0.771f,  0.328f,  0.970f,
        0.406f,  0.615f,  0.116f,
        0.676f,  0.977f,  0.133f,
        0.971f,  0.572f,  0.833f,
        0.140f,  0.616f,  0.489f,
        0.997f,  0.513f,  0.064f,
        0.945f,  0.719f,  0.592f,
        0.543f,  0.021f,  0.978f,
        0.279f,  0.317f,  0.505f,
        0.167f,  0.620f,  0.077f,
        0.347f,  0.857f,  0.137f,
        0.055f,  0.953f,  0.042f,
        0.714f,  0.505f,  0.345f,
        0.783f,  0.290f,  0.734f,
        0.722f,  0.645f,  0.174f,
        0.302f,  0.455f,  0.848f,
        0.225f,  0.587f,  0.040f,
        0.517f,  0.713f,  0.338f,
        0.053f,  0.959f,  0.120f,
        0.393f,  0.621f,  0.362f,
        0.673f,  0.211f,  0.457f,
        0.820f,  0.883f,  0.371f,
        0.982f,  0.099f,  0.879f
    };

     //3.4创建VBO,将顶点数组的元素数据传入GLSL(OpenGL shading language),即着色器。

    //创建一个储存其顶点信息的VBO对象
    GLuint vertexbuffer;

    //返回n个当前未使用的缓存名称(此处是1),并保存到后面的数组中
    glGenBuffers(1, &vertexbuffer);

    //绑定缓存对象到OpenGL环境,绑定缓存时需要指明缓存对象的类型,这里是GL_ARRAY_BUFFER(顶点数据)
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);

    //创建并初始化VBO对象的数据区,参数为(类型,指针大小,数据的指针,enum(用处))
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

    //创建一个用于存储点的颜色信息的VBO对象
    GLuint colorbuffer;
    glGenBuffers(1, &colorbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);

   //3.5在着色器中利用MVP矩阵变换顶点,并实现绘制过程

   /*下面是一个无限执行的循环,负责一直处理窗口和操作系统的用户输入等操作,只有用户想退出的时候,才会终止循环*/
    do{

        // 清屏
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // 使用着色器
        glUseProgram(programID);
        // 将我们的转换发送到当前绑定的着色器,
        // in the "MVP" uniform
        glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

        // 第一个属性缓冲区:顶点
        glEnableVertexAttribArray(vertexPosition_modelspaceID);//启动顶点属性数组
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);//指定当前激活的对象

        glVertexAttribPointer(                    //函数详解见下
            vertexPosition_modelspaceID,          // index为想要设定的属性为顶点位置属性                  3,                   //每个顶点的元素数目                         GL_FLOAT,                    // 元素类型                            GL_FALSE,                    //是否需要归一化处理,限制在[-1,1]之间
                   0,                            //数据紧密封装在一起                           (void*)0                     // array buffer offset
        );

        // 第二个属性缓冲:颜色
        glEnableVertexAttribArray(vertexColorID);
        glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
        glVertexAttribPointer(
            vertexColorID,               // The attribute we want to configure
            3,                           // size
            GL_FLOAT,                    // type
            GL_FALSE,                    // normalized?
            0,                           // stride
            (void*)0                     // array buffer offset
        );

        // 画三角形
        glDrawArrays(GL_TRIANGLES, 0, 12*3); // 12*3 indices starting at 0 -> 12 triangles

        glDisableVertexAttribArray(vertexPosition_modelspaceID);
        glDisableVertexAttribArray(vertexColorID);

        //将画面展现给用户
        glfwSwapBuffers(window);
        //检查操作系统返回的任何信息
        glfwPollEvents();

    } 


 //**第四部分,绘制结束,清理缓存**


    //判断ESC键有没有按下或者有没有关闭窗口的行为
    while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
           glfwWindowShouldClose(window) == 0 );

    // 清理VBO和着色器    
    glDeleteBuffers(1, &vertexbuffer);
    glDeleteBuffers(1, &colorbuffer);
    glDeleteProgram(programID);

    // 关闭OpenGL,终止GLFW库
    glfwTerminate();

    return 0;
}

知识补充

1.glfw库、glew库和glm库

GLEW是一个基于OpenGL图形接口的跨平台的C++扩展库。GLEW能自动识别当前平台所支持的全部OpenGL高级扩展涵数。只要包含glew.h头文件,就能使用gl,glu,glext,wgl,glx的全部函数。GLEW支持目前流行的各种操作系统。
官方解释如下:GLEW is an open-source cross-platform extension loading library with thread-safe support for multiple rendering contexts and automatic code generation capability. GLEW provides easy-to-use and efficient methods for checking OpenGL extensions and core functionality.
GLFW是一个跨平台的OpenGL应用框架,支持窗口创建,接受输入和事件等功能。
官方解释如下:GLFW is an Open Source, multi-platform library for creating windows with OpenGL contexts and receiving input and events. It is easy to integrate into existing applications and does not lay claim to the main loop.
GLM是一个OpenGL的数学库
官方解释如下:GLM is a C++ mathematics library for graphics software based on the OpenGL Shading Language (GLSL) specification.

整理一下也就是说:
GLEW库:
是包含了glGenbuffer()、glBindBuffer此类OpenGL函数的库,是OpenGL基本的函数库
glfw库:
是一个应用框架,包含了一些创建窗口的函数,所以这个库是最先初始化的。
GLM库:
一个数学库,用于矩阵的计算等。

2.关于glfwMakeContextCurrent(window)函数
作为新手,我觉得context(也就是上下文)是一件不太容易理解的东西,
查阅资料:说context是一个非常抽象的概念,可以姑且把他的理解成一个对象,这个对象包含了所有的OpenGL的对象。

关于此还要记住一点,
OpenGL是一个状态机,所用的模式是客户端服务器模式,这个地方我还不太懂,继续学吧!
3.函数glfwSetInputMode (GLFWwindow * window,int mode, ubt value)
查阅glfw INPUT Reference可得
这里写图片描述
也就是说,此函数设置了输入模式的选择项,只能为以下三个之一 GLFW_CURSOR, GLFW_STICKY_KEYS GLFW_STICKY_MOUSE_BUTTONS
Sticky keys :粘连键 比如启动粘连键之后,按alt+f4就可以一次只按一个键
这里写图片描述
没按的同学,我们继续,也就是根据上述英文可得,这个函数可以允许粘连键存在,并且,当一个键盘按下后,如果这个键is called,glfwGetKey函数会返回GLFW_PRESS,仅仅只适用于你只想知道这个键是否被按下的情况,但不适用于以下情况:你想知道什么时候按下的或者以什么顺序按下。

4.glVertexAttribPointer函数
可以先看看函数名字,gl代表glew库里的函数,vertex是顶点,Attrib是attribution的缩写,意思是属性,pointer 指针,这个函数也就是:指定渲染时索引值为 index(index是着色器中的属性位置) 的顶点属性数组数据格式和位置。(转自百度百科)
void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);
参数:

index
指定要修改的顶点属性的索引值
size
指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
type
指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
normalized
指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。

stride
指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
pointer
指定第一个组件在数组的第一个顶点属性中的偏移量。该数组与GL_ARRAY_BUFFER绑定,储存于缓冲区中。初始值为0;

猜你喜欢

转载自blog.csdn.net/alexhu2010q/article/details/80927681