OpenGL--GLSL基础

news/2024/10/29 2:32:39/

Shader简介

首先简单介绍一下Shader是什么,Shader意为着色器,只是整个图形渲染管线流程中的某几个单元,也可以理解为图形渲染管线中的几处会被执行的代码,Shader主要包括:顶点Shader,片段Shader以及几何Shader这3种。

那么顶点,片段和几何分别是什么呢?顶点很好理解,如要绘制一张图片,一般是一个由四个顶点组成的图形。就是我们读书那会几何学里的顶点一个意思。

片段简单点理解就是要绘制这张图片的每一个像素。(这种叫法一般指在渲染管线的着色阶段的像素,片段和像素是有区别的,如在重叠的情况下,一个像素上可以渲染多个片段)

几何指的是要绘制的形状,同样的4个点,可以组成两个三角形、一个四边形或者两条线。

我们通常说的图形渲染其实就是一个固定流水线流程,即一张图片从无到有怎么显示到显示器上的一个过程。Shader就是这个过程中我们程序员唯一能动态操作改变的部分。操作的桥梁就是语言了,DirectX中是HLSL,OpenGL中使用的是GLSL语言来编写Shader脚本,可以写出各种炫酷的效果~

图形渲染管线

下面我们来大致讲讲图形渲染管线流程的具体的几个步骤:
1.准备好顶点数据和顶点连通性数据。顶点数据包括顶点的位置、颜色、纹理坐标、法线等数据,而顶点连通性数据则是描述顶点之间如何连接组合的数据,如这边两个顶点是连成一条线,这边三个顶点组成一个三角形。

