从0开始的OpenGL学习(十)-GLSL语言及语法

本文主要解决两个问题:

  • GLSL基本语法介绍

在前面第四讲中我们简单提及了GLSL语言,但是没有太深入,对于我们学习及后面编写的openGL GLSL来说,有些吃力,所以这里单独写一篇来介绍GLSL语言.

1. GLSL 编程概念

顶点着色器(.vs文件)与片元着色器(.fs文件)

一个着色器程序分为两大部分,即 “顶点着色器” 与 “片元着色器” 简单来说,前者多用于模型构建,后者用于在光栅化时表现出更多细节,一个着色器程序必须同时包含这两部分,程序会先通过 “顶点着色器” 处理再交与 “片元着色器” 渲染细节。

渲染细节

举个例子:比如你想绘制一个蓝色四面体,那就需要用到 8 个顶点 和 “蓝” 这两个参数。 其中 8 个顶点数据先传入 “顶点着色器” 这时一个四面体的模型便建立了,而 “蓝色” 这一参数属于纹理细节,将在 “片元着色器” 中被处理。
处理流程

2. GLSL语法介绍

2.1 内置变量

GLSL 是一种面向过程的编程语言,有着与 C 语言类似的语法,但没有 C 语言复杂的指针概念。 常用基本的类型如下:

类型说明
void空类型,即不返回任何值
bool布尔类型 true,false
int带符号的整数 signed integer
float带符号的浮点数 floating scalar
vec2, vec3, vec4n维浮点数向量 n-component floating point vector
bvec2, bvec3, bvec4n维布尔向量 Boolean vector
ivec2, ivec3, ivec4n维整数向量 signed integer vector
mat2, mat3, mat42x2, 3x3, 4x4 浮点数矩阵 float matrix
sampler2D2D纹理 a 2D texture
samplerCube盒纹理 cube mapped texture

2.2变量限定符:

下面来讲讲变量限定符,包含attribute, varying, uniform等, 其实这些都是 GLSL 的变量限定符,一般用来声明与其宿主程序沟通的接口,什么意思呢。 假设在 WebGL 环境中, GLSL 的宿主程序就是 javascript, 所有数据均由 javascript 通过事先定义好的变量限定符传入 GLSL。

除了 attribute 和 varying 还有其他修饰符,具体见下表:

