s3.GLSL学习之着色器基础

2023-10-31

着色器

  着色器程序看起来确实和C语言非常类似,它们从入口点main函数开始,并且使用同样的字符集和注释约定,以及很多相同的处理指令。着色器是运行在GPU上的小程序。这些小程序为图形渲染管线的一个特定部分而运行。从基本意义上来说,着色器不是别的,只是一种把输入转化为输出的程序。着色器也是一种相当独立的程序,它们不能相互通信;只能通过输入和输出的方式来进行沟通。

  • 着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。
  • 每个着色器的入口都是main函数,在这里我们处理所有输入变量,用输出变量输出结果。

一个典型的着色器有下面的结构:

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

void main()
{
  // 处理输入
  ...
  // 输出
  out_variable_name = weird_stuff_we_processed;
}

以《OpenGL编程指南(原书第八版)》第一张的顶点着色器:triangles.vert为例

#version 430 core
layout(location = 0) in vec4 vPosition;

void main()
{
gl_Position = vPosition;
}

  第一行“#version 430 core”指定了我们所用的OpenGL着色语言的版本。这里的“430”表示我
准备使用OpenGL4.3对应的GLSL语言。这里的“core”表示我们将使用OpenGL核心模式(core profile)
  第二行我们分配了一个着色器变量。着色器变量是着色器与外部世界的联系所在。换句话说
着色器并不知道自己的数据从哪里来,它只是在每次运行时直接获取数据对应的输入变量。
  最后,在着色器的main()函数中实现它的柱体部分。对于这个着色器而言,它所实现的就是将输入的顶点位置复制到顶点着色器的指定输出位置gl_Position中。OpenGL所提供的一些着色器变量,它们全部都是以gl_作为前缀的。
  上面的//是注释符号,它到当前行的末尾结束,这一点与C语言一致。此外着色器程序也支持C语言形式的多行注释符号(//)。但是,与ANSI C语言不同,这里的main()函数不需要返回一个整数值,它被声明为void。
  更多的GLSL语法细节,我们在后面用到时再详述。

着色器的编译

  OpenGL着色器程序的编写与C语言等基于编译器的语言非常类似。我们使用编译器来解析程序,检查是否存在错误,然后将它翻译为目标代码。然后,在链接过程中将一系列目标文件合并,并产生最终的可执行程序。在程序中使用GLSL着色器的过程与之类似,只不过编译器和链接器都是OpenLG API的一部分而已。下图给出了创建GLSL着色器对象并且通过链接来生成可执行着色器程序的过程。
这里写图片描述

一般的流程如下:

  1. 先处理每个着色器对象(创建一个着色器对象->将着色器源代码编译成对象->验证着色器的编译是否成功)
  2. 链接着色器对象为一个着色器程序(创建一个着色器程序->j将着色器对象关联到着色器程序->链接着色器程序->判断着色器的链接过程是否成功完成->使用着色器来处理顶点和片元)

示例演示

目前我们可以将GLSL编程流程总结为:
1. 向OpenGL传递数据(如上节的glBufferData等工作)
2. 着色器的编译(流程如上)
3. 指定着色器的变量和缓存对象中数据的关系(如glVertexAttribPointer等工作)
这里我们按照该流程,在上一节代码基础上渲染出一个三个点颜色不同的三角形。主要代码如下:

