目录

GLSL简介

GLSL的内建变量

顶点着色器变量

gl_PointSize

gl_VertexID

片段着色器变量

gl_FragCoord

gl_FragDepth


参考网站:LearnOpenGL

参考书籍:OpenGL编程指南第九版

GLSL简介

OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。比如:视图转换、投影转换等。GLSL(GL Shading Language)的着色器代码分成2个部分:Vertex Shader(顶点着色器)和Fragment(片段着色器),有时还会有Geometry Shader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。

GLSL的内建变量

我们已经学会使用顶点属性、uniform和采样器来完成这一任务了。然而,除此之外,GLSL还定义了另外几个以gl_为前缀的变量,它们能提供给我们更多的方式来读取/写入数据。我们已经在前面教程中接触过其中的两个了:顶点着色器的输出向量gl_Position,和片段着色器的gl_FragCoord。

我们将会讨论几个有趣的GLSL内建输入和输出变量,并会解释它们能够怎样帮助你。注意,我们将不会讨论GLSL中存在的所有内建变量,如果你想知道所有的内建变量的话,请查看OpenGL的wiki。

顶点着色器变量

我们已经见过gl_Position了,它是顶点着色器的裁剪空间输出位置向量。如果你想在屏幕上显示任何东西,在顶点着色器中设置gl_Position是必须的步骤。这已经是它的全部功能了。

gl_PointSize

我们能够选用的其中一个图元是GL_POINTS,如果使用它的话,每一个顶点都是一个图元,都会被渲染为一个点。我们可以通过OpenGL的glPointSize函数来设置渲染出来的点的大小,但我们也可以在顶点着色器中修改这个值。

GLSL定义了一个叫做gl_PointSize输出变量,它是一个float变量,你可以使用它来设置点的宽高(像素)。在顶点着色器中修改点的大小的话,你就能对每个顶点设置不同的值了。

在顶点着色器中修改点大小的功能默认是禁用的,如果你需要启用它的话,你需要启用OpenGL的GL_PROGRAM_POINT_SIZE:

glEnable(GL_PROGRAM_POINT_SIZE);

一个简单的例子就是将点的大小设置为裁剪空间位置的z值,也就是顶点距观察者的距离。点的大小会随着观察者距顶点距离变远而增大。

void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);    gl_PointSize = gl_Position.z;
}

结果就是,当我们远离这些点的时候,它们会变得更大:

main中使用0号(接下来不再说明,如果用了多个,从小到大)

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);

shader.vert

#version 330 core
layout (location = 0) in vec3 aPos;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main() {gl_Position = projection * view * model * vec4(aPos, 1.0);gl_PointSize = gl_Position.z;
}

shader.frag

#version 330 coreout vec4 FragColor;void main() {FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}

运行结果

gl_PointSize越远越大

全部代码下载

我的网盘
提取码:waxk

gl_VertexID

gl_Positiongl_PointSize都是输出变量,因为它们的值是作为顶点着色器的输出被读取的。我们可以对它们进行写入,来改变结果。顶点着色器还为我们提供了一个有趣的输入变量,我们只能对它进行读取,它叫做gl_VertexID

整型变量gl_VertexID储存了正在绘制顶点的当前ID。当(使用glDrawElements)进行索引渲染的时候,这个变量会存储正在绘制顶点的当前索引。当(使用glDrawArrays)不使用索引进行绘制的时候,这个变量会储存从渲染调用开始的已处理顶点数量。

虽然现在它没有什么具体的用途,但知道我们能够访问这个信息总是好的。

片段着色器变量

在片段着色器中,我们也能访问到一些有趣的变量。GLSL提供给我们两个有趣的输入变量:gl_FragCoordgl_FrontFacing

gl_FragCoord

在讨论深度测试的时候,我们已经见过gl_FragCoord很多次了,因为gl_FragCoord的z分量等于对应片段的深度值。然而,我们也能使用它的x和y分量来实现一些有趣的效果。

gl_FragCoord的x和y分量是片段的窗口空间(Window-space)坐标,其原点为窗口的左下角。我们已经使用glViewport设定了一个800x600的窗口了,所以片段窗口空间坐标的x分量将在0到800之间,y分量在0到600之间。

