OpenGL Chan视频学习-7 Writing a Shader inOpenGL

bilibili视频链接:

【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p=5\&vd_source=44b77bde056381262ee55e448b9b1973

函数网站:

docs.gl

说明:

1.之后就不再整理具体函数了,网站直接翻译会更直观也会有更多注意点。直接通过csdn索引查找反而会慢。

2.代码区域会单独注释功能参数返回值和相关注意事项。

3.课程学习从4-本节,如果有些函数没有注释可以看专栏里面的前面发表的文章,一般会有解释。

4.如果觉得代码注释白色字体不太直观可以直接copy到相应软件看。

5.有两种版本的可供查看:注释全面的和值注释功能的简洁版的,可以在索引里面找到相关代码查看。

6.希望能帮到你。

7.有错误请跟我说明一下,可能整理的时候没有检查好。

一、知识点整理

1.1着色器程序

1.1.1 解释

  • 功能:创建着色器程序
  • 参数:顶点着色器代码、片段着色器代码

1.1.2过程

连接两个着色器到单独着色器程序,并返回唯一标识符,所以可以绑定一个顶点着色器,用顶点缓冲获得一个返回id并在glGenBuffers里面去访问。

1.1.3 程序

static unsigned int CompilesShader(unsigned int type, const std::string& source)

cpp 复制代码
//功能:编译着色器代码
//参数:1.type表示着色器类型,GL_VERTEX_SHADER表示顶点着色器,GL_FRAGMENT_SHADER表示片段着色器
//2.source表示着色器源代码的字符串
//返回值:编译成功的着色器对象ID,失败则返回0
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
    //功能:创建着色器对象
    //参数:1.type表示着色器类型,GL_VERTEX_SHADER表示顶点着色器,GL_FRAGMENT_SHADER表示片段着色器
    //返回值:着色器对象ID
    unsigned int id = glCreateShader(type);
    //功能:设置着色器源代码.
    //通过传递的字符串指针,将源代码复制到着色器对象中
    //注意:这里的src指针必须指向以null结尾的字符串,否则会导致编译错误
    //c_str()函数可以将std::string转换为const char*类型
    //也可const char* src = &source[0];
    const char* src = source.c_str();
    //功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
    //参数:1.id表示着色器对象ID
    //2.1表示着色器源代码的数量
    //3.src指针表示着色器源代码的字符串指针
    //4.nullptr表示长度为0的字符串指针
    glShaderSource(id, 1, &src, nullptr);
    //功能:编译着色器对象的源代码
    //参数:1.id表示着色器对象ID
    glCompileShader(id);

    //设置返回着色器的对象ID
    //这里不能写成unsigned,会报错------
    // "unsigned int *" 类型的实参与 "GLint *" (aka "int *") 类型的形参不兼容
    int result;
    //功能:从着色器对象返回一个参数,表示编译是否成功。
    //参数:1.id表示着色器对象ID
    //2.GL_COMPILE_STATUS表示对象的参数
    //3.result指针表示编译成功/请求的对象参数值
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    //如果编译失败,则输出错误信息
    if (result == GL_FALSE)
    {
        int length;
        //功能:获取编译错误信息的长度
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        //分配内存,用于存储编译错误信息
        //alloca()函数用于分配堆栈内存,避免堆内存碎片化
        //alloca和new的区别:alloca分配的内存不会被自动释放,而new分配的内存会被自动释放
        //alloca和malloc的区别:alloca分配的内存大小必须是编译器确定的,而malloc分配的内存大小可以由用户指定
        char* message = (char*)alloca(length*sizeof(char));
        //功能:获取编译错误信息
        //参数:1.id表示着色器对象ID
        //2.length表示编译错误信息的长度,指定用于存储返回的信息日志的字符缓冲区大小。
        //3.length指针表示实际获取的编译错误信息的长度,返回在infoLog中返回的字符串长度(不包括终止符)。
        //4.message指针表示编译错误信息的字符串指针
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
        std::cout << message << std::endl;
        //删除着色器对象
        glDeleteShader(id);
        return 0;
    }

    //TODO:错误处理ing
    return id;
}

static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)