修饰符说明
none(默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型
const声明变量或函数的参数为只读类型
attribute只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据
uniform在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等.
varying主要负责在 vertex 和 fragment 之间传递变量

值得注意的是如果在 顶点着色器 与 片元着色器 中存在同名的 varying 变量,则其值可以由顶点着色器传递与片元着色器,如上例中都存在名为 vColor 的 varying 变量,执行 vColor=aColor 后在片元着色器中便可以取到 vColor 的值。

宿主程序(javascript)运行时, 会将四面体的顶点与颜色数据分别传给 aPosition 、 aColor。 一般来讲,给 gl_FragColor 赋值是整个着色器的最后一步工作,意为该点的最终颜色已确定。整体流程如下图所示:
运行流程

2.3 函数参数限定符

GLSL 允许自定义函数,但参数默认是以值形式(in限定符)传入的,也就是说任何变量在传入时都会被拷贝一份,若想以引用方式传参,需要增加函数参数限定符。

限定符说明
< none: default >默认使用 in 限定符
in复制到函数中在函数中可读写
out返回时从函数中复制出来 (可写不可读)
inout复制到函数中并在返回时复制出来

其中使用 inout 方式传递的参数便与其他 OOP 语言中的引用传递类似,参数可读写,函数内对参数的修改会影响到传入参数本身。

vec4 getPosition(out vec4 p)
{ 
    p = vec4(0.,0.,0.,1.);
    return v4;
}

void doubleSize(inout float size)
{
    size= size*2.0  ;
}

2.4 流控制

在语法上,GLSL 与 C 非常相似, 但多了一种特殊的控制语句 discard,它会立即跳出片元着色器,并不在向下任何语句。

for (l = 0; l < numLights; l++)
{
    if (!lightExists[l]);
        continue;
    color += light[l];
}
...

while (i < num)
{
    sum += color[i];
    i++;
}
...

do
{
    color += light[lightNum];
    lightNum--;
}while (lightNum > 0)

...

if (true)
    discard;

2.4 内置函数库

类型方法说明
通用函数T abs(T x)返回x的绝对值
通用函数T sign(T x)比较x与0的值,大于,等于,小于 分别返回 1.0 ,0.0,-1.0
通用函数T floor(T x)返回<=x的最大整数
通用函数T ceil(T x)返回>=等于x的最小整数
通用函数T fract(T x)获取x的小数部分
通用函数T mod(T x, T y)取x,y的余数
通用函数T mod(T x, float y)取x,y的余数
通用函数T min(T x, T y)取x,y的最小值
通用函数T min(T x, float y)取x,y的最小值
通用函数T max(T x, T y)取x,y的最大值
通用函数T max(T x, float y)取x,y的最大值
通用函数T clamp(T x, T minVal, T maxVal)
通用函数T clamp(T x, float minVal,float maxVal) min(max(x, minVal), maxVal),返回值被限定在 minVal,maxVal之间
通用函数T mix(T x, T y, T a)取x,y的线性混合,x*(1-a)+y*a
通用函数T mix(T x, T y, float a)取x,y的线性混合,x*(1-a)+y*a
通用函数T step(T edge, T x)如果 x<edge 返回 0.0 否则返回1.0
通用函数T step(float edge, T x)如果 x<edge 返回 0.0 否则返回1.0
通用函数T smoothstep(T edge0, T edge1, T x)如果xedge1返回1.0, 否则返回Hermite插值
通用函数T smoothstep(float edge0,float edge1, T x)如果xedge1返回1.0, 否则返回Hermite插值
角度&三角函数T radians(T degrees)角度转弧度
角度&三角函数T degrees(T radians)弧度转角度
角度&三角函数T sin(T angle)正弦函数,角度是弧度
角度&三角函数T cos(T angle)余弦函数,角度是弧度
角度&三角函数T tan(T angle)正切函数,角度是弧度
角度&三角函数T asin(T x)反正弦函数,返回值是弧度
角度&三角函数T acos(T x)反余弦函数,返回值是弧度
角度&三角函数T atan(T y, T x)反正切函数,返回值是弧度
角度&三角函数T atan(T y_over_x)反正切函数,返回值是弧度
指数函数T pow(T x, T y)返回x的y次幂 xy
指数函数T exp(T x)返回x的自然指数幂 ex
指数函数T log(T x)返回x的自然对数 ln
指数函数T exp2(T x)返回2的x次幂 2x
指数函数T log2(T x)返回2为底的对数 log2
指数函数T sqrt(T x)开根号 √x
指数函数T inversesqrt(T x)先开根号,在取倒数,就是 1/√x
几何函数float length(T x)返回矢量x的长度
几何函数float distance(T p0, T p1)返回p0 p1两点的距离
几何函数float dot(T x, T y)返回x y的点积
几何函数vec3 cross(vec3 x, vec3 y)返回x y的叉积
几何函数T normalize(T x)对x进行归一化,保持向量方向不变但长度变为1
几何函数T faceforward(T N, T I, T Nref)根据 矢量 N 与Nref 调整法向量
几何函数T reflect(T I, T N)返回 I - 2 * dot(N,I) * N, 结果是入射矢量 I 关于法向量N的 镜面反射矢量
几何函数T refract(T I, T N, float eta)返回入射矢量I关于法向量N的折射矢量,折射率为eta
矩阵函数mat matrixCompMult(mat x, mat y)将矩阵 x 和 y的元素逐分量相乘
向量函数bvec lessThan(T x, T y)逐分量比较x < y,将结果写入bvec对应位置
向量函数bvec lessThanEqual(T x, T y)逐分量比较 x <= y,将结果写入bvec对应位置
向量函数bvec greaterThan(T x, T y)逐分量比较 x > y,将结果写入bvec对应位置
向量函数bvec greaterThanEqual(T x, T y)逐分量比较 x >= y,将结果写入bvec对应位置
向量函数bvec equal(T x, T y)逐分量比较 x == y,将结果写入bvec对应位置
向量函数bvec equal(bvec x, bvec y)逐分量比较 x == y,将结果写入bvec对应位置
向量函数bvec notEqual(T x, T y)逐分量比较 x!= y,将结果写入bvec对应位置
向量函数bvec notEqual(bvec x, bvec y)逐分量比较 x!= y,将结果写入bvec对应位置
向量函数bool any(bvec x)如果x的任意一个分量是true,则结果为true
向量函数bool all(bvec x)如果x的所有分量是true,则结果为true
向量函数bvec not(bvec x)bool矢量的逐分量取反
纹理查询函数vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod)从sampler中提取指定坐标的颜色信息,只在vertex shader中可使用
纹理查询函数vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod)从sampler中提取指定坐标的颜色信息,只在vertex shader中可使用
纹理查询函数vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod)从sampler中提取指定坐标的颜色信息,只在vertex shader中可使用
纹理查询函数vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod)从sampler中提取指定坐标的颜色信息,只在vertex shader中可使用
纹理查询函数vec4 texture2D(sampler2D sampler, vec2 coord, float bias)第一个参数代表图片纹理,第二个参数代表纹理坐标点,通过GLSL的内建函数texture2D来获取对应位置纹理的颜色RGBA值,从sampler中提取指定坐标的颜色信息,只在fragment shader中可用
纹理查询函数vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias)从sampler中提取指定坐标的颜色信息,只在fragment shader中可用
纹理查询函数vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias)从sampler中提取指定坐标的颜色信息,只在fragment shader中可用
纹理查询函数vec4 textureCube(samplerCube sampler, vec3 coord, float bias)从sampler中提取指定坐标的颜色信息,只在fragment shader中可用
纹理查询函数vec4 texture2D(sampler2D sampler, vec2 coord)第一个参数代表图片纹理,第二个参数代表纹理坐标点,通过GLSL的内建函数texture2D来获取对应位置纹理的颜色RGBA值,在vertex shader与fragment shader中都可用
纹理查询函数vec4 texture2DProj(sampler2D sampler, vec3 coord)从sampler中提取指定坐标的颜色信息,在vertex shader与fragment shader中都可用
纹理查询函数vec4 texture2DProj(sampler2D sampler, vec4 coord)从sampler中提取指定坐标的颜色信息,在vertex shader与fragment shader中都可用
纹理查询函数vec4 textureCube(samplerCube sampler, vec3 coord)从sampler中提取指定坐标的颜色信息,在vertex shader与fragment shader中都可用

3. GLSL 示例程序

我们来看一个超简单的顶点着色器实例:

attribute vec3 aPosition;
attribute vec3 aColor;
varying vec4 vColor;
void main(void) 
{
    vColor = aColor;
    gl_Position = aPosition;
}

一个简单的片元着色器实例

varying vec4 vColor;
void main(void)
{
    gl_FragColor = vColor;
}

上例着色器中,gl_Position 、 gl_FragColor 等这些以 gl_ 开头的变量都是内置变量,通过给这些特殊的变量赋值,可以完成与硬件的通讯。其中 gl_Position 用于放置顶点坐标信息,gl_FragColor 用于设置当前片段的颜色。

参考:
博客文章: http://www.twinklingstar.cn/category/opengl/
博客文章: https://www.wangshaoxing.com/blog/2018-11-06-shader-lession-1.html
shader 赏析库: https://www.shadertoy.com/
着色器语言 GLSL 入门大全: https://github.com/wshxbqq/GLSL-Card

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值