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)

//功能:编译着色器代码
//参数: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表示片段着色器//返回值:着色器对象IDunsigned 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表示着色器对象IDglCompileShader(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:错误处理ingreturn id;
}

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

//功能:创建着色器程序
//将顶点着色器和片段着色器的代码连接(作为字符串)编译为一个程序对象,并返回程序对象
//参数:顶点着色器代码、片段着色器代码
//返回值:着色器程序对象的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()表示顶点着色器源代码的字符串指针//返回值:编译成功的着色器对象IDunsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);//编译片段着色器对象//参数:1.GL_FRAGMENT_SHADER表示创建片段着色器对象//2.fragmentShader.c_str()表示片段着色器源代码的字符串指针//返回值:编译成功的着色器对象IDunsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);//功能:将编译好的着色器对象附加到程序对象中//参数:1.program表示程序对象ID//2.vs表示顶点着色器对象ID//3.fs表示片段着色器对象IDglAttachShader(program, vs);glAttachShader(program, fs);//功能:链接程序对象//实际上链接是通过把所有着色器对象中的代码合并到一个程序对象中,然后编译这个程序对象来实现的。//参数:1.program表示程序对象IDglLinkProgram(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增加代码

 //准备着色器代码//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实例

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

指定 string 和 length 数组中的元素数量。

  • string

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

  • length

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

 1.4.4代码

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代码

glCompileShader(id);

1.5.5描述

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

着色器编译器支持是可选的,因此在使用之前必须通过调用 glGet 与参数 GL_SHADER_COMPILER 进行查询。glShaderSource、glCompileShader、glGetShaderPrecisionFormat 和 glReleaseShaderCompiler 在不支持着色器编译器的实现中将分别生成 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代码

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代码

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代码

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检索出来。例如programglGetActiveAttrib和glGetActiveUniform。

 1.9glDeleteShader

1.9.1c规范

1.9.2功能

删除着色器对象

1.9.3参数

  • shader

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

 1.9.4代码

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代码

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代码

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代码

glUseProgram(shader);

1.12.5描述

 1.13glGetShaderInfoLog

1.13.1c规范

1.13.2功能

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

1.13.3参数

  • shader

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

  • maxLength

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

  • length

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

  • infoLog

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

 1.13.4代码

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 代码

全注释版

#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表示片段着色器//返回值:着色器对象IDunsigned 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表示着色器对象IDglCompileShader(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:错误处理ingreturn 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()表示顶点着色器源代码的字符串指针//返回值:编译成功的着色器对象IDunsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);//编译片段着色器对象//参数:1.GL_FRAGMENT_SHADER表示创建片段着色器对象//2.fragmentShader.c_str()表示片段着色器源代码的字符串指针//返回值:编译成功的着色器对象IDunsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);//功能:将编译好的着色器对象附加到程序对象中//参数:1.program表示程序对象ID//2.vs表示顶点着色器对象ID//3.fs表示片段着色器对象IDglAttachShader(program, vs);glAttachShader(program, fs);//功能:链接程序对象//实际上链接是通过把所有着色器对象中的代码合并到一个程序对象中,然后编译这个程序对象来实现的。//参数:1.program表示程序对象IDglLinkProgram(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;//初始化glfwif (!glfwInit())return -1;//创建一个窗口模式的窗口并设置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口创建失败,则终止程序{glfwTerminate();//释放glfw资源return -1;}//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行glfwMakeContextCurrent(window);//初始化GLEWif (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;
}

简洁版,纯功能注释

#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);//设置返回着色器的对象IDint 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:错误处理ingreturn 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;//初始化glfwif (!glfwInit())return -1;//创建一个窗口模式的窗口并设置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口创建失败,则终止程序{glfwTerminate();//释放glfw资源return -1;}//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行glfwMakeContextCurrent(window);//初始化GLEWif (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运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 3.0中复杂状态如何管理

在现代前端应用中&#xff0c;状态管理扮演着至关重要的角色。一个良好的状态管理方案能够&#xff1a; 1. 保持应用数据的一致性和可预测性&#xff1b; 2. 简化组件间的通信和数据共享&#xff1b; 3. 提高代码的可维护性和可测试性&#xff1b; 4. 优化应用性能&#xf…

AGI大模型(33):LangChain之Memory

大多数的 LLM 应用程序都会有一个会话接口,允许我们和 LLM 进行多轮的对话,并有一定的上下文记忆能力。但实际上,模型本身是不会记忆任何上下文的,只能依靠用户本身的输入去产生输出。而实现这个记忆功能,就需要额外的模块去保存我们和模型对话的上下文信息,然后在下一次…

leetcode513. 找树左下角的值:层序遍历中的深度与顺序控制之道

一、题目深度解析与核心诉求 在二叉树的众多问题中&#xff0c;寻找最深层最左节点的值是一个兼具趣味性与代表性的问题。题目要求我们在给定的二叉树中&#xff0c;找到深度最大的那一层中最左边的节点值。如果存在多个最深层&#xff0c;只需返回最左边节点的值即可。 这个…

制作一款打飞机游戏54:子弹编辑UI

今天&#xff0c;我们将继续工作在我们的子弹模式系统上&#xff0c;创建一些简单的子弹&#xff0c;并为其设计用户界面&#xff08;UI&#xff09;。 自动保存功能的重要性 首先&#xff0c;我想提一下自动保存功能。这个功能在编辑器中非常重要&#xff0c;因为我们经常犯…

线程封装与互斥

目录 线程互斥 进程线程间的互斥相关背景概念 互斥量mutex 互斥量的接口 初始化互斥量有两种方法&#xff1a; 销毁互斥量 互斥量加锁和解锁 改进售票系统 互斥量实现原理探究 互斥量的封装 线程互斥 进程线程间的互斥相关背景概念 临界资源&#xff1a;多线程执行流共…