cpp 复制代码
//功能:创建着色器程序
//将顶点着色器和片段着色器的代码连接(作为字符串)编译为一个程序对象,并返回程序对象
//参数:顶点着色器代码、片段着色器代码
//返回值:着色器程序对象的ID
//定义为静态函数:
// 静态函数可以使函数的可见性降低,仅限于被定义的文件内部使用。
// 这有助于封装代码,使得其他文件无法直接调用这个函数。
// 可以避免命名冲突
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    //创建程序对象
    //返回:程序对象ID。创建的程序对象是一个ID值,用于标识一个OpenGL程序对象
    unsigned int program = glCreateProgram();
    //编译顶点着色器对象
    //参数:1.GL_VERTEX_SHADER表示创建顶点着色器对象
    //2.vertexShader.c_str()表示顶点着色器源代码的字符串指针
    //返回值:编译成功的着色器对象ID
    unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
    //编译片段着色器对象
    //参数:1.GL_FRAGMENT_SHADER表示创建片段着色器对象
    //2.fragmentShader.c_str()表示片段着色器源代码的字符串指针
    //返回值:编译成功的着色器对象ID
    unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);

    //功能:将编译好的着色器对象附加到程序对象中
    //参数:1.program表示程序对象ID
    //2.vs表示顶点着色器对象ID
    //3.fs表示片段着色器对象ID
    glAttachShader(program, vs);
    glAttachShader(program, fs);

    //功能:链接程序对象
    //实际上链接是通过把所有着色器对象中的代码合并到一个程序对象中,然后编译这个程序对象来实现的。
    //参数:1.program表示程序对象ID
    glLinkProgram(program);

    //功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
    //如果验证失败,OpenGL会设置一个错误标志,可以通过glGetProgramiv函数查询验证结果和错误信息。
    //验证过程生成的信息将存储在 program 的信息日志中。
    // 验证信息可能是一个空字符串,或者是一个包含当前程序对象与当前OpenGL状态其余部分如何交互的信息的字符串。
    // 验证操作的状态将作为程序对象状态的一部分被存储。
    // 如果验证成功,此值将被设置为GL_TRUE,否则将被设置为GL_FALSE。
    //可以通过调用glGetProgram并传入参数program和GL_VALIDATE_STATUS来查询。
    glValidateProgram(program);

    //删除着色器对象,因为它们已经被链接到程序对象中
    glDeleteShader(vs);
    glDeleteShader(fs);

    //返回着色器程序
    return program;
}

int main增加代码

cpp 复制代码
 //准备着色器代码
 //core表示使用的是核心配置文件,它移除了旧版本中一些过时的OpenGL函数和功能,使得代码更加清晰和高效。
 //layout(location = 0) : 这是一个布局限定符(layout qualifier)
 // 用于指定输入变量在着色器程序中的位置索引。
 //in vec4 position; : 这是一个输入变量声明。
 // in关键字表示该变量是输入到顶点着色器的,
 // vec4表示数据类型为4维浮点数向量(vec4),
 // position是变量的名称。
 // 这行代码的意思是顶点着色器接收一个4维浮点数向量的输入,变量名是position,用于表示顶点的位置。
 // 实际应用中,通常只使用前三个分量(x, y, z)来表示顶点的位置,第四个分量(w)用于透视除法等操作。
 //void main(): 这是顶点着色器的主函数声明。每个顶点着色器程序都必须有一个名为main的函数。
 //gl_Position = position;将输入的顶点位置position赋值给gl_Position。
 // gl_Position是OpenGL内置的变量,用于存储顶点在裁剪空间中的位置。
 //在这个简单的例子中,顶点着色器不做任何额外的处理,只是将输入的顶点位置直接输出到裁剪空间。
 // 这意味着顶点的位置不会被变换,而是直接基于裁剪空间的坐标系来绘制。
 std::string vertexShader =
     "#version 330 core\n"
     "\n"
     "layout (location = 0) in vec4 position;\n"
     "void main()\n"
     "{\n"
     "   gl_Position = position;\n"
     "}\n";
 //vec4 是 GLSL(OpenGL Shading Language)中的一个内置类型,表示一个包含四个浮点数的向量。
 // 这四个浮点数通常用于表示颜色的 RGBA 值,即红(R)、绿(G)、蓝(B)和透明度(A)。
 //color 是片段着色器中的一个输出变量。用于设置最终输出到屏幕上的颜色。
 std::string fragmentShader =
     "#version 330 core\n"
     "\n"
     "layout (location = 0) out vec4 color;\n"
     "void main()\n"
     "{\n"
     "   color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
     "}\n";

 //创建着色器程序
 unsigned int shader = CreateShader(vertexShader, fragmentShader);
 //使用着色器程序
 glUseProgram(shader);

1.2 glCreateProgram

1.2.1c规范

1.2.2功能

创建程序对象

1.2.3实例

cpp 复制代码
unsigned int program = glCreateProgram();

1.2.4描述

创建一个空的程序对象并返回一个非零值,通过该值可以引用它。程序对象是一个可以附加着色器对象的对象。这提供了一种指定将要链接以创建程序的着色器对象的机制。它还提供了一种检查将用于创建程序的着色器兼容性的方法(例如,检查顶点着色器和片段着色器之间的兼容性)。当不再作为程序对象的一部分所需时,着色器对象可以被分离。

通过成功地使用glAttachShader将着色器对象附加到程序对象上,成功地使用glCompileShader编译着色器对象,并成功地使用glLinkProgram链接程序对象,可以在程序对象中创建一个或多个可执行文件。当调用glUseProgram时,这些可执行文件将被加入到当前状态中。程序对象可以通过调用glDeleteProgram来删除。当程序对象不再属于任何上下文的当前渲染状态时,与程序对象相关的内存将被删除。

像显示列表和纹理对象一样,程序对象的命名空间也可以在一组上下文中共享,只要这些上下文的服务器端共享相同的地址空间。如果命名空间在上下文中共享,任何附加的对象及其相关数据也会被共享。

