首页 > 其他分享 >OpenGL-GLSL语言入门教程(1)

OpenGL-GLSL语言入门教程(1)

时间:2023-03-12 09:13:49浏览次数:33  
标签:GLSL 片段 OpenGL 入门教程 FragCoord gl 着色器

目录

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 core

out vec4 FragColor;

void main() {
FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
运行结果


gl_PointSize越远越大
全部代码下载

我的网盘
提取码:waxk

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

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

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

片段着色器变量
在片段着色器中,我们也能访问到一些有趣的变量。GLSL提供给我们两个有趣的输入变量:gl_FragCoord和gl_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入门教程

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。
————————————————
原文链接:https://blog.csdn.net/lady_killer9/article/details/89474563

 

标签:GLSL,片段,OpenGL,入门教程,FragCoord,gl,着色器
From: https://www.cnblogs.com/im18620660608/p/17207587.html

相关文章

  • OpenGL学习(十)-- 着色语言 GLSL 语法介绍
    我的OpenGL专题学习目录,希望和大家一起学习交流进步!OpenGL学习(一)--术语了解OpenGL学习(二)--Xcode搭建OpenGL环境OpenGL学习(三)--OpenGL基础渲染OpenGL学习(......
  • 高级GLSL
    这一小节并不会向你展示非常先进非常酷的新特性,也不会对场景的视觉质量有显著的提高。但是,这一节会或多或少涉及GLSL的一些有趣的地方以及一些很棒的技巧,它们可能在今后会......
  • OpenGL笔记十四:GLSL语法
    前言期待您移步上篇:OpenGL笔记十三:GLSL加载纹理颠倒六种方案概述GLSL全称OpenGLShadingLanguage,是用来在OpenGL中着色编程的语言,即开发人员写的自定义程序代码......
  • GLSL基础语法介绍
    GLSL(OpenGL着色语言OpenGLShadingLanguage)语法跟C语言很类似,在可编程管线中我们必须要纯手写顶点和片源着色器,这里就要求必须使用GLSL,自行编译,链接,使用,本片文章介绍......
  • WebGL着色器GLSL矩阵mat
    WebGL着色器GLSL矩阵mat本文是WebGL教程(电子书)的2.5节内容着色器语言中通过关键字mat2、mat3、mat4分别声明一个2x2矩阵、3x3矩阵、4x4矩阵,通过内置函数mat2()、mat3()......
  • GLSL shder的简单示例
    GLSL的HelloWorld这一节中包含一个最基本的shader,它提供如下功能:顶点变换然后使用单一的颜色渲染图元。顶点shader前面已经说过,顶点shader负责完成顶点变换。这里将按......
  • GLSL语法简单总结
    1、变量类型基础类型:bool,int,uint,float,double向量类型:vecN,bvecN,ivecN,uvecN,dvecNN表示向量维数(N=1,2,3,4)。含前缀b为bool向量,i为int向量,u为uint向量,d为double向量,不含......
  • Shader 入门:GLSL ES(数据类型)
    在上一篇文章中我们初步了解了GLSLES的基本语法,那么本篇文章就和大家一起学习GLSLES的数据类型。Let’sgo!!!上一篇:《Shader入门:GLSLES(简介和基本语法)》在本系......
  • openGL之glsl入门1--基本概念
    从零开始学习openGL与GLSL(没有计算机图像学基础),开始确实挺费劲,网上的资料虽然多,但不系统,例子也不全,openGL还好(这里指的是v2.0之前的版本,使用glBegin(),glEnd()方式绘制),完......
  • 自定义控件 QOpenGLWidget并实现缩放(纯代码)
    QScrollArea+QOpenGLWidget实现缩放,用于显示QImage。先自定义QOpenGLWidget,然后自定义QWidget(上图)glwidget.h#ifndefGLWIDGET_H#defineGLWIDGET_H#include<QO......