s4.GLSL学习之图元类型

图元类型

   OpenGL的主要作用就是讲图形渲染到帧缓冲当中。为了实现这一要求,需要将复杂的物体分解成图元的形式(包括点、线、以及三角形),当它们的分布密度足够高时,就可以表达为2D以及3D物体的形态。OpenGL可以支持很多种不同的图元类型。不过它们最后都可以归结为三种类型的一种,即点、线或者三角形。线和三角形图元类型可以再组合为条带、循环体(线),或扇面(三角形)。这些图元类型通过OpenGL的枚举量来进行表达,并且作为渲染函数的输入参数。下图为图元类型与OpenGL枚举量之间的对应关系。
s4.GLSL学习之图元类型_第1张图片

示例演示

  我们利用三角形图元渲染出一个彩色的立方体,而是是利用索引绘制方式。也从篇开始,着色编程添加打印错误日志。代码主要代码如下:

void MyQGLWidget::initShader()
{
    glGenVertexArrays(NumVAOs, VAOs);
    glBindVertexArray(VAOs[Triangles]);
    // create a cube
    //    v6----- v5
    //   /|      /|
    //  v1------v0|
    //  | |     | |
    //  | |v7---|-|v4
    //  |/      |/
    //  v2------v3
    GLfloat vertices[] = {
        // position                 // color
        0.5,  0.5,  0.5,     1.0,  1.0,  1.0,  // v0 White
        -0.5,  0.5,  0.5,    1.0,  0.0,  1.0,  // v1 Magenta
        -0.5, -0.5,  0.5,    1.0,  0.0,  0.0,  // v2 Red
        0.5, -0.5,  0.5,     1.0,  1.0,  0.0,  // v3 Yellow
        0.5, -0.5, -0.5,     0.0,  1.0,  0.0,  // v4 Green
        0.5,  0.5, -0.5,     0.0,  1.0,  1.0,  // v5 Cyan
        -0.5,  0.5, -0.5,    0.0,  0.0,  1.0,  // v6 Blue
        -0.5, -0.5, -0.5,    0.0,  0.0,  0.0   // v7 Black
    };

    //vertex index
    GLushort indices[36] = {
        0, 1, 2,   0, 2, 3,    // front

        0, 3, 4,   0, 4, 5,    // right

        0, 5, 6,   0, 6, 1,    // up

        1, 6, 7,   1, 7, 2,    // right

        7, 4, 3,   7, 3, 2,    // down

        4, 7, 6,   4, 6, 5     // back

     };


    glGenBuffers(NumBuffers, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(vColor);
    glVertexAttribPointer(vColor, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));

    GLuint  indexBufferID;
    glGenBuffers(1, &indexBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    const char*  vertexShaderCode =
        "#version 430 \n"
        ""
        "layout(location = 0) in vec3 vPosition;"
        "layout(location = 1) in vec3 color;"
        "out vec3 myColor;"
        ""
        "void main()"
        "{"
        "   mat4 rotatey = mat4(0.5, 0.0, 0.866, 0.0,   0.0,1.0,0.0,0.0, -0.866,0.0,0.5,0.0,  0.0,0.0, 0.0,1.0);"
        "   mat4 rotatex = mat4(1.0, 0.0, 0.0, 0.0,   0.0,0.707,-0.707,0.0, 0.0,0.707,0.707,0.0,  0.0,0.0, 0.0,1.0);"
        "   gl_Position =  rotatex *rotatey* vec4(vPosition, 1.0);"
        "   myColor = color;"
        "}";

    const char* fragmentShaderCode =
        "#version 430 \r \n"
        ""
        "in vec3 myColor;"
        "out vec4 fColor;"
        ""
        "void main()"
        "{"
        "   fColor = vec4(myColor, 1.0f);"
        "}";
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    const char* adapter[1];
    adapter[0] = vertexShaderCode;
    glShaderSource(vertexShaderID, 1, adapter, 0);

    adapter[0] = fragmentShaderCode;
    glShaderSource(fragmentShaderID, 1, adapter, 0);

    glCompileShader(vertexShaderID);

    GLint compiled;
    glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &compiled );
    if (!compiled)
    { 
        std::cout<<"vertexShaderID";
        GLsizei len;
        glGetShaderiv( vertexShaderID, GL_INFO_LOG_LENGTH, &len );
        GLchar* log = new GLchar[len+1];
        glGetShaderInfoLog( vertexShaderID, len, &len, log );
        std::cerr << "Shader compilation failed: " << log << std::endl;
        delete [] log;
    }

    glCompileShader(fragmentShaderID);

    glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &compiled );
    if (!compiled) 
    { 
        std::cout<<"fragmentShaderID";
        GLsizei len;
        glGetShaderiv( fragmentShaderID, GL_INFO_LOG_LENGTH, &len );
        GLchar* log = new GLchar[len+1];
        glGetShaderInfoLog( fragmentShaderID, len, &len, log );
        std::cerr << "Shader compilation failed: " << log << std::endl;
        delete [] log;
    }

    GLuint programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);

    glLinkProgram(programID);
    GLint linked;
    glGetProgramiv( programID, GL_LINK_STATUS, &linked );
    if (!linked) 
        std::cout<<"Error";
    glUseProgram(programID);
}

运行结果:

s4.GLSL学习之图元类型_第2张图片

代码分析

1、绘制命令

 大部分OpenGL绘制命令都是以Draw这个单词开始的。绘制命令大致可以分为两个部分:索引形式和非索引形式的绘制。索引形式的绘制需要用到绑定GL_ELEMENT_ARRAY_BUFFER的缓存对象中存储的索引数组,它可以用来间接地对已经启用的顶点数组进行索引。而我们之前的渲染都是用非索引的绘制。什么时候应用索引绘制?索引绘制能够节省存储空间,共享顶点属性数据,但存在的限制时共享的数据的属性时相同的。当我们需要为同一个顶点指定不同的属性,例如颜色和法向量时,索引绘制无法满足需求,这时候需要使用顶点数组为同一个顶点指定不同属性。最基本的索引形式的绘制命令是glDrawElements。

void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
使用count个元素来定义一个系列几何图元,而元素的索引值保存在GL_ELEMENT_ARRAY_BUFFER的缓存中。
model定义了图元类型,它必须是图元类型标识符中一个。

2、查询着色器编译和链接结果

  • 用glCompileShader编译着色器的源代码,结果可以调用glGetShaderiv来查询。如果编译失败,那么可以通过glGetShaderInfoLog调取编译日志来判断错误的原因。
  • 用glLinkProgram来处理所有与program关联的着色器对象来生产一个完整的着色器程序。链接操作的结果查询可以调用glGetProgramiv。如果链接过程失败了,可以通过glGetProgramInfoLog来获取程序链接的日志信息并判断错误原因。

代码下载
OpenGL学习系列导航

你可能感兴趣的:(Study-OpenGL)