如果在创建程序对象时发生错误,此函数将返回0。

1.3glCreateShader

1.3.1c规范

1.3.2功能

创建着色器对象

1.3.3描述

创建一个空的着色器对象并返回一个非零值,通过该值可以引用它。着色器对象用于维护定义着色器的源代码字符串。shaderType 指示要创建的着色器类型。支持两种类型的着色器。类型为 GL_VERTEX_SHADER 的着色器是旨在在可编程顶点处理器上运行的着色器。类型为 GL_FRAGMENT_SHADER 的着色器是旨在在可编程片段处理器上运行的着色器。 当创建着色器对象时,其GL_SHADER_TYPE参数设置为GL_VERTEX_SHADER或GL_FRAGMENT_SHADER,具体取决于shaderType的值。

像纹理对象一样,着色器对象的命名空间可以在一组上下文中共享,只要这些上下文的服务器端共享相同的地址空间。如果命名空间在上下文中共享,任何附加的对象及其相关数据也会被共享。

如果在创建着色器对象时发生错误,此函数将返回0。

GL_INVALID_ENUM 生成如果 shaderType 不是可接受的值。

1.4glShaderSource

1.4.1c规范

1.4.2功能

替换着色器对象中的源代码

1.4.3参数

  • shader

指定要替换源代码的着色器对象的句柄。

  • count

指定 stringlength 数组中的元素数量。

  • string

指定一个字符串数组的指针,这些字符串包含要加载到着色器中的源代码。

  • length

指定一个字符串长度的数组。

1.4.4代码

cpp 复制代码
glShaderSource(id, 1, &src, nullptr);

1.4.5描述

glShaderSource 将源代码设置为 shader 中指定的字符串数组。任何之前存储在着色器对象中的源代码将被完全替换。字符串数组的长度由 string 指定。如果 count 为 length,则每个字符串被认为是 null 终止的。如果 NULL 是一个值,它指向一个包含每个相应元素的字符串长度的数组。每个元素在 length 数组中可能包含相应字符串的长度(不包括 null 字符作为字符串长度的一部分)或一个小于 0 的值,表示字符串是 null 终止的。源代码字符串在此时不会被扫描或解析;它们只是被复制到指定的着色器对象中。

OpenGL在glShaderSource被调用时复制着色器源代码字符串,因此应用程序可以在函数返回后立即释放其源代码字符串的副本。

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 生成 shader 如果不是着色器对象。

GL_INVALID_VALUE 生成如果 count 小于 0。

1.5glCompileShader

1.5.1c规范

1.5.2功能

编译着色器对象

1.5.3参数

  • hader

    指定要编译的着色器对象。

1.5.4代码

cpp 复制代码
glCompileShader(id);

1.5.5描述

对于支持着色器编译的实现,glCompileShader 编译由 shader 指定的着色器对象中存储的源代码字符串。 编译状态将作为着色器对象状态的一部分进行存储。如果着色器编译时没有错误并且可以使用,则此值将被设置为GL_TRUE,否则为GL_FALSE。可以通过调用glGetShaderiv并传入参数shader和GL_COMPILE_STATUS来查询。 着色器的编译可能会因多种原因失败,具体原因由OpenGL ES 着色语言规范规定。无论编译是否成功,都可以通过调用glGetShaderInfoLog从着色器对象的信息日志中获取编译信息。

着色器编译器支持是可选的,因此在使用之前必须通过调用 glGet 与参数 GL_SHADER_COMPILER 进行查询。glShaderSourceglCompileShaderglGetShaderPrecisionFormatglReleaseShaderCompiler 在不支持着色器编译器的实现中将分别生成 GL_INVALID_OPERATION。此类实现提供了 glShaderBinary 作为提供预编译着色器二进制数据的替代方案。

GL_INVALID_OPERATION如果不受支持的着色器编译器生成。

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 生成 shader 如果不是着色器对象。

1.6glAttachShader

1.6.1c规范

1.6.2功能

将着色器对象附加到程序对象

1.6.3参数

  • program

指定将着色器对象附加到的程序对象。

  • shader

指定要附加的着色器对象。

1.6.4代码

cpp 复制代码
glAttachShader(program, vs);
glAttachShader(program, fs);

1.6.5描述

为了创建一个可执行文件,必须有一种方法来指定将要链接在一起的一系列事物。程序对象提供了这种机制。要链接在一起的着色器必须首先附加到该程序对象。glAttachShader将由*shader* 指定的着色器对象附加到由*program* 指定的程序对象。shader 这表示*program*将被包含在对

可以对着色器对象执行的所有操作在着色器对象是否附加到程序对象上都是有效的。允许在将源代码加载到着色器对象中或编译着色器对象之前将着色器对象附加到程序对象上。允许附加多个相同类型的着色器对象,因为每个着色器对象可能包含完整着色器的一部分。还允许将着色器对象附加到一个以上的程序对象上。如果在着色器对象附加到程序对象时删除它,它将被标记为删除,直到调用glDetachShader 将其从所有附加的程序对象中分离出来,才会进行删除。

