当前位置:   article > 正文

GLSL——常用内建函数与应用_glsl 内置函数 smoothstep

glsl 内置函数 smoothstep

GLSL——常用内建函数与应用

STEP函数

step(a, b);当b > a时, 返回1;当b < a时,返回0。
函数原型

float step(float a, float x)
{
    if (a < x)
    {
        return x;
    }
    else
    {
        return a;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

应用
对控件着色时,x坐标小于0.5时,使用黑色渲染;x坐标大于0.5时,使用红色渲染。
代码段

varying mediump vec2 texCoord0;
 
void main()
{
	precision mediump float;
	float color = 0.;
//  使用step函数原型实现
//	if (texCoord0.x > 0.5)
//	{
//		color = 1.;
//	}
//	else
//	{
//		color = 0.;
//	}
 
    //使用step函数实现
	color = step(0.5, texCoord0.x);
    gl_FragColor = vec4(vec3(color, 0., 0.), 1.);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

效果
在这里插入图片描述

MIX

mix(colorA, colorB, weight); 两种颜色混合渲染,weight为colorB的渲染权重,1-weight为colorA的渲染权重,应用于颜色混合叠加效果。
函数原型

vec4 mix(vec4 colorA, vec4 colorB, float a)
{
    return x * (1 - a) + y * a;
}
  • 1
  • 2
  • 3
  • 4

应用
将黑色和红色进行混合,黑色权重按x坐标增加
代码段

varying mediump vec2 texCoord0;
 
void main()
{
	precision mediump float;
	vec4 colorRed = vec4(1.0, 0., 0., 1.);
	vec4 colorBlack = vec4(0., 0., 0., 1.);
 
    //使用mix原型实现
    //gl_FragColor = colorRed * (1 - texCoord0.x) + colorBlack * texCoord0.x;
    
    //使用mix函数实现		
    gl_FragColor = mix(colorRed, colorBlack, texCoord0.x);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

效果
在这里插入图片描述

CLAMP

clamp(x, min, max);当x大于max时,返回max, 当x小于min时,返回min,当x介于min和max之间时,返回x本身
函数原型

float clamp(float x, float min, float max)
{
    if (min > x)
    {
        return min;
    }
    else if (min < x && max > x)
    {
        return x;
    }
    else
    {
        return max;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

应用
当x小于0.4时,使用红色通道值为0.4渲染,当x大于0.8时,使用红色通道值为0.8进行渲染,在0.4和 0.8之间进行红色通道由0.4到0.8渐变
代码段

varying mediump vec2 texCoord0;
 
void main()
{
	precision mediump float;
	float color = 0.;
    //使用if条件判断实现
//    if (texCoord0.x < 0.4)
//    {
//        color = 0.4;
//    }
//    else if (0.4 < texCoord0.x && texCoord0.x < 0.8)
//    {
//        color = texCoord0.x;    
//    }
//    else
//    {
//        color = 0.8;
//    }
 
    //使用clamp实现
	color = clamp(texCoord0.x, 0.4, 0.8);
		
    gl_FragColor = vec4(vec3(color, 0., 0.), 1.);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

效果
在这里插入图片描述

LENGTH

length(a); 返回向量a的长度

length(float a);
length(vec2 vec);
length(vec3 vec);
length(vec4 vec);
  • 1
  • 2
  • 3
  • 4

应用
画一个圆,圆心坐标center(0.5, 0.5),半径radio为0.5,背景为黑色,圆红色。当任意一点到圆心的距离小于半径时,画圆,使用length计算点到圆心的距离
代码段

varying mediump vec2 texCoord0;
 
void main()
{
	precision mediump float;
	//圆的颜色
	vec4 colorCircle = vec4(1.0, 0., 0., 1.);
	//背景色
	vec4 colorBg = vec4(0., 0., 0., 1.);
	//圆心
	vec2 center = vec2(0.5, 0.5);
	//半径
	float radio = 0.5;
	
	//使用length计算任意点到圆心的距离
	float d = length(texCoord0 - center);
	if (d < radio)
	{
	    gl_FragColor = colorCircle;
	}
	else
	{
	    gl_FragColor = colorBg;
	}  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

效果
在这里插入图片描述

DISTANCE

distance(a, b);返回a和b之间的距离,即 d = sqrt(a * a + b * b) ;

应用
在上图使用了length函数计算任意点到圆心的距离,也可以使用distance函数来计算任意点到圆心的距离
代码段

varying mediump vec2 texCoord0;
 
void main()
{
	precision mediump float;
	//圆的颜色
	vec4 colorCircle = vec4(1.0, 0., 0., 1.);
	//背景色
	vec4 colorBg = vec4(0., 0., 0., 1.);
	//圆心
	vec2 center = vec2(0.5, 0.5);
	//半径
	float radio = 0.5;
	
	//任意点掉圆心的距离
	float d = distance(texCoord0, center);
	if (d < radio)
	{
	    gl_FragColor = colorCircle;
	}
	else
	{
	    gl_FragColor = colorBg;
	}  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

效果和length一样

SMOOTHSTEP

smoothstep(edg0, edg1, x); edg0左边缘,edg1右边缘,使x在edg0和edg1区间内进行平滑处理。返回值在[0, 1]区间内,当x > edg1时,返回1,当x < edg0时,返回0,当x在edg0和edg1之间时,返回x
函数原型

float smoothstep(float edg0, float edg1, float x)
{
    //对x进行归一化处理
    float t = clamp((x - edg0) / (edg1 - edg0), 0., 1.);
    //对归一化处理后的结果进行平滑处理
    return (3 - 2 * x) * x * x;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

应用

在上面用length函数和distance画了个圆,但是画的圆边缘有锯齿,是圆看起来比较生硬,那么如何让圆的边缘更圆滑呢?使用smoothstep函数就是个很好的处理方法,核心是给圆的边缘预留一定的区间,在此区间内进行边缘和边缘的外界颜色、透明度的渐变。在上面画的圆中,圆的半径是radio,那么可以给定一个区间radio - blur或radio + blur,在此区间内进行颜色、透明度的渐变处理
代码段

varying mediump vec2 texCoord0;
 
void main()
{
    precision mediump float;
    //圆心
    vec2 center = vec2(0.5, 0.5);
    //半径
    float radio = 0.5;
    //定义边缘区间
    float blur = 0.025;
    
    //计算任意点到圆心的距离
    float d = distance(texCoord0, center);
    //对d进行平滑处理,当d大于radio时,返回1,当d小于radio-blur时,返回0,
    //当d在radio-blur和radio之间时,进行模糊化平滑处理
    //因为我们要画的圆石红色,背景是黑色,所以要加上1.-
    float d1 = 1.-smoothstep(radio - blur, radio, d);
    //gl_FragColor = mix(colorBg, colorCircle, d1);  
    gl_FragColor = vec4(vec3(d1, 0., 0.), 1.);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

效果
在这里插入图片描述
可以看到,圆的边缘已经没有锯齿效果了,可以通过blur值来调整平滑程度
如果用两个smoothstep函数相减会得到什么效果呢?
代码段

varying mediump vec2 texCoord0;
 
void main()
{
    precision mediump float;
    //横坐标乘以纵横比写在vertexshader中
//    texCoord0.x *= (200.0/100.0);
    //圆心
    vec2 center = vec2(0.5, 0.5);
    //半径
    float radio = 0.5;
    float radio1 = 0.4;
    //定义边缘区间
    float blur = 0.025;
    
    //计算任意点到圆心的距离
    float d = distance(texCoord0, center);
    //对d进行平滑处理,当d大于radio时,返回1,当d小于radio-blur时,返回0,
    //当d在radio-blur和radio之间时,进行模糊化平滑处理
    //因为我们要画的圆石红色,背景是黑色,所以要加上1.-
    float d1 = (1.-smoothstep(radio - blur, radio, d)) - (1. - smoothstep(radio1 - blur, radio1, d));
    //gl_FragColor = mix(colorBg, colorCircle, d1);  
    gl_FragColor = vec4(vec3(d1, 0., 0.), 1.);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

效果图
在这里插入图片描述
那么,想乘呢?
代码段

varying mediump vec2 texCoord0;
 
void main()
{
    precision mediump float;
    //横坐标乘以纵横比写在vertexshader中
//    texCoord0.x *= (200.0/100.0);
    //圆心
    vec2 center = vec2(0.5, 0.5);
    //半径
    float radio = 0.5;
    float radio1 = 0.4;
    //定义边缘区间
    float blur = 0.025;
    
    //计算任意点到圆心的距离
    float d = distance(texCoord0, center);
    //对d进行平滑处理,当d大于radio时,返回1,当d小于radio-blur时,返回0,
    //当d在radio-blur和radio之间时,进行模糊化平滑处理
    //因为我们要画的圆石红色,背景是黑色,所以要加上1.-
    float d1 = (1.-smoothstep(radio - blur, radio, d)) * (1. - smoothstep(radio1 - blur, radio1, d));
    //gl_FragColor = mix(colorBg, colorCircle, d1);  
    gl_FragColor = vec4(vec3(d1, 0., 0.), 1.);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

效果图
在这里插入图片描述
通过上述效果可以看到,两个smoothstep相减,可以获得除去作为减数smoothstep以外图案,相乘可以得到除去被减数smoothstep以外的部分

LERP

lerp(a, b, x);当x=0时,返回a,当x=1时,返回b,否则返回a和b的差值
函数原型

float lerp (float a, floatb, float x)
{
    a + x * (b - a);
}
  • 1
  • 2
  • 3
  • 4

应用
当x越接近0时,返回值月接近a,当x越接近1时,返回值越接近b,通过这一特性,可用来做一些渐变的效果,比如,从坐标中心向四周渐变的效果
代码段

varying mediump vec2 texCoord0;
 
void main()
{
    precision mediump float;
    vec4 colorBlack = vec4(0., 0., 0., 1.);
    //有中间向两边渐变成黑色
    gl_FragColor = lerp(0., 1., length(texCoord0 - 0.5)) * colorBlack;  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

效果图
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/574152
推荐阅读
相关标签
  

闽ICP备14008679号