OpenGL中使用Shader

263 阅读3分钟

Shader介绍

  • Shader(着色器程序), 一种运行在GPU端的,类C语言,用于处理顶点数据以及决定像素片元最终着色。

  • Shader对三角形数据的处理,分为顶点处理与片元处理,分别称为VertexShader与FragmentShader

GLSL语言

Graphic Library Shader Language的简写,着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

GLSL语言特点:

  • GLSL程序本质是一种将输入转化为输出的程序
  • GLSL程序是一种非常独立的程序,彼此之间无法通信,只能通过输入输出相互承接。

Shader的编译与链接

Shader的编译相关代码

使用的API

API介绍
glCreateShader创建某一种shader程序(vs或者fs),并返回句柄
glShaderSource给Shader程序注入源代码
glCompileShader对Shader程序进行编译
void prepareShader()
{
    // 1, vertexShader与fragmentShader的代码
    const char* vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "void main()\n"
        "{\n"
        "  gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
        "}\0";

    const char* fragmentShaderSource =
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "  FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

    // 2, 创建Shader
    GLuint vertex, fragment;
    vertex = glCreateShader(GL_VERTEX_SHADER);
    fragment = glCreateShader(GL_FRAGMENT_SHADER);


    // 3, 为Shader程序输入shader代码
    glShaderSource(vertex, 1, &vertexShaderSource, nullptr);
    glShaderSource(fragment, 1, &fragmentShaderSource, nullptr);

    int success = 0;
    char infoLog[1024];
    // 4, Shader代码编译

    glCompileShader(vertex);      // 编译vertexShader

    glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);   // 获取上一步vertexShader的编译是否成功

    if (!success)  {  // success为0说明编译出错,为1没有错误
        glGetShaderInfoLog(vertex, 1024, nullptr, infoLog);  // 获取vertexShader编译的错误信息
        std::cout << "Error: VERTEX SHADER COMPILE ERROR :" << infoLog << std::endl;
    }

    glCompileShader(fragment);    // 编译fragmentShader
    glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);   // 获取上一步fragmentShader的编译是否成功

    if (!success) {  // success为0说明编译出错,为1没有错误
        glGetShaderInfoLog(fragment, 1024, nullptr, infoLog);  // 获取fragmentShader编译的错误信息
        std::cout << "Error: FRAGMENT SHADER COMPILE ERROR :" << infoLog << std::endl;
    }

}

Shader链接相关代码

使用的API

API介绍
glCreateProgram创建最终可执行程序对象,返回句柄
glAttachShader将编译好的Shader程序附着到program上
glLinkProgram将program里面附着的程序进行链接,使之成为一个完整的shader可执行程序
void prepareShader()
{
    // 1, vertexShader与fragmentShader的代码
    const char* vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "void main()\n"
        "{\n"
        "  gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
        "}\0";

    const char* fragmentShaderSource =
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "  FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

    // 2, 创建Shader
    GLuint vertex, fragment;
    vertex = glCreateShader(GL_VERTEX_SHADER);
    fragment = glCreateShader(GL_FRAGMENT_SHADER);


    // 3, 为Shader程序输入shader代码
    glShaderSource(vertex, 1, &vertexShaderSource, nullptr);
    glShaderSource(fragment, 1, &fragmentShaderSource, nullptr);

    int success = 0;
    char infoLog[1024];
    // 4, Shader代码编译

    glCompileShader(vertex);      // 编译vertexShader

    glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);   // 获取上一步vertexShader的编译是否成功

    if (!success)  {  // success为0说明编译出错,为1没有错误
        glGetShaderInfoLog(vertex, 1024, nullptr, infoLog);  // 获取vertexShader编译的错误信息
        std::cout << "Error: VERTEX SHADER COMPILE ERROR :" << infoLog << std::endl;
    }

    glCompileShader(fragment);    // 编译fragmentShader
    glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);   // 获取上一步fragmentShader的编译是否成功

    if (!success) {  // success为0说明编译出错,为1没有错误
        glGetShaderInfoLog(fragment, 1024, nullptr, infoLog);  // 获取fragmentShader编译的错误信息
        std::cout << "Error: FRAGMENT SHADER COMPILE ERROR :" << infoLog << std::endl;
    }


    // 5, 创建一个program
    GLuint program = 0;
    program = glCreateProgram();


    // 6, 将vs与fs编译好的结果放到program里

    glAttachShader(program, vertex);
    glAttachShader(program, fragment);


    // 7, 执行program的链接操作,形成最终可执行shader程序
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &success);   // 检测链接的状态

    if (!success) {  // success为0说明编译出错,为1没有错误
        glGetProgramInfoLog(vertex, 1024, nullptr, infoLog);  // 获取program链接的错误信息
        std::cout << "Error: PROGRAM LINK ERROR :" << infoLog << std::endl;
    }

    // 清理
    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

进行绘制

使用的API

API介绍
glUseProgram设置绘制的时候所使用的Shader程序
glBindVertexArray设置绘制的时候所使用的VAO几何信息
glDrawArrays向GPU发起绘制渲染指令
void render()
{

    GL_CALL(glClear(GL_COLOR_BUFFER_BIT));  // 画布清理
    // 绑定program
    glUseProgram(program);

    // 绑定vao
    glBindVertexArray(vao);

    // 发出绘制指令
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

image.png