1.7glValidateProgram

1.7.1c规范

1.7.2功能

根据当前 GL 状态验证程序管道对象。

验证着色器程序对象是否可以在当前OpenGL状态中执行。具体来说,它会检查着色器程序中所有着色器的接口是否匹配,包括输入和输出变量的类型、名称和数量。此外,它还会检查着色器程序是否可以在当前的OpenGL版本和上下文中正确执行。

1.7.3参数

  • program

    指定要验证的程序对象的句柄。即要验证的着色器程序对象的ID。这个ID在之前通过glCreateProgram()创建,并通过glAttachShaderglLinkProgram附加和链接了顶点着色器和片段着色器。

1.7.4代码

cpp 复制代码
glValidateProgram(program);

1.7.5描述

这个函数会检查着色器程序的完整性和可执行性。它验证着色器程序的接口是否正确,并且在特定的OpenGL环境中是否可以正确地执行。

如果验证失败,OpenGL会设置一个错误标志,可以通过glGetProgramiv函数查询验证结果和错误信息。

glValidateProgram 检查是否可以在当前OpenGL状态下调用包含在 program 中的可执行文件。验证过程生成的信息将存储在 program 的信息日志中。验证信息可能是一个空字符串,或者是一个包含当前程序对象与当前OpenGL状态其余部分如何交互的信息的字符串。这为OpenGL实现者提供了一种传达当前程序为何效率低下、不优化、无法执行等更多信息的方法。 验证操作的状态将作为程序对象状态的一部分被存储。如果验证成功,此值将被设置为GL_TRUE,否则将被设置为GL_FALSE。可以通过调用glGetProgram并传入参数program和GL_VALIDATE_STATUS来查询。如果验证成功,program在当前状态下保证会被执行。否则,program保证不会执行。 此功能通常仅在应用程序开发期间有用。存储在信息日志中的信息字符串完全取决于实现;因此,应用程序不应期望不同的 OpenGL 实现产生相同的信息字符串。

此函数模拟了当渲染命令发出时,OpenGL 实现必须执行的验证操作,此时可编程着色器是当前状态的一部分。如果发生以下情况,将生成错误GL_INVALID_OPERATION:

当前程序对象中的任意两个活动采样器是不同类型的,但引用相同的纹理图像单元,

程序中活动采样器的数量超过了允许的最大纹理图像单元数量。

当发出渲染命令时,应用程序可能难以捕获这些错误或会导致性能下降。因此,建议应用程序在开发过程中调用glValidateProgram以检测这些问题。

GL_INVALID_VALUE 生成,如果 program 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 生成 program 如果不是程序对象。

1.8glLinkProgram

1.8.1c规范

1.8.2功能

链接程序对象

1.8.3参数

  • program

    指定要链接的程序对象的句柄。

1.8.4代码

cpp 复制代码
glLinkProgram(program);

1.8.5描述

glLinkProgram 将指定的程序对象链接 program。如果 GL_VERTEX_SHADER类型的任何着色器对象附加到 program,它们将被用来创建一个将在可编程顶点处理器上运行的可执行文件。如果 GL_GEOMETRY_SHADER类型的任何着色器对象附加到 program,它们将被用来创建一个将在可编程几何处理器上运行的可执行文件。如果 GL_FRAGMENT_SHADER类型的任何着色器对象附加到 program,它们将被用来创建一个将在可编程片段处理器上运行的可执行文件。

链接操作的状态将作为程序对象状态的一部分被存储。如果程序对象链接成功且无错误,该值将被设置为GL_TRUE,否则为GL_FALSE。可以通过调用glGetProgram并传入参数program和GL_LINK_STATUS来查询。

成功的链接操作后,属于program的所有活动的用户定义的统一变量将被初始化为0,并且每个程序对象的活动统一变量将被分配一个可以通过调用glGetUniformLocation查询的位置。同时,任何未绑定到通用顶点属性索引的活动用户定义的属性变量将在此时绑定到一个。

程序对象的链接可能会因多种原因失败,具体原因请参阅OpenGL着色语言规范。以下列出了一些会导致链接错误的条件。

实现所支持的活动属性变量数量已超出。

均匀变量的存储限制已超出。

实现支持的活动统一变量数量已超出。

顶点、几何或片段着色器的main函数缺失。

在片段着色器中实际使用的可变变量没有以相同的方式声明(或根本未声明)在顶点着色器中,如果存在几何着色器,则在几何着色器中也是如此。

对函数或变量名的引用未解析。

声明一个全局共享变量,有两种不同类型或两种不同的初始值。

一个或多个附加的着色器对象编译未成功。

绑定通用属性矩阵时导致矩阵的一些行超出了允许的最大值GL_MAX_VERTEX_ATTRIBS。

无法找到足够的连续顶点属性插槽来绑定属性矩阵。

程序对象包含用于形成片段着色器的对象,但不包含用于形成顶点着色器的对象。

程序对象包含用于形成几何着色器的对象,但不包含用于形成顶点着色器的对象。