void MyQGLWidget::initShader()
{
    glGenVertexArrays(NumVAOs, VAOs);
    glBindVertexArray(VAOs[Triangles]);
    GLfloat vertices[] = {
        // 位置                 // 颜色
         0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
         0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 顶部
    };
    glGenBuffers(NumBuffers, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(vColor);
    glVertexAttribPointer(vColor, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));

    const char*  vertexShaderCode =
        "#version 430 \n"
        ""
        "layout(location = 0) in vec3 vPosition;"
        "layout(location = 1) in vec3 color;"
        "out vec3 myColor;"
        ""
        "void main()"
        "{"
        "   gl_Position = vec4(vPosition, 1.0);"
        "   myColor = color;"
        "}";

    const char* fragmentShaderCode =
        "#version 430 \r \n"
        ""
        "in vec3 myColor;"
        "out vec4 fColor;"
        ""
        "void main()"
        "{"
        "   fColor = vec4(myColor, 1.0f);"
        "}";
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    const char* adapter[1];
    adapter[0] = vertexShaderCode;
    glShaderSource(vertexShaderID, 1, adapter, 0);

    adapter[0] = fragmentShaderCode;
    glShaderSource(fragmentShaderID, 1, adapter, 0);

    glCompileShader(vertexShaderID);
    glCompileShader(fragmentShaderID);

    GLuint programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);

    glLinkProgram(programID);
    glUseProgram(programID);

}

运行结果:

这里写图片描述

代码分析:

顶点着色器源代码中出现了如下代码:

layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec3 color;

这里layout(location = 0) 或 layout(location = 1)叫做布局限定符,目的是为变量提供元数据(meta data)。我们可以使用布局限定符来设置很多不同的数学。0或1对应glEnableVertexAttribArray和
glVertexAttribPointer的第一参数。

代码下载
OpenGL学习系列导航

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

s3.GLSL学习之着色器基础 的相关文章