2.将第一步获取的顶点数据进行处理,包括顶点位置变换,顶点光照计算,生成纹理坐标等操作,处理完后输出到下一步。(顶点着色器负责阶段

3.根据上面提供的顶点数据和顶点连通性数据,将点连成线,线连成面。把零零散散的顶点组装成一个一个的图元,并且将图元进行栅格化,即处理成一个一个的像素格子,并且决定了每个像素格子的位置,这就是我们说的片段。
被确定的除了片段的位置之外,还可能包含片段的颜色,OpenGL会根据图元各个顶点的颜色,纹理坐标进行插值,得出每个片段的颜色插值。这个阶段还会对不在视口范围中的内容进行裁剪背面剔除操作也会在这个阶段执行。(几何着色器负责阶段,这个我们一般不会用到,因为一般不需要我们再去实现一套新的图元组装规则)

4.对第三步输出的片段进行处理,包括对颜色处理,或者丢弃片段,雾化也是在这个阶段执行的。(片段着色器负责阶段

5.为即将呈现到屏幕上的内容进行最后的处理,即对每个片段进行一系列的测试

  • 裁剪测试,激活GL_SCISSOR_TEST时开启,判断是否在设定的裁剪窗口中,如是则通过,否则不渲染当前片段。
  • Alpha测试,激活GL_ALPHA_TEST时开启,判断当前片段的透明度是否符合glAlphaFunc设定的条件(如透明度大于0.5),如是则通过,否则不渲染当前片段。
  • 模版测试,激活GL_STENCIL_TEST时开启,判断当前片段模版值与模版缓冲区中对应的模版值是否符合glStencilFunc()函数设定的条件,如是则通过,否则不渲染当前片段。
  • 深度测试,激活GL_DEPTH_TEST时开启,用于判断片段的前后遮挡关系,判断当前片段的深度值和深度缓冲区中对应的值是否符合glDepthFunc()函数设定的条件,如是则通过,否则不渲染当前片段。

最后,如果测试都通过了的话,会根据当前的混合模式将片段更新到帧缓冲区里对应的像素中,当屏幕刷新时,帧缓冲区的内容会被渲染到屏幕上。这就是我们看到一个图像如何显示到屏幕上的整个过程。

GLSL基础语法

下面我们看看怎么编写Shader脚本,GLSL语法类似C语言,顶点着色器和片段着色器都是使用GLSL编写的。
一:数据类型和变量
1.基础类型
GLSL支持以下三种基本数据类型:float、int、bool
需要特别注意的是,假设有一个float变量,在着色器中将其赋值为1,在一些显卡上可能会崩溃!因为1是整数不是浮点数,所以需要将1.0赋给浮点型变量。可以这样使用基本类型变量:

int a, b;
float c = 3.0;
bool d = true;

2.向量类型
上面3种基本数据类型分别对应3种向量:
vec2、vec3、vec4:浮点型向量,可以存储2~4个浮点数。
ivec2、ivec3、ivec4:整数向量。
bvec2、bvec3、bvec4:布尔型向量。
向量的操作是很灵活的,可以使用下标来访问向量的分量,也可以使用x、y、z、w字段来访问向量的成员,使用r、g、b、a字段可以访问颜色向量,使用s、t、p、q字段可以访问纹理坐标向量。如果要访问向量的x、y、z3个字段,还可以连续使用字段。下面来代码演示下:

vec2 a = vec2(1.0, 2.0);
vec3 b = vec3(3.0, 4.0, 5.0);
vec3 color = b.rgb;    //使用rgb来操作b的三个分量
float c = a[0];        //使用下标的方式来访问a的第一个变量
vec3 d = vec3(a, c);   //使用一个vec2和一个float初始化vec3
float e = float(d);    //d的x分量被赋值给了e

3.矩阵类型
GLSL提供了2✖️2,3✖️3,4✖️4共3种矩阵类型,分别使用mat2,mat3,mat4表示。此外还支持2~4✖️2~4的任意矩阵,如mat3✖️2、mat4✖️3等。用法和向量类似。

4.采样器
GLSL提供了一组采样器,这是一种用于访问纹理的特殊类型,在读取纹理值时会用到,主要有下面几种采样器。

  • sampler1D:一维纹理采样器
  • sampler2D:二维纹理采样器
  • sampler3D:三维纹理采样器
  • samplerCube:立方体映射纹理采样器
  • sampler1DShadow:一维阴影映射采样器
  • sampler2DShadow:二维阴影映射采样器

5.数组和结构体
在GLSL中,可以像C语言一样声明和访问数组,但不能在声明时直接初始化数组,数组下标从0开始,如:

int a[3];
a[0] = 1;

GLSL还可以定义结构体,定义和初始化如下:

struct xxx
{vec3 pos;vec3 color;
};xxx st1;
xxx st2 = xxx(vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0));
st2.pos = vec3(0.0, 1.0, 0.0);

二:操作符

=<+-*/&&||.等等这些基本和c语言操作符一致,不作过多介绍。

三:变量修饰符
变量修饰符放在变量类型之前,用于修饰变量,GLSL常用的有以下变量修饰符。

  • const:编译时期的常量,不可被修改
  • attribute:属性变量
  • uniform:统一变量
  • varying:易变变量

属性变量和统一变量都是只读的全局变量(不能定义在函数内),都是由OpenGL应用程序设置的变量,即值由底层操作,我们只需定义使用。
属性变量是针对每个顶点的数据,所以只能在顶点着色器中定义,一般会将顶点的颜色、位置、法线等顶点数据作为属性变量传递给顶点着色器。
统一变量是针对整个图元的数据,既可以在顶点着色器中使用,也可以在片段着色器中使用。我们把统一变量作为中间媒介,通过统一变量传递应用程序中的变量给着色器使用

易变变量是着色器中最神奇的变量,也最不容易理解。主要用于存储插值数据,必须同时在顶点着色器和片段着色器中定义同一个易变变量,在顶点着色器中写入易变变量的值,然后在片段着色器中获取易变变量的值(片段着色器中,易变变量是只读的)。
在顶点着色器中写入顶点的插值,然后到了插值计算阶段会根据这些顶点的插值会进行插值运算,计算出顶点之间片段的值。简单的讲就是对数据进行插值计算。

四:语句与函数
GLSL语句和函数基本和c语言一致,支持if-else,for,while,do-while语句,同时支持break和continue关键字。在片段着色器中,还可以使用discard语句来丢弃当前片段。
着色器程序由函数组成,每个着色器都需要有一个main()函数,和c一样这是程序的入口。
函数返回值可以是任意类型,但不能是数组。函数参数有3种修饰符,分别是in,out,inout,分别表示输入、输出、既输入又输出。没有指定默认为in。函数还允许重载。

bool areyouhappy(in float money)
{if(money < 1000000000.0)return false;elsereturn true;
}

五:Shader简单示例
简单的颜色Shader脚本:

//顶点Shader
//输入顶点和颜色数据
attribute vec4 vVertex;
attribute vec4 vColor;
//输出颜色插值到vVaryingColor中
varying vec4  vVaryingColor;
void main()
{vVaryingColor = vColor;gl_Position = vVertex;
}
//片段Shader
//拿到经过插值后的vVaryingColor,将它设置到最终输出的gl_FragColor变量中
varying vec4 vVaryingColor;
void main()
{gl_FragColor = vVaryingColor;
}

顶点着色器最主要的职责就是计算位置,所以顶点着色器至少需要写入一个变量gl_Position,这个是GLSL内置的位置变量,需要将变换后的顶点坐标赋予该变量。

片段着色器主要职责是计算片段颜色,所以需要将片段最终颜色写入内置的gl_FragColor变量中(或者将该片段抛弃)。


http://www.ppmy.cn/news/206784.html

相关文章

x10ti怎么禁用核显_顶配玩光追,机械革命X10Ti-S游戏本快速体验

来源&#xff1a;新浪众测 作者&#xff1a;超高校级的囧小平 前言 国内疫情逐渐进入了平稳期&#xff0c;各地已经逐渐全面复工&#xff0c;笔记本厂商们也陆续发布了自己的新一代产品。向来主打性价比的机械革命在4月2日发布了三款游戏本新品&#xff0c;并于4月15日发售&…

电大计算机应用技术基础形考二,贵州电大2020年春季《计算机应用技术基础》计算机应用技术基础02任务满分...

2020年春季《计算机应用技术基础》计算机应用技术基础02任务8 e0 T4 M9 X5 Z! l ? 1.[判断题] 存储器容量的基本单位是字节。( ) # n( _/ [ R ~% R# J E请参考帮助中心说明&#xff0c;自助下载答案 ; w7 0 s2 I8 u A.√ % C H" D; x2 T9 \# h. ~, {! | k B. : |…

纯净Ubuntu16安装CUDA(9.1)和cuDNN

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 自己有一台2015年的联想笔记本&#xff0c;显卡是GTX950M&#xff0c;已安装ubuntu 16.04 LTS桌面版&#xff0c;为了使用其GPU完成deeplearning4j…

基于树莓派4B设计的音视频播放器(从0开始)

一、前言 【1】功能总结 选择树莓派设计一款家庭影院系统,可以播放本地视频、网络视频直播、游戏直播、娱乐直播、本地音乐、网络音乐,当做FM网络收音机。 软件采用Qt设计、播放器引擎采用ffmpeg。 当前的硬件选择的是树莓派4B,烧写官方系统,完成最终的开发。 本篇文章主…

amd r7 200 linux驱动,AMD Radeon R7 200Seres显卡不能驱动的问题!

尽管我知道发米高手如云,但有时间帮忙解答的人不多,但还是想寻求一下知心人,因为强烈的求知欲望令我备受折磨! 交待一下:我的显卡是AMD Radeon R7 200Seres,ID是683F1002, 系统是Yosemite10.10.5,引导是最新变色龙(Chameleon_2.3svn_r2705_trunk_pkg+wowpc), …

各种显卡指标参数查询

各种显卡指标参数查询 为什么需要这个&#xff1f;它有什么用&#xff1f; 这份伟大的清单详细给你列出了各个时期的各个厂商各个芯片组显卡的性能 它能为你的引擎程序员提供参考&#xff0c;什么样的显卡技术是适合目前使用的&#xff0c;什么样的过于前卫、什么样的已经成为事…

实验篇(7.2) 05. 通过浏览器访问远端内网服务器 (SSL) ❀ 远程访问

【简介】直接将内网服务器映射成公网IP&#xff0c;可以方便的从任何地方访问服务器的指定端口&#xff0c;但是这种方式下&#xff0c;服务器是公开且暴露的。那有没有即方便、又比较安全的远程访问服务器的方法呢&#xff1f;我们来看看SSL VPN的Web模式。 SSL VPN介绍 从概念…

Scala学习(十二)---模式匹配

文章目录 1.基本语法2.模式守卫3.匹配常量和类型4.匹配对象和样例类4.1 匹配对象4.2 匹配样例类 5.偏函数中的模式匹配 1.基本语法 在Scala中的模式匹配类似于Java中的switch语法 //模式匹配基本语法val a10val b20val c""c match {case "" >println(…