程序对象包含用于形成几何着色器的对象,但未在任何编译的几何着色器对象中指定输入原始类型、输出原始类型或最大输出顶点数。

程序对象包含用于形成几何着色器的对象,并且在多个几何着色器对象中几何输入类型、几何输出类型或最大输出顶点数的指定方式不同。

片段着色器中活动输出的数量大于GL_MAX_DRAW_BUFFERS的值。

该程序有一个活动输出被分配到一个大于或等于GL_MAX_DUAL_SOURCE_DRAW_BUFFERS的值的位置。

该程序有一个活动输出被分配到一个大于或等于一的索引。

多个变化输出变量绑定到相同的编号和索引。

显式绑定分配没有为链接器自动分配一个位置留下足够的空间,对于需要多个连续位置的可变输出数组来说是这样。

glTransformFeedbackVaryingscount指定的值非零,但程序对象没有顶点或几何着色器。

任何在glTransformFeedbackVaryings中指定的变量名在varyings数组中未在顶点着色器(或启用时的几何着色器)中声明为输出。

数组中的任意两个条目varyings由glTransformFeedbackVaryings指定相同的可变变量。

在任何变换反馈可变变量中捕获的组件总数大于常量GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,缓冲模式是GL_SEPARATE_ATTRIBS.。

当程序对象成功链接后,可以通过调用glUseProgram使程序对象成为当前状态的一部分。无论链接操作是否成功,程序对象的信息日志都会被覆盖。信息日志可以通过调用glGetProgramInfoLog来检索。

glLinkProgram 如果链接操作成功,并且指定的程序对象在之前调用 glUseProgram 后已经正在使用中,则还会将生成的可执行文件安装为当前渲染状态的一部分。如果当前正在使用的程序对象链接不成功,其链接状态将被设置为 GL_FALSE ,但其可执行文件和相关状态将保持在当前状态中,直到后续调用 glUseProgram 将其从使用中移除。在移除之前,它不能在成功重新链接之前成为当前状态的一部分。

如果program包含类型为GL_VERTEX_SHADER的着色器对象,并且可以包含类型为GL_GEOMETRY_SHADER的着色器对象,但不包含类型为GL_FRAGMENT_SHADER的着色器对象,顶点着色器可执行文件将被安装在可编程顶点处理器上,如果存在几何着色器可执行文件,将被安装在可编程几何处理器上,但不会在片段处理器上安装任何可执行文件。使用这种程序渲染原语的结果将是未定义的。

程序对象的信息日志会在链接操作时更新并生成程序。链接操作完成后,应用程序可以自由修改附加的着色器对象、编译附加的着色器对象、分离着色器对象、删除着色器对象以及附加额外的着色器对象。这些操作都不会影响程序对象的一部分的信息日志或程序。

如果链接操作不成功,任何关于之前链接操作的信息都会丢失(即,失败的链接不会恢复*program* 的旧状态)。某些信息即使在链接操作不成功后仍然可以从*program* 检索出来。例如*program* glGetActiveAttribglGetActiveUniform

1.9glDeleteShader

1.9.1c规范

1.9.2功能

删除着色器对象

1.9.3参数

  • shader

    指定要删除的着色器对象。

1.9.4代码

cpp 复制代码
glDeleteShader(vs);
glDeleteShader(fs);

1.9.5描述

glDeleteShader 释放指定的着色器对象所关联的内存并使该名称无效 shader。此命令有效地撤销了对 glCreateShader 的调用效果。

如果要删除的着色器对象附加到一个程序对象上,它将被标记为删除,但在它不再附加到任何程序对象、任何渲染上下文之前不会被删除(即,它必须从之前附加的位置 detachment 才会被删除)。shader的值为0将被静默忽略。

要确定一个对象是否已被标记删除,请调用 glGetShader 并传入参数 shader 和 GL_DELETE_STATUS。

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

1.10glGetShaderInfoLog

1.10.1c规范

1.10.2功能

返回着色器对象的信息日志

1.10.3参数

  • shader

指定要查询信息日志的着色器对象。

  • maxLength

指定用于存储返回的信息日志的字符缓冲区的大小。

  • length

返回在*infoLog*中返回的字符串长度(不包括终止符)。

  • infoLog

指定用于返回信息日志的字符数组。

1.10.4代码

cpp 复制代码
char* message = (char*)alloca(length*sizeof(char));
glGetShaderInfoLog(id, length, &length, message);

1.10.5描述

glGetShaderInfoLog返回指定着色器对象的信息日志。当着色器编译时,着色器对象的信息日志会进行修改。返回的字符串将是以空字符结尾的。

glGetShaderInfoLog 返回 infoLog 尽可能多的信息日志,最多 maxLength 个字符。实际返回的字符数(不包括空终止字符)由 length 指定。如果不需要返回字符串的长度,可以在 NULL 中传递 length 的值。通过调用 glGetShader 和传递值 GL_INFO_LOG_LENGTH 可以获得存储返回信息日志所需的缓冲区大小。