通过利用片段着色器,我们可以根据片段的窗口坐标,计算出不同的颜色。gl_FragCoord的一个常见用处是用于对比不同片段计算的视觉输出效果,这在技术演示中可以经常看到。比如说,我们能够将屏幕分成两部分,在窗口的左侧渲染一种输出,在窗口的右侧渲染另一种输出。下面这个例子片段着色器会根据窗口坐标输出不同的颜色:

我将第一个三角形的片段着色器进行了修改:

//片段着色器
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"if(gl_FragCoord.x < 400)\n"
"FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"else\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";

gl_FragCoord的使用

全部代码下载

我的网盘
提取码:waxk

gl_FragDepth

输入变量gl_FragCoord能让我们读取当前片段的窗口空间坐标,并获取它的深度值,但是它是一个只读(Read-only)变量。我们不能修改片段的窗口空间坐标,但实际上修改片段的深度值还是可能的。GLSL提供给我们一个叫做gl_FragDepth的输出变量,我们可以使用它来在着色器内设置片段的深度值。

要想设置深度值,我们直接写入一个0.0到1.0之间的float值到输出变量就可以了:

gl_FragDepth = 1.0; // 这个片段现在的深度值为 1.0

如果着色器没有写入值到gl_FragDepth,它会自动取用gl_FragCoord.z的值。

然而,由我们自己设置深度值有一个很大的缺点,只要我们在片段着色器中对gl_FragDepth进行写入,OpenGL就会(像深度测试小节中讨论的那样)禁用所有的提前深度测试(Early Depth Testing)。它被禁用的原因是,OpenGL无法在片段着色器运行之前得知片段将拥有的深度值,因为片段着色器可能会完全修改这个深度值。

在写入gl_FragDepth时,你就需要考虑到它所带来的性能影响。然而,从OpenGL 4.2起,我们仍可以对两者进行一定的调和,在片段着色器的顶部使用深度条件(Depth Condition)重新声明gl_FragDepth变量:

layout (depth_<condition>) out float gl_FragDepth;

condition可以为下面的值:

条件 描述
any 默认值。提前深度测试是禁用的,你会损失很多性能
greater 你只能让深度值比gl_FragCoord.z更大
less 你只能让深度值比gl_FragCoord.z更小
unchanged 如果你要写入gl_FragDepth,你将只能写入gl_FragCoord.z的值

通过将深度条件设置为greater或者less,OpenGL就能假设你只会写入比当前片段深度值更大或者更小的值了。这样子的话,当深度值比片段的深度值要小的时候,OpenGL仍是能够进行提前深度测试的。

下面这个例子中,我们对片段的深度值进行了递增,但仍然也保留了一些提前深度测试:

#version 420 core // 注意GLSL的版本!
out vec4 FragColor;
layout (depth_greater) out float gl_FragDepth;void main()
{             FragColor = vec4(1.0);gl_FragDepth = gl_FragCoord.z + 0.1;
}  

注意这个特性只在OpenGL 4.2版本或以上才提供。笔者没有使用这么高版本的,故没有测试。

更多OpenGL知识:现代OpenGL入门教程

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

