数学可视化(02)——ShaderLab内部常用函数

  1. 1. floor、ceil与frac
  2. 2. saturate、clamp、step、sign
  3. 3. lerp与smoothstep

 

floor、ceil与frac

  • 常用于数据分段
  • floor(x):返回小于或等于指定值x的最大整数值(向下取整)
  • ceil(x):返回大于或等于指定值x的最小整数值(向上取整)
  • frac(x):返回指定值的小数部分,返回大于0小于1值
  • fmod(x,y):返回指定值x/y的浮点余数,这种方法对于非整数取模更灵活,但比使用floor/ceil + frac方式开销更大一些
  • modf(x,out ip):将指定值x拆分为小数部分和整数部分,其中返回值为小数部分,参数输出为整数部分,每个部分的符号与x相同,与fmod相比它更适合处理整数和取模的方式。效率高的同时同样不如fmod用起来灵活

1
2
3
4
5
6
7
8
9
10
11
12
13
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
const int uvScale = 5;
uv.xy = uv * uvScale;

float2 uvInteger = floor(uv);
// uv的x映射到r通道
c.r = (uvInteger.x) / uvScale;
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
const int uvScale = 5;
uv.xy = uv * uvScale;

float2 uvInteger = floor(uv);
// uv的xy映射到rb通道
c.rb = (uvInteger.xy) / uvScale;
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
const int uvScale = 5;
uv.xy = uv * uvScale;

float2 uvInteger = floor(uv);
float2 uvDecimal = frac(uv);
// 用floor/ceil离散化数据 + 小数部分 还原回连续的颜色映射
c.rb = (uvInteger.xy + uvDecimal.xy) / uvScale;
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
const int uvScale = 5;
uv.xy = uv * uvScale;

float2 uvInteger = floor(uv); // 二维图案数组的索引
float2 uvDecimal = frac(uv); // 0-1区间的连续uv
// 只取小数部分,得到多个重复的连续颜色映射图案
c.rb = uvDecimal.xy;
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
12
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
const int uvScale = 5;
uv.xy = uv * uvScale;

// fmod方式按0 - 0.4区间划分处理,*2.5为了弥补颜色值差异
c.rb = fmod(uv, 0.4) * 2.5;
//
return c;
}

saturate、clamp、step、sign

  • 常用于数据值处理(数据截断)
  • saturate(x):将指定值固定在0-1的范围内
  • clamp(x,min,max):将指定值固定到指定的最大最小值范围
  • step(y,x):比较两个值,前者小于后者则返回0,否则返回1。可用于二元判断
  • sign(x):返回指定值的符号,x小于0返回-1;x等于0返回0;x大于0返回1。可用于三元判断

lerp与smoothstep

  • lerp(x,y,s):执行两个指定值的线性插值,s为插值系数
  • smoothstep(min,max,x):如果x在[min,max]范围内,则返回介于0和1之间的平滑埃尔米特插值

1
2
3
4
5
6
7
8
9
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
// 用uv的x插值红色到绿色
c = lerp(half3(1,0,0), half3(0,1,0), uv.x);
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
uv = uv * 2 - 1;
float d = sqrt(pow(uv.x, 2) + pow(uv.y, 2));
// 用smoothstep做0.4-0.5插值过渡的圆
c = smoothstep(0.4, 0.5, d);
//
return c;
}
  • 过渡部分是由外到内由白到黑的过渡部分
  • 如果用白色去减就可以变成由黑到白的过渡了

1
2
3
4
5
6
7
8
9
10
11
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
uv = uv * 2 - 1;
float d = sqrt(pow(uv.x, 2) + pow(uv.y, 2));
// 用白色减去,得到相反效果
c = 1 - smoothstep(0.4, 0.5, d);
//
return c;
}

1
2
3
4
5
6
7
8
9
10
11
half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//
uv = uv * 2 - 1;
float d = sqrt(pow(uv.x, 2) + pow(uv.y, 2));
// 用小圆减大圆 得到圆环
c = smoothstep(0.3, 0.4, d) - smoothstep(0.4, 0.5, d);
//
return c;
}