随机推荐

  • CSS——网易云音乐首页导航栏的制作

    文章目录 前言 一 结构的布局 二 实现过程 1 HTML结构 2 CSS样式 总结 前言 本文主要介绍了网易云导航栏的制作过程 这个案例中将会运用到CSS中的浮动 绝对定位等相关知识点 这些在以往的文章里有所介绍 一 结构的布局 示例图
  • js数组去重(9种方法),你都会了吗?

    以下共有九种数组去重的方式和详解 包含对象数组去重 1 利用Array from new Set 去重 1 利用set去重 Set是es6新增的数据结构 似于数组 但它的一大特性就是所有元素都是唯一的 没有重复的值 我们一般称为集合 Arr
  • Qt QSqlQueryModel详解

    背景知识 Qt SQL的API分为不同层 驱动层 驱动层 对于QT是基于C 来实现的框架 该层主要包括QSqlDriver QSqlDriverCreator QSqlDriverCreatorbase QSqlDriverPlugin a
  • C4droid安装使用教程

    1 C4droid简介 手机 Android 上C C 的IDE 编译器 便携 功能强大 足以满足初学者平时的练习 汉化版 更易理解和使用 2 C4droid下载 在我分享的百度网盘链接中下载 https pan baidu com s 1
  • mysql yearweek函数_MySQL的YEARWEEK函数(转)_MySQL

    MySQL的YEARWEEK函数以及查询本周数据MySQL 的 YEARWEEK 是获取年份和周数的一个函数 函数形式为 YEARWEEK date mode 例如 2010 3 14 礼拜天 www bitsCN com SELECT Y
  • numpy:广播机制

    广播是numpy对不同形状的数组进行数值计算的方式 对数组的算术运算通常在相应的元素上进行的 如果两个数组a和b形状相同 即满足a shape b shape 那么a b的结果就是a与b数组对应位相乘 这要求维数相同 且各维度的长度相同 对
  • 2023华为OD机试真题【区块链转储系统】

    题目描述 区块链底层存储是一个链式文件系统 由顺序的N个文件组成 每个文件的大小不一 依次为F1 F2 Fn 随着时间的推移 所占存储会越来越大 云平台考虑将区块链按文件转储到廉价的SATA盘 只有连续的区块链文件才能转储到SATA盘上 且
  • Pandas中inf值替换

    文章目录 问题 出现inf的原因 解决办法 参考文章 问题 今天使用Pandas从MySQL读取数据 在处理之后再写回到数据库时报了一个错误 sqlalchemy exc ProgrammingError MySQLdb exception
  • mysql数据库 期末总结

    目录 数据库基础知识 MySQL命令 字符集 库操作 表操作 创建 查看和删除 修改表 复制表 约束控制 数据操作 插入数据 增 删除数据 删 修改数据 改 查询数据 查 单表查询 分组查询 排序 限制查询结果数量 集合函数 多表查询 1
  • Game of Primes (博弈)

    Game of Primes 题目链接 题意 初始有两个数 x 和 y 每次操作可以选择一个数减1 Alice和Bob轮流操作 指定某人先手 1 如果某时刻 x k 或 y k Bob胜 2 如果某时刻 x y都是素数 Alice胜 3 如
  • shell使用示例

    文章目录 shell使用示例 统计一个文本文件中每个单词出现的频率 打印文本文件的第十行 判断有效的电话号码 输出数字范围内7的倍数 shell使用示例 统计一个文本文件中每个单词出现的频率 cat text tr s n sort uni
  • Win11 文件夹打开慢或卡顿解决方案

    问题 目前是 2023 2 27 我的 Win11 系统点开一个文件夹要等待 2 3 秒才能加载出来 使用体验极差 网上查阅大量资料 有些人在系统更新后这个情况就消失了 但是我这一直存在 系统也是当前的最新版 没有修复 目前得出的结论是 因
  • 修改Maven的本地仓库位置

    最近开始学SSM整合项目视频时 需要用到Maven仓库于是便开始研究起了Maven 首先需要在官网下载Maven的压缩包 然后进行解压 再把其加入到环境变量中 由于主要研究的时Maven的如何修改仓库位置 所以这里就一笔带过 不知道如何配置
  • MySQL复习笔记-一条SQL更新语句是如何执行的?

    前面我们系统了解了一个查询语句的执行流程 并介绍了执行过程中涉及的处理模块 相信你还记得 一条查询语句的执行过程一般是经过连接器 分析器 优化器 执行器等功能模块 最后到达存储引擎 那么 一条更新语句的执行流程又是怎样的呢 之前你可能经常听
  • 简单的Markdown功能实现——marked模块的使用

    marked是一个markdown 解析 编译器 通过引入marked模块 可以实现一个简单的markdown编辑器 使用方式如下 Install 新建一个项目文件夹 在项目中下载marked模块 Usage 新建一个marked js文件
  • java 生成纯色图片_canvas简单实现纯色背景图片抠图(示例代码)

    最近在研究html5 canvas的过程中 发现 canvas为前端对图像的处理开辟了一条新的道路 canvas可以做到很多事情 甚至可以做个类似于PhotoShop的东西 曾经本人在一家软件工作就做类似的工作 可以看一下我之前开发的软件
  • 支付宝、微信Android APP支付接入流程

    支付类型 一次性支付 自动续费 支付宝周期扣款 微信委托扣款 1 支付并签约 2 先签约后扣费 注 微信委托扣款中先签约后扣费 自动续费 授权扣款 免密支付 支付宝 支付流程中各端交互逻辑 支付流程中商户APP端交互逻辑 先签约后扣费流程中
  • 深度学习笔记2:手写一个单隐层的神经网络

    欢迎关注天善智能 我们是专注于商业智能BI 人工智能AI 大数据分析与挖掘领域的垂直社区 学习 问答 求职一站式搞定 对商业智能BI 大数据分析挖掘 机器学习 python R等数据领域感兴趣的同学加微信 tsaiedu 并注明消息来源 邀
  • layout_weight属性的用法和意义

    一直没理解在LinearLayout中的layout weight属性的意义 使用的时候都是将子控件的layout width或者layout height设置为0 然后在设置layout weight的权重值 以至于在被问到如果设置了la
  • s3.GLSL学习之着色器基础

    着色器 着色器程序看起来确实和C语言非常类似 它们从入口点main函数开始 并且使用同样的字符集和注释约定 以及很多相同的处理指令 着色器是运行在GPU上的小程序 这些小程序为图形渲染管线的一个特定部分而运行 从基本意义上来说 着色器不是别