着色器对象的信息日志是一个字符串,可能包含诊断消息、警告消息和其他关于上次编译操作的信息。当着色器对象创建时,其信息日志将是一个长度为0的字符串。

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 如果 shader 不是着色器对象,则生成。

GL_INVALID_VALUE 生成如果 maxLength 小于 0。

1.11glGetShaderiv

1.11.1c规范

1.11.2功能

从着色器对象返回一个参数

1.11.3参数

  • shader

指定要查询的着色器对象。

  • pname

指定对象参数。接受的符号名称是 GL_SHADER_TYPE、GL_DELETE_STATUS、GL_COMPILE_STATUS、GL_INFO_LOG_LENGTH、GL_SHADER_SOURCE_LENGTH。

  • params

返回请求的对象参数。

1.11.4代码

cpp 复制代码
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);

1.11.5描述

如果生成错误,则不会更改*params*的内容。

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 如果 shader 不是指向着色器对象,则生成

GL_INVALID_ENUM 生成 pname 如果不是接受的值。

1.12glUseProgram

1.12.1c规范

1.12.2功能

将程序对象安装为当前渲染状态的一部分

1.12.3参数

  • program

指定用于当前渲染状态的程序对象的句柄。

1.12.4代码

cpp 复制代码
glUseProgram(shader);

1.12.5描述

1.13glGetShaderInfoLog

1.13.1c规范

1.13.2功能

返回着色器对象的信息日志

1.13.3参数

  • shader

指定要查询信息日志的着色器对象。

  • maxLength

指定用于存储返回的信息日志的字符缓冲区大小。

  • length

返回在infoLog中返回的字符串长度(不包括终止符)。

  • infoLog

指定用于返回信息日志的字符数组。

1.13.4代码

cpp 复制代码
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
std::cout << message << std::endl;

1.13.5描述

GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。

GL_INVALID_OPERATION 生成 shader 如果不是着色器对象。

GL_INVALID_VALUE 生成如果 maxLength 小于 0。

二、代码

2.1 代码

全注释版

cpp 复制代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include<iostream>

//功能:编译着色器代码
//参数:1.type表示着色器类型,GL_VERTEX_SHADER表示顶点着色器,GL_FRAGMENT_SHADER表示片段着色器
//2.source表示着色器源代码的字符串
//返回值:编译成功的着色器对象ID,失败则返回0
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
    //功能:创建着色器对象
    //参数:1.type表示着色器类型,GL_VERTEX_SHADER表示顶点着色器,GL_FRAGMENT_SHADER表示片段着色器
    //返回值:着色器对象ID
    unsigned int id = glCreateShader(type);
    //功能:设置着色器源代码.
    //通过传递的字符串指针,将源代码复制到着色器对象中
    //注意:这里的src指针必须指向以null结尾的字符串,否则会导致编译错误
    //c_str()函数可以将std::string转换为const char*类型
    //也可const char* src = &source[0];
    const char* src = source.c_str();
    //功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
    //参数:1.id表示着色器对象ID
    //2.1表示着色器源代码的数量
    //3.src指针表示着色器源代码的字符串指针
    //4.nullptr表示长度为0的字符串指针
    glShaderSource(id, 1, &src, nullptr);
    //功能:编译着色器对象的源代码
    //参数:1.id表示着色器对象ID
    glCompileShader(id);

    //设置返回着色器的对象ID
    //这里不能写成unsigned,会报错------
    // "unsigned int *" 类型的实参与 "GLint *" (aka "int *") 类型的形参不兼容
    int result;
    //功能:从着色器对象返回一个参数,表示编译是否成功。
    //参数:1.id表示着色器对象ID
    //2.GL_COMPILE_STATUS表示对象的参数
    //3.result指针表示编译成功/请求的对象参数值
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    //如果编译失败,则输出错误信息
    if (result == GL_FALSE)
    {
        int length;
        //功能:获取编译错误信息的长度
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        //分配内存,用于存储编译错误信息
        //alloca()函数用于分配堆栈内存,避免堆内存碎片化
        //alloca和new的区别:alloca分配的内存不会被自动释放,而new分配的内存会被自动释放
        //alloca和malloc的区别:alloca分配的内存大小必须是编译器确定的,而malloc分配的内存大小可以由用户指定
        char* message = (char*)alloca(length*sizeof(char));
        //功能:获取编译错误信息
        //参数:1.id表示着色器对象ID
        //2.length表示编译错误信息的长度,指定用于存储返回的信息日志的字符缓冲区大小。
        //3.length指针表示实际获取的编译错误信息的长度,返回在infoLog中返回的字符串长度(不包括终止符)。
        //4.message指针表示编译错误信息的字符串指针
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
        std::cout << message << std::endl;
        //删除着色器对象
        glDeleteShader(id);
        return 0;
    }

    //TODO:错误处理ing
    return id;
}


