Analysis of OpenGL Shader Program--Introduction to Shaders

The version of OpenGL has developed from version 1.0 in 1994 to version 4.6 now. OpenGL has undergone qualitative changes. Let us now put aside the previous fixed pipeline and talk about the rendering pipeline, that is, the use of shaders.
The codes we use here are all from "OpenGL Programming Guide (Eighth Edition)", because various resources on the Internet are already very rich (source code http://www.opengl-redbook.com/ , teaching material https://yq .aliyun.com/articles/212785?spm=5176.100239.blogcont212917.14.EZWxCF ), our later articles have mainly been code analysis, so that everyone can understand the use of shaders more easily.
Let's look at a simple shader program. In this program, we use the GLFW (OpenGL for windows) library for the first time. This library is used to process window commands and can replace the glut library, which is more portable. In addition, we use the GL3W library, which simplifies the process of obtaining function addresses and includes some other OpenGL programming methods that can be used cross-platform. Without GL3W, we might still have to do quite a bit of work to be able to run the program.

//////////////////////////////////////////////////////////////////////////////
//
//  Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include "vgl.h"
#include "LoadShaders.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];
const GLuint  NumVertices = 6;
//----------------------------------------------------------------------------
//
// init
//
void
init( void )
{
    glGenVertexArrays( NumVAOs, VAOs );//初始化顶点数组名字栈,栈数组为VAOs,数组大小为NumVAOs
    glBindVertexArray( VAOs[Triangles] );//创建并且绑定了一个顶点数组对象,OpenGL内部会将它作为当前对象,即所有后继的操作都会作用于这个被绑定的对象
    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, {  0.85f, -0.90f }, { -0.90f,  0.85f },  // Triangle 1
        {  0.90f, -0.85f }, {  0.90f,  0.90f }, { -0.85f,  0.90f }   // Triangle 2
    };
    glGenBuffers( NumBuffers, Buffers );//初始化缓存名字栈,栈数组为Buffers,数组大小为NumBuffers
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );//创建并且绑定了一个缓存对象,OpenGL内部会将它作为当前对象,即所有后继的操作都会作用于这个被绑定的对象;GL_ARRAY_BUFFER为缓存类型,Buffers[ArrayBuffer]设置的是要绑定的缓存对象名称
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);//在OpenGL服务端内存中分配size个存储单元(通常为字节),用于存储数据或者索引
    ShaderInfo  shaders[] =
    {//每一个OpenGL程序进行绘制的时候,都需要指定至少两个着色器:顶点着色器和片元着色器
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };
    GLuint program = LoadShaders( shaders );//指定着色器
    glUseProgram( program );//使用shader
    /*最后的两个函数指定了顶点着色器的变量与我们存储在缓存对象中数据的关系。这也就是我们所说的着色管线装配的过程,即将应用程序与着色器之间,以及不同着色阶段之间的数据通道连接起来*/
    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );//将着色器中声明的in变量用glVertexAttribPointer()将它关联到一个顶点属性数组vPosition,每个顶点分量为2,数据类型为浮点型。
    glEnableVertexAttribArray( vPosition );//启用顶点属性数组
}
//----------------------------------------------------------------------------
//
// display
//
void
display( void )
{
    static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
    glClearBufferfv(GL_COLOR, 0, black);//清除颜色帧缓存的数据,设置背景色为黑色
    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );//实现顶点数据向OpenGL管线的传输,构建图元的类型为GL_TRIANGLES,绘制点从0到5
}
//----------------------------------------------------------------------------
//
// main
//
#ifdef _WIN32
int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
    glfwInit();//负责初始化GLFW库
    GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);//设置了程序所使用的窗口类型以及期望的窗口尺寸,创建了一个与窗口关联的OpenGL设备环境
    glfwMakeContextCurrent(window);//设置它为当前环境
    gl3wInit();//初始化另一个辅助库GL3W
    init();
    while (!glfwWindowShouldClose(window))//判断是否需要关闭窗口
    {
        display();
        glfwSwapBuffers(window);//重绘它的内容,并且展现给最终用户
        glfwPollEvents();//检查操作系统返回的任何信息
    }
    glfwDestroyWindow(window);//清理窗口
    glfwTerminate();//关闭GLFW库
}

Let's take a look at what's in the shader file again. Shaders use the OpenGL Shading Language (GLSL), which is similar to the C language.
Vertex shader "media/shaders/triangles/triangles.vert"

#version 400 core//指定了我们所用的OpenGL着色语言的版本,即OpenGL4.0对应的glsl版本

layout( location = 0 ) in vec4 vPosition;//传入GLSL的四维浮点数向量数据vPosition

void
main()
{
    gl_Position = vPosition;//将输入的顶点位置复制到顶点着色器的指定输出位置gl_Position中
}

Fragment shader "media/shaders/triangles/triangles.frag"

#version 450 core

out vec4 fColor;//着色器输出数据

void main()
{
    fColor = vec4(0.5, 0.4, 0.8, 1.0);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325525829&siteId=291194637