OpenGL-GLSL语言入门教程(1)相关推荐

  1. c++ 结构体赋值_《零基础看得懂的C语言入门教程》—(十二)结构体是这么回事

    一.学习目标 了解C语言的结构体的使用方法 了解C语言结构体的结构的赋值 了解多种C语言结构体变量的赋值方法和取值方法 目录 <零基础看得懂的C语言入门教程>--(二)简单带你了解流程 & ...

  2. c语言入门教程文库,C语言入门教程(全集)课件

    C语言入门教程(全集)课件 01123364105 Y N p AB X=0? YN P1 A A P2 a a b b Y Y N N y n A B P A A B X=0? 3 a97 3 U ...

  3. 2017年Go语言入门教程-徐培成-专题视频课程

    2017年Go语言入门教程-3763人已学习 课程介绍         Go语言入门教程,只要你懂中文都可以看的懂本套教程,为任何想学习Go语言研制的教程. 课程收益     让任何人都可以轻松掌握G ...

  4. GO语言入门教程(二)

    Hello,各位小伙伴,在接着之前发表的Go语言系列教程之投石问路之后,我们大致了解了一下Go语言的发展史和Go语言的优势,另外我也带着小伙伴进行了Go语言环境的安装和常用命令的介绍.接下来我们就正式 ...

  5. java编程输出平行四边形_JAVA语言入门教程之打印图形实例——打印平行四边形...

    本文主要向大家介绍了JAVA语言入门教程之打印图形实例--打印平行四边形,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 输出平行四边形: public class Parallelo ...

  6. C语言入门教程学习 C语言学习包括哪些?

    嵌入式开发有一定了解的朋友们知道是在操作系统内部开发的,对于操作系统内部来说基本上都是用C语言来进行编译的,所以说对于C语言的学习在嵌入式开发过程中是非常重要的.下面就给大家介绍一些C语言入门教程的相 ...

  7. 小白都能看懂的C语言入门教程

    文章目录 C语言入门教程 1. 第一个C语言程序HelloWorld 2. C语言的数据类型 3. 常量变量的使用 4. 自定义标识符#define 5. 枚举的使用 6. 字符串和转义字符 7. 判 ...

  8. 计算机语言中的逻辑型数据,零基础易语言入门教程(五)之逻辑型数据类型

    在上篇文章给大家介绍了零基础易语言入门教程(四)之数据类型,上篇针对数值到文本类型知识,今天给大家介绍下逻辑型数据. 具体方法和步骤如下所示: 1.逻辑型数据非真即假: 首先申请一个局部变量(A)类型 ...

  9. iOS开发之c语言入门教程

    苹果作为移动互联的高端品牌,iOS操作系统也被用户公认为是最好用的移动互联网操作系统.据了解,曾一度拒绝为iOS平台对出浏览器的火狐在今年5月份的时候,他们却食言了.今天,Mozilla宣布iOS版F ...

  10. c语言5基础教程,[简001]《极简C语言入门教程》共5章

    Saturday,May 18,2019 ---Andy ###目录: 前言 第一章 数据类型 1.1 数据类型 1.2 宏定义.常量.变量(一般和指针型) 第二章 格式化输入输出 2.1 输入 2. ...

最新文章

  1. js parsefloat
  2. Mac svn使用学习-2-服务端
  3. 可搜索本机文档内容软件:anytext(批量检索文档内容)(不是很好用,推荐用filelocator)
  4. 解决 spring-cloud-starter-zipkin 启动错误
  5. jeecg中ajax传值的前端js和后台代码
  6. 算法导论课后习题解析 第四章 下
  7. linuxoracle查看用户权限_权限管理系统设计过程
  8. cache数据库和mysql_并发环境下,先操作数据库还是先操作缓存?
  9. 一段有趣的python小代码(将numpy中的数组转化为可哈希的字典)
  10. Revit二次开发——选集
  11. 大合集!2019-2020年目标跟踪资源全汇总(论文、模型代码、优秀实验室)
  12. 单模光纤和多模光纤区别
  13. “AI复活了我的妻子,但我决定跟她说再见了”
  14. 什么是DOM(超详细解释,建议收藏!!!)
  15. BIOS知识枝桠——GPU
  16. 应用型人才的培养之随笔
  17. 【R语言】5种探索数据分布的可视化技术
  18. 日本用计算机模拟核试验,法国:将用超级计算机模拟核试验
  19. busybox文件系统制作
  20. 计算机蓝牙快捷键,如何打开Windows10笔记本电脑的蓝牙,快捷键打开笔记本电脑的蓝牙!...

热门文章

  1. 硅谷“钢铁侠”:最不爱钱的人,却成了最有钱的人!
  2. Godaddy注册的域名转发、转向教程
  3. extern C 引起的 error C2059
  4. 大三Web课程设计——悬崖上的波妞(4页) HTML+CSS(可以很好的应付老师的作业)
  5. tomcat乱码解决方案 tomcat 乱码
  6. 简单知识——跨页面信息传递
  7. 生产者消费者模型问题
  8. git学习——上传项目代码到github
  9. 圣思园官方论坛正式上线,众板块版主火热招募中,欢迎围观
  10. 12-render函数