【系统设计】2WTPS生产级数据处理系统设计Review

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读与评论&#x1f604;。 目录 反正能用的系统问题分析方案一&#xff1a;简单多…

历年北京理工大学保研上机真题

2025北京理工大学保研上机真题 2024北京理工大学保研上机真题 2023北京理工大学保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/problem?classification1 判断身份证校验位是否正确 题目描述 给定一个身份证号码&#xff0c;判断其最后一位校验位是否正确。 如果…

uni-app学习笔记十--vu3综合练习

巩固提升前面学习的知识点,主要涉及下面这方面的运用&#xff1a; 1.v-for运用; 2.v-model双向绑定&#xff1b; 3.confirm确认事件&#xff1b; 4.click点击事件&#xff1b; 5.控制按钮的可点击和不可点击&#xff1b; 6.集合删除和追加元素&#xff0c;获取集合元素的…

AI时代新词-AI芯片(AI - Specific Chip)

一、什么是AI芯片&#xff1f; AI芯片&#xff08;AI - Specific Chip&#xff09;是指专为人工智能&#xff08;AI&#xff09;计算任务设计的芯片。与传统的通用处理器&#xff08;如CPU&#xff09;相比&#xff0c;AI芯片针对深度学习、机器学习等AI应用进行了优化&#x…

华为云Astro前端页面数据模型选型及绑定IoTDA物联网数据实施指南

目录 1. 选择合适的数据模型类型及推荐理由 自定义模型: 对象模型: 服务模型: 事件模型: 推荐方案: 2. 数据模型之间的逻辑关系说明 服务模型获取数据: 对象模型承接数据: 前端组件绑定显示: 数据保存与反馈(可选): (可选)事件模型实时更新: 小结 …

因重新安装python新版本,pycharm提示找不到python.exe(No Python at“c:\python.exe“)问题解决方法

1、安装新版本python后提示错误如下&#xff1a; 2、打开设置 3、添加Interpreter 4、配置程序的安装路径 5、问题完美解决。

一文带你彻底理清C 语言核心知识 与 面试高频考点:从栈溢出到指针 全面解析 附带笔者手写2.4k行代码加注释

引言&#xff1a;C 语言的魅力与挑战 从操作系统内核到嵌入式系统&#xff0c;从高性能计算到网络编程&#xff0c;C 语言高效、灵活和贴近硬件的特性&#xff0c;始终占据着不可替代的地位。然而&#xff0c;C 语言的强大也伴随着较高的学习曲线&#xff0c;尤其是指针、内存管…

GitHub 趋势日报 (2025年05月22日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1microsoft/WSLLinux的Windows子系统⭐ 2524⭐ 26627C2HeyPuter/puter&#x1…

AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡

AI智能混剪核心技术解析&#xff08;一&#xff09;&#xff1a;字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡 引言&#xff1a;文字到画面的桥梁工程 在AI视频混剪系统中&#xff0c;字幕与标题生成是连接语言表达与视觉呈现的核心枢纽。优雅草卓伊凡团队将该功能拆…

如何通过PHPMyadmin对MYSQL数据库进行管理?

管理MySQL数据库时&#xff0c;使用PHPMyAdmin是一种常见且方便的方式。PHPMyAdmin是一个基于Web的数据库管理工具&#xff0c;提供了许多功能&#xff0c;如数据库创建、表管理、数据查询、用户权限设置等。本文将介绍如何通过PHPMyAdmin对MySQL数据库进行管理&#xff0c;包括…

如何解决大模型返回的JSON数据前后加上```的情况

环境说明 springboot 应用使用dashscope-sdk-java对接阿里百练 deepseek v3模型 问题表现 已经指定了输出json格式&#xff0c;但指令不明确&#xff0c;输出JSON格式的写法如下 注&#xff1a;提示词一开始是能正常功能的&#xff0c;但过了几天就出现了异常&#xff0c;原…

uniapp实现H5、APP、微信小程序播放.m3u8监控视频

目录 1.APP播放.m3u8监控视频 2.H5播放.m3u8监控视频 3.微信小程序播放.m3u8监控视频 最近在写一个uniapp实现h5、app、微信小程序兼容三端的播放监控视频功能&#xff0c;我原本以为一套代码多处运行&#xff0c;但事实并非如此&#xff0c;h5可以运行&#xff0c;微信小程…

萤石云实际视频实时接入(生产环境)

萤石云视频接入 本示例可用于实际接入萤石云开放平台视频&#xff0c;同时支持音频输入和输出。 实际优化内容 1.动态获取token 2.切换各公司和车间时&#xff0c;自动重新初始化播放器 let EZUIKit null; // 第三方库引用 let EZUIKitPlayers []; // 播放器实例数组 le…

【Dify平台】使用Dify API 实现网页内嵌式AI助手

使用 Dify API 实现网页内嵌式 AI 助手 一. 引言二. Dify API 概述三. 实现网页内嵌式 AI 助手的技术架构四. 前端实现五. 后端实现六. 功能扩展与优化七. 测试与部署一. 引言 随着 AI 技术的不断发展,越来越多的企业希望将智能助手集成到自己的网页中,实现用户自动接待、问…

mysql8配置文件my.ini讲解,原汁原味直接拷贝再讲解

文章目录 一、原英文版本&#xff0c;不带注释二、由原版逐字翻译成的中文版&#xff08;行行对应&#xff09;三、最常用的配置 一、原英文版本&#xff0c;不带注释 # Other default tuning values # MySQL Server Instance Configuration File # -------------------------…