//功能:创建着色器程序
//将顶点着色器和片段着色器的代码连接(作为字符串)编译为一个程序对象,并返回程序对象
//参数:顶点着色器代码、片段着色器代码
//返回值:着色器程序对象的ID
//定义为静态函数:
// 静态函数可以使函数的可见性降低,仅限于被定义的文件内部使用。
// 这有助于封装代码,使得其他文件无法直接调用这个函数。
// 可以避免命名冲突
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    //创建程序对象
    //返回:程序对象ID。创建的程序对象是一个ID值,用于标识一个OpenGL程序对象
    unsigned int program = glCreateProgram();
    //编译顶点着色器对象
    //参数:1.GL_VERTEX_SHADER表示创建顶点着色器对象
    //2.vertexShader.c_str()表示顶点着色器源代码的字符串指针
    //返回值:编译成功的着色器对象ID
    unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
    //编译片段着色器对象
    //参数:1.GL_FRAGMENT_SHADER表示创建片段着色器对象
    //2.fragmentShader.c_str()表示片段着色器源代码的字符串指针
    //返回值:编译成功的着色器对象ID
    unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);

    //功能:将编译好的着色器对象附加到程序对象中
    //参数:1.program表示程序对象ID
    //2.vs表示顶点着色器对象ID
    //3.fs表示片段着色器对象ID
    glAttachShader(program, vs);
    glAttachShader(program, fs);

    //功能:链接程序对象
    //实际上链接是通过把所有着色器对象中的代码合并到一个程序对象中,然后编译这个程序对象来实现的。
    //参数:1.program表示程序对象ID
    glLinkProgram(program);

    //功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
    //如果验证失败,OpenGL会设置一个错误标志,可以通过glGetProgramiv函数查询验证结果和错误信息。
    //验证过程生成的信息将存储在 program 的信息日志中。
    // 验证信息可能是一个空字符串,或者是一个包含当前程序对象与当前OpenGL状态其余部分如何交互的信息的字符串。
    // 验证操作的状态将作为程序对象状态的一部分被存储。
    // 如果验证成功,此值将被设置为GL_TRUE,否则将被设置为GL_FALSE。
    //可以通过调用glGetProgram并传入参数program和GL_VALIDATE_STATUS来查询。
    glValidateProgram(program);

    //删除着色器对象,因为它们已经被链接到程序对象中
    glDeleteShader(vs);
    glDeleteShader(fs);

    //返回着色器程序
    return program;
}


int main(void)
{
    GLFWwindow* window;

    //初始化glfw
    if (!glfwInit())
        return -1;

    //创建一个窗口模式的窗口并设置OpenGL上下文
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)//如果窗口创建失败,则终止程序
    {
        glfwTerminate();//释放glfw资源
        return -1;
    }

    //设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
    glfwMakeContextCurrent(window);

    //初始化GLEW
    if (glewInit() != GLEW_OK)
        std::cout << "Error!" << std::endl;

    //打印OpenGL版本信息
    std::cout << glGetString(GL_VERSION) << std::endl;

    //准备数据
    float position[6] = {
        0.0f, 0.5f,
        -0.5f, -0.5f,
        0.5f, -0.5f
    };

    //定义缓冲区对象
    unsigned int buffer;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &buffer);
    //功能:将缓冲区对象绑定到目标
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    //功能:将数据写入缓冲区
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);

    //功能:配置顶点属性指针
    //参数:1.0表示顶点属性数组的索引
    glEnableVertexAttribArray(0);
    //功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
    //参数:1.0表示顶点属性数组的索引.和下面vertexShader(location=0)的0匹配
    //2.2表示顶点属性数组的大小,这里是2D坐标
    //3.GL_FLOAT表示数据类型
    //4.GL_FALSE表示是否归一化
    //5.sizeof(float)*2表示数据指针的字节大小
    //6.0表示偏移量
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    //准备着色器代码
    //core表示使用的是核心配置文件,它移除了旧版本中一些过时的OpenGL函数和功能,使得代码更加清晰和高效。
    //layout(location = 0) : 这是一个布局限定符(layout qualifier)
    // 用于指定输入变量在着色器程序中的位置索引。
    //in vec4 position; : 这是一个输入变量声明。
    // in关键字表示该变量是输入到顶点着色器的,
    // vec4表示数据类型为4维浮点数向量(vec4),
    // position是变量的名称。
    // 这行代码的意思是顶点着色器接收一个4维浮点数向量的输入,变量名是position,用于表示顶点的位置。
    // 实际应用中,通常只使用前三个分量(x, y, z)来表示顶点的位置,第四个分量(w)用于透视除法等操作。
    //void main(): 这是顶点着色器的主函数声明。每个顶点着色器程序都必须有一个名为main的函数。
    //gl_Position = position;将输入的顶点位置position赋值给gl_Position。
    // gl_Position是OpenGL内置的变量,用于存储顶点在裁剪空间中的位置。
    //在这个简单的例子中,顶点着色器不做任何额外的处理,只是将输入的顶点位置直接输出到裁剪空间。
    // 这意味着顶点的位置不会被变换,而是直接基于裁剪空间的坐标系来绘制。
    std::string vertexShader =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec4 position;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = position;\n"
        "}\n";
    //vec4 是 GLSL(OpenGL Shading Language)中的一个内置类型,表示一个包含四个浮点数的向量。
    // 这四个浮点数通常用于表示颜色的 RGBA 值,即红(R)、绿(G)、蓝(B)和透明度(A)。
    //color 是片段着色器中的一个输出变量。用于设置最终输出到屏幕上的颜色。
    std::string fragmentShader =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "void main()\n"
        "{\n"
        "   color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
        "}\n";

    //创建着色器程序
    unsigned int shader = CreateShader(vertexShader, fragmentShader);
    //使用着色器程序
    glUseProgram(shader);

    //渲染循环,直到窗口被关闭
    while (!glfwWindowShouldClose(window))
    {
        //清除颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);

        //功能:绘制三角形
        glDrawArrays(GL_TRIANGLES, 0, 3);

        //刷新缓冲区并交换窗口
        glfwSwapBuffers(window);

        //处理窗口事件,如键盘输入、鼠标移动等
        glfwPollEvents();
    }

    //删除着色器程序
    glDeleteProgram(shader);

    //释放 GLFW 库占用的所有资源。它在程序结束时调用,以确保不会出现资源泄漏。
    //调用 glfwTerminate() 后,GLFW 将释放所有与 OpenGL 上下文相关的资源,包括窗口、OpenGL 对象等。
    glfwTerminate();
    return 0;
}

