简单着色器编写(中上)

这篇具有很好参考价值的文章主要介绍了简单着色器编写(中上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这篇我们来介绍函数部分,也就是下面这些:

static unsigned int CompileShader(unsigned int type,const std::string& source)
{
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(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"<<
            (type==GL_VERTEX_SHADER?"vertex":"fragment")
            << "shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }

    return id;
}

下面来逐步解释每一行代码:

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

  • static:这个关键字表示函数是静态的,意味着它属于类或命名空间,而不是特定的对象实例。它可以通过类名或命名空间名直接调用,而无需创建对象。

  • unsigned int type:这是一个参数,表示要编译的着色器的类型。可以是 GL_VERTEX_SHADER(顶点着色器)或 GL_FRAGMENT_SHADER(片段着色器)。

  • const std::string& source:这是另一个参数,表示要编译的着色器源代码。它是一个引用,指向一个字符串对象,其中包含了要编译的着色器源代码。

unsigned int id = glCreateShader(type);

这行代码的作用是使用 glCreateShader 函数创建一个着色器对象,并将返回的标识符(ID)存储在名为 id 的无符号整数变量中。

  • unsigned int id:这是一个无符号整数变量,用于存储着色器对象的标识符(ID)。在OpenGL中,标识符通常是无符号整数类型。

  • glCreateShader(type):这是一个OpenGL函数调用,用于创建一个指定类型的着色器对象。type 参数表示着色器的类型,可以是 GL_VERTEX_SHADER(顶点着色器)或 GL_FRAGMENT_SHADER(片段着色器)。函数返回一个表示新创建着色器对象的唯一标识符。

const char* src = source.c_str();

这行代码的作用是将从 source 字符串对象获取的C风格字符串(null-terminated string)赋值给名为 srcconst char* 指针。

  • const char* src:这是一个指向字符的指针,它被声明为指向常量字符(const char),表示它指向的字符数据是只读的。

  • source.c_str():这是一个 std::string 对象的成员函数,用于返回一个指向以null结尾的C风格字符串的指针。通过调用这个函数,你可以获取 source 字符串对象的C风格表示。

这个操作通常用于将C++的 std::string 类型转换为C风格字符串,因为很多OpenGL函数需要接受C风格字符串作为参数。在这种情况下,从 source 字符串对象中获取一个C风格字符串指针,以便在后续的OpenGL函数中使用。请注意,因为 src 是一个指向常量字符的指针,所以不能通过它来修改原始字符串数据。

glShaderSource(id, 1, &src, nullptr);

  • id:这是一个无符号整数(GLuint),代表着色器对象的标识符。你可以通过 glCreateShader 函数创建着色器对象,并将其标识符赋给 id

  • 1:这是一个整数,表示要加载的源代码字符串的数量。在这里,我们加载一个源代码字符串。

  • &src:这是一个指向源代码字符串的指针。由于在之前的代码中,我们将 source 字符串对象的C风格表示(即以null结尾的字符序列)赋给了 src 指针,所以可以通过 &src 获取该指针的地址。

  • nullptr:这是一个指向字符数组的长度的指针。在这里,我们没有指定字符串长度,因为OpenGL会根据null终止符自动计算字符串长度。

总的来说,glShaderSource 函数的作用是将源代码加载到着色器对象中,使着色器对象拥有这些源代码,以便后续的编译操作。

这个函数比较复杂,我来解释一下,

函数签名:

void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
  • shader:表示要设置源代码的着色器对象的标识符。这是通过 glCreateShader 创建的。
  • count:表示源代码字符串的数量。通常情况下,你会加载一个源代码字符串,所以值为 1。
  • string:是一个指向源代码字符串的指针的指针(const GLchar**)。这里的 string 是一个数组,每个元素指向一个源代码字符串的起始位置。你可以使用单个源代码字符串,也可以将多个源代码字符串合并成一个数组。
  • length:是一个指向整数数组的指针(const GLint*),用于指定每个源代码字符串的长度。通常情况下,你可以将其设置为 nullptr,OpenGL会自动计算字符串长度。

glShaderSource 函数将源代码加载到指定的着色器对象中,以便后续使用 glCompileShader 函数对其进行编译。

glCompileShader(id);

调用 glCompileShader 函数会编译着色器对象中的源代码,将其转换为可以在图形渲染管线中执行的机器代码。如果源代码中存在语法错误、逻辑问题或其他编译错误,编译过程将失败,并且你可以通过查询编译状态和错误日志来调试和查找问题。

一旦着色器成功编译,你就可以将其与其他着色器链接到一起,或将其用于渲染管线的其他阶段,从而实现所需的图形渲染效果。

 glGetShaderiv(id, GL_COMPILE_STATUS, &result);

glGetShaderiv 是一个OpenGL函数,用于查询着色器对象的特定信息。在这段代码中,它用于查询着色器的编译状态,即是否成功编译了着色器源代码。

函数签名:

void glGetShaderiv(GLuint shader, GLenum pname, GLint* params);

参数解释:

  • shader:表示要查询的着色器对象的标识符。
  • pname:表示要查询的参数名称,这里是 GL_COMPILE_STATUS,用于查询编译状态。
  • params:是一个指向整数的指针,用于存储查询结果。

在这段代码中,传递的 pnameGL_COMPILE_STATUS,表示想查询编译状态。params 是一个指向 result 的指针,用于存储查询结果。如果编译成功,result 将被设置为 GL_TRUE,如果编译失败,result 将被设置为 GL_FALSE

通过查询编译状态,你可以判断着色器是否成功编译,从而在发生编译错误时进行适当的处理和调试。

glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);

在这段代码中,glGetShaderiv 函数用于查询着色器信息日志的长度。这个信息日志包括着色器编译过程中的警告、错误和其他相关信息。通过查询信息日志的长度,你可以了解信息日志所需的缓冲区大小,然后可以为信息日志分配足够的空间来存储这些信息。

具体地说,以下是这段代码中各个参数的含义:

  • id:着色器对象的标识符,即你之前通过 glCreateShader 创建的着色器对象。
  • GL_INFO_LOG_LENGTH:表示你要查询的参数名称,这里是用于查询信息日志长度的参数。
  • &length:一个指向整数的指针,用于存储查询结果,即信息日志的长度。

通过这个查询,你可以获得信息日志的长度,然后根据这个长度分配足够大的内存,以便在之后的调用中使用 glGetShaderInfoLog 函数获取实际的信息日志内容。这些信息日志对于调试和定位着色器编译过程中的问题非常有用。

 char* message = (char*)alloca(length * sizeof(char));

  • allocaalloca 是一个函数,用于在栈上动态分配内存空间。与标准的动态内存分配函数(如 malloc)不同,alloca 分配的内存在函数退出时会自动释放,因为它是在栈上分配的。这意味着分配的内存空间不能在函数外部访问,也不能在函数内部的其他函数中访问。在这里,它用于为信息日志分配临时的内存空间。

  • char* message:这声明了一个指向字符的指针,名为 message,用于存储信息日志内容。

  • (char*)alloca(length * sizeof(char)):这部分是对 alloca 函数的调用。alloca 分配的内存大小由 length * sizeof(char) 决定,其中 length 是通过查询 GL_INFO_LOG_LENGTH 得到的信息日志长度。sizeof(char) 是一个字符的字节数(通常为1),因此这里的乘法实际上只是为了分配与信息日志长度相等的内存空间。类型转换 (char*) 是将 alloca 返回的指针转换为指向字符的指针,以便后续存储字符串数据。

总之,这段代码的目的是在栈上分配一块内存空间,以便在之后的调用中存储着色器信息日志的内容。需要注意的是,由于 alloca 分配的内存在函数退出时会自动释放,所以你在退出函数后不能再使用指向这块内存的指针。

glGetShaderInfoLog(id, length, &length, message);

  • id:着色器对象的标识符,即你之前通过 glCreateShader 创建的着色器对象。
  • length:这是之前查询到的信息日志的长度,通过调用 glGetShaderiv 传递 GL_INFO_LOG_LENGTH 参数获得的。
  • &length:这是一个指向整数的指针,传递给 glGetShaderInfoLog 函数,用于接收实际写入信息日志内容的字符数。
  • message:这是一个之前通过 alloca 分配的字符数组,用于存储信息日志的内容。

通过调用 glGetShaderInfoLog 函数,OpenGL将实际的信息日志内容写入到 message 数组中,并将实际写入的字符数更新到 length 变量中。你可以随后使用这些内容来查看着色器编译过程中的警告、错误和其他消息,以帮助你进行调试和排错。

return id;

在函数 CompileShader 的最后,有一行代码 return id;,它的作用是将编译后的着色器对象标识符返回给调用者。这样做的目的是让调用者可以在后续的代码中继续使用这个着色器对象,例如将它附加到程序对象中,以便进行渲染。

在这个特定的代码中,CompileShader 函数负责编译着色器并返回一个表示着色器对象的标识符。调用者(可能是 CreateShader 函数)将得到这个标识符,并在适当的地方使用它。通过返回标识符,你可以在多个函数之间传递着色器对象,并在不同的地方使用它,以便实现更复杂的OpenGL操作。

 文章来源地址https://www.toymoban.com/news/detail-668330.html

 

到了这里,关于简单着色器编写(中上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenGL和OpenGL ES显示YUV图片的着色器差别(一)

    这里解释的只是用于显示YUV图片的代码,没有增加任何效果: OpenGL 的片段着色器片段: OpenGL 的顶点着色器片段: OpenGL ES 的片段着色器片段: OpenGL ES的顶点着色器片段: 差别: 添加了  #version 320 es  指令,指定使用 OpenGL ES 3.2 版本。 使用  in  和  out  替代了原来

    2024年02月02日
    浏览(39)
  • OpenGL ES 3.0 着色器程序二进制化

    之前有位读者提问:C++ 如何将 OpenGL ES 的着色器程序二进制(保存),然后在其他地方加载使用?现在写篇文章介绍下。 将着色器程序二进制化(Shader Program Binary)有哪些好处? 快速加载和解析 :使用二进制形式的着色器程序可以更快地加载和解析,因为不需要进行编译和

    2024年02月07日
    浏览(44)
  • OpenGL ES 2.0 for Android教程(二):定义顶点和着色器

    文章传送门 OpenGL ES 2.0 for Android教程(一) OpenGL ES 2.0 for Android教程(三) OpenGL ES 2.0 for Android教程(四) OpenGL ES 2.0 for Android教程(五) OpenGL ES 2.0 for Android教程(六) OpenGL ES 2.0 for Android教程(七) OpenGL ES 2.0 for Android教程(八) OpenGL ES 2.0 for Android教程(九) 本章介绍我们

    2023年04月14日
    浏览(43)
  • OpenGL ES 2.0 for Android教程(三):编译着色器并绘制到屏幕

    文章传送门 OpenGL ES 2.0 for Android教程(一) OpenGL ES 2.0 for Android教程(二) OpenGL ES 2.0 for Android教程(四) OpenGL ES 2.0 for Android教程(五) OpenGL ES 2.0 for Android教程(六) OpenGL ES 2.0 for Android教程(七) OpenGL ES 2.0 for Android教程(八) OpenGL ES 2.0 for Android教程(九) 本章将继续我

    2023年04月26日
    浏览(60)
  • 【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~ 虽然OpenGL的三维制图功能非常强大,但是它主要为计算机设计的,对于嵌入式设备和移动端设备来说显得比较臃肿,所以业界又设计了专供嵌入式设备的OpenGL ES 它相当于OpenGL的精简版,因为嵌入式设备追求性价比,所以能不做的

    2024年02月04日
    浏览(51)
  • vscode shadertoy插件,非常方便的glsl着色器编写工具

    很著名的shadertoy网站,集合了非常多大神利用数学写出美妙的shader效果。像shadertoy创始人之一的IQ大神它在这方面有很多的建树。他的利用光线步进和躁声可以创建很多不可思议的3D场景。  vscode有一件shadertoy的插件,安装后可以新建一个*.glsl文件,写好代码就可以直接运行看

    2024年04月09日
    浏览(36)
  • OpenGL ES入门教程(一)编写第一个OpenGL程序

    从本文开始我将参考学习OpenGL ES应用开发实践指南 Android卷 [(美)KevinBrothaler著](提取码: 394m),并基于自己的理解以更加通俗易懂的方式讲解如何应用OpenGL ES。本系列教程的目标是应用OpenGL,所以不会涉及太多的理论知识,主要讲解方式是基于简单功能的代码拆解,学会对

    2024年02月06日
    浏览(49)
  • 让AI臣服,而不是被它替代!让ChatGPT为我们编写Unity3d Shaderlab的着色器(shader)

    ChatGPT的火热大家应该都有目共睹,文案工作者、翻译工作者和画师等各种行业都在被嘲即将失业。不光是这些岗位的员工,作为资深社畜程序猿也能感受到会受到冲击。网上很多人都在发ChatGPT写的代码,并开始大肆宣扬AI要取代程序员了,今天测一测使用ChatGPT来生成一些代码,

    2023年04月23日
    浏览(47)
  • 计算机图形学,OpenGL编写的一个可实现旋转缩放移动的房间,内有数十种交互

    #include stdlib.h #includestdio.h #includewindows.h #include GL/glut.h #include math.h #include gl/GLU.h //颜色宏定义 #define white 1.0f, 1.0f, 1.0f #define black 0.0f, 0.0f, 0.0f #define red 1.0f, 0.0f, 0.0f #define blue 0.0f, 0.0f, 1.0f #define skyBlue 135.0/255.0, 206.0/255.0, 1.0f #define plum 1.0f, 187.0/255.0, 1.0f //浅紫色 #define pink 1.0f, 1

    2024年04月17日
    浏览(65)
  • 实验二:OpenGL的简单动画

    一、实验目的 1.掌握OpenGL的闲置函数。 2.掌握OpenGL的时间函数。 3.掌握OpenGL的简单动画功能。 4.了解OpengGL裁剪窗口、视区、显示窗 口的概念和它们之间的关系。 5.进一步掌握OpenGL基本图元的绘制。 二、实验内容 1.闲置函数的使用与简单动画。 1)旋转的六边形如实验图2-1所

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包