简洁版,纯功能注释

cpp 复制代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include<iostream>

//功能:编译着色器代码
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
    //功能:创建着色器对象
    unsigned int id = glCreateShader(type);
    //功能:设置着色器源代码.
    const char* src = source.c_str();
    //功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
    glShaderSource(id, 1, &src, nullptr);
    //功能:编译着色器对象的源代码
    glCompileShader(id);

    //设置返回着色器的对象ID
    int result;
    //功能:从着色器对象返回一个参数,表示编译是否成功。
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    //如果编译失败,则输出错误信息
    if (result == GL_FALSE)
    {
        int length;
        //功能:获取编译错误信息的长度
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        //分配内存,用于存储编译错误信息
        char* message = (char*)alloca(length*sizeof(char));
        //功能:获取编译错误信息
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
        std::cout << message << std::endl;
        //删除着色器对象
        glDeleteShader(id);
        return 0;
    }

    //TODO:错误处理ing
    return id;
}


//功能:创建着色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    //创建程序对象
    unsigned int program = glCreateProgram();
    //编译顶点着色器对象
    unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
    //编译片段着色器对象
    unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);

    //功能:将编译好的着色器对象附加到程序对象中
    glAttachShader(program, vs);
    glAttachShader(program, fs);

    //功能:链接程序对象
    glLinkProgram(program);

    //功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
    glValidateProgram(program);

    //删除着色器对象,因为它们已经被链接到程序对象中
    glDeleteShader(vs);
    glDeleteShader(fs);

    //返回着色器程序
    return program;
}


int main(void)
{
    GLFWwindow* window;

    //初始化glfw
    if (!glfwInit())
        return -1;

    //创建一个窗口模式的窗口并设置OpenGL上下文
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)//如果窗口创建失败,则终止程序
    {
        glfwTerminate();//释放glfw资源
        return -1;
    }

    //设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
    glfwMakeContextCurrent(window);

    //初始化GLEW
    if (glewInit() != GLEW_OK)
        std::cout << "Error!" << std::endl;

    //打印OpenGL版本信息
    std::cout << glGetString(GL_VERSION) << std::endl;

    //准备数据
    float position[6] = {
        0.0f, 0.5f,
        -0.5f, -0.5f,
        0.5f, -0.5f
    };

    //定义缓冲区对象
    unsigned int buffer;
    //功能:生成缓冲区对象,并将数据写入缓冲区
    glGenBuffers(1, &buffer);
    //功能:将缓冲区对象绑定到目标
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    //功能:将数据写入缓冲区
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);

    //功能:配置顶点属性指针
    glEnableVertexAttribArray(0);
    //功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    //准备着色器代码
    std::string vertexShader =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec4 position;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = position;\n"
        "}\n";

    std::string fragmentShader =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "void main()\n"
        "{\n"
        "   color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
        "}\n";

    //创建着色器程序
    unsigned int shader = CreateShader(vertexShader, fragmentShader);
    //使用着色器程序
    glUseProgram(shader);

    //渲染循环,直到窗口被关闭
    while (!glfwWindowShouldClose(window))
    {
        //清除颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);

        //功能:绘制三角形
        glDrawArrays(GL_TRIANGLES, 0, 3);

        //刷新缓冲区并交换窗口
        glfwSwapBuffers(window);

        //处理窗口事件,如键盘输入、鼠标移动等
        glfwPollEvents();
    }

    //删除着色器程序
    //glDeleteProgram(shader);

    //释放 GLFW 库占用的所有资源。
    glfwTerminate();
    return 0;
}

2.2运行结果

相关推荐
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习
im_AMBER6 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J6 天前
从“Hello World“ 开始 C++
c语言·c++·学习