文章目录
- 相关网址
- 前言
- 基本实现画一个圆步骤
- 1.初步-根据长度绘画圆
- 2.初步-根据1-length(uv)绘画圆
- 3.正式-绘画白色形状的圆
- (1)if逻辑代码实现
- (2)用shader的step函数
 
 
- 完善圆-实现绘画手环圆
- 1.if逻辑代码实现
- 2.用step函数代替if
 
- 用smoothstep代替step函数
- 1.smoothstep函数
- 2.使用smoothstep
- 3.完善shader代码
 
- 用smoothstep的小Bug
- 1.Bug说明
- 2.解决方法
- 方法一
- 方法二
 
 
- 测试smoothstep(edg0, edg1, distance)
相关网址
Cherno原视频网址:https://www.youtube.com/watch?v=xf7Y988cPRk
shader网站:https://www.shadertoy.com/
GLSL函数解释网址:https://docs.gl/
此文是记录对第一个网址学习的笔记和思考的过程。
鄙人作为shader初学者,文中应该会有错误,欢迎指正。
前言
-  基本思路 用Quad顶点包围一个范围作为画布(Canvas)用glsl控制画出一个圆内alpha为1,圆外的范围的alpha为0。 
  
-  如何控制在圆内的alpha为1,圆外的alpha为0 用当前坐标点距离原点的长度、step函数来控制 
基本实现画一个圆步骤
1.初步-根据长度绘画圆
- shader和效果图

-  说明 -  uv相当于在xy坐标系的坐标,xy坐标系的原点在中心 
-  length(uv) = sqrt(u*u+v*v) 即长度 
-  原点的坐标是(0, 0),distance是0,所以是黑色 假设x点(0, 0.5), distance是0.5,所以是灰色 
 所以形成 - 靠近原点的颜色是黑色
- 远离原点的颜色是灰色
 
-  
2.初步-根据1-length(uv)绘画圆
-  shader+效果图 
  
-  说明 distance= 1-length(uv); 原点的坐标是(0, 0),length(uv)是0,被1减去后,是白色1 假设边缘点x(0, 1), length(uv)是1,被1减去后,是黑色0 所以形成翻转颜色的效果 -  原先靠近圆心是黑色0,远离圆心逐渐递增到白色1 
-  现在靠近圆心是白色1,远离圆心逐渐递减到黑色0 
 
-  
3.正式-绘画白色形状的圆
(1)if逻辑代码实现
- shader代码+效果图

-  说明 if(distance > 0.0){ distance = 1.0; }表示原先大于0.0的颜色都白色,即灰色都是白色 
(2)用shader的step函数
- shader代码+效果图

-  说明 step(edge0, x); x<edge0 返回0,x>edge0 返回1 step函数作用同 if(distance > 0.0){ distance = 1.0; }step(0, x);函数图像  
 从线性变成阶梯型
完善圆-实现绘画手环圆
1.if逻辑代码实现
- shader+效果

-  说明 -  原本靠近圆心的distance为1,颜色为白色1,远离圆心的distance逐渐从1降为0,颜色从白色1到黑色0。 但经历下面代码后成上图所示 if(distance > 0.1){ col = vec3(0.0); }
-  被白色包围的黑色范围形成说明 以圆心为出发点,length(uv)在(0, 0.9)范围内的distance为(1, 0.1),满足if条件,使颜色为黑色0。 
-  白色范围 以圆心为出发点,length(uv)在(0.9, 1)范围内的distance为(0.1, 0),不满足if条件,使颜色依旧是白色0。 
-  白色外面的黑色范围形成说明 以圆心为出发点,length(uv)在(1, 1.1)范围内的distance为(0, -0.1),虽然不满足if条件不受第13行if代码块的影响,但是受第12行代码step函数的影响,早已为黑色。 
 所以白色范围length为(0.9, 1) 
-  
2.用step函数代替if
- shader+效果

-  说明 -  col *= vec3(1.0 - step(0.02, distance))的作用相当于 if(distance > 0.1){ col = vec3(0.0); }
-  设第13行*以的中间值c2如下 c2 = vec3(1 - step(0.02, distance));// step(0.02, distance)使得大于0.02的为1,小于0.02的为0
-  c2的值 以圆心为出发点,length(uv)在(0, 0.98)范围内的distance为(1, 0.02),step(0.02, distance)后为1,被1减去后,为黑色0 以圆心为出发点,length(uv)在(0.98, 1)范围内的distance为(0.02, 0),step(0.02, distance)后为0,被1减去后,为白色1 
-  col的值-第11行的代码,并执行第13行的*代码 vec3 col = vec3(step(0.0, distance)); col *= c2;以圆心为出发点,length(uv)在(0, 0.98)范围内的distance为(1, 0.02)的col是白色1,与上述同范围的c2黑色0相乘为0黑色。 以圆心为出发点,length(uv)在(0.98, 1)范围内的distance为(0.02, 0)的col是白色1,与上述同范围的c2白色1相乘为1白色。 
 所以白色的范围length是(0.98, 1),所以很小 
-  
用smoothstep代替step函数
1.smoothstep函数
-  说明 https://docs.gl/sl4/smoothstep // 当edge0 < edge1时,当x < edg0时,返回0,当x > edg1时,返回1,当x在edg0和edg1之间时,返回x。 // 当edge1 < edge0时,当x < edg1时,返回1,当x > edg0时,返回0,当x在edg0和edg1之间时,返回x。这个有点难理解,是我在下面情况测试出来的,没有官方说明,也许不对 // 当edge0 = edge1 ,smoothstep退化成step(0除外) smoothstep(edge0, edge1, x);等同于 genType t; t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); return (3.0 - 2.0 * t) * t * t;自己测试smoothstep的结论,测试过程在后面 // 当edge1 < edge0时,当x < edg1时,返回1,当x > edg0时,返回0,当x在edg0和edg1之间时,返回x。 // 当edge0 = edge1 ,smoothstep退化成step // 但当edge0=edge1=0,smoothstep(edge0,edge1,x);无论x是什么都返回0! smoothstep(edge0, edge1, x);
-  表示的阶梯型函数图形  如图所示,在e0 e1范围更平滑,不像step那么突兀 
2.使用smoothstep
-  代替后的shader代码+效果图  // 其中fade = 0.005,即smoothstep的第二个参数 第16行替换成smoothstep函数是给外圈边缘平滑过渡的 第17行替换成smoothstep函数是给内圈边缘平滑过渡的 
3.完善shader代码
-  当前代码的不足 由于之前第17行代码有点冗余,所以可以简短一点,写完如下,效果依旧保持良好不变  即 vec3(smoothstep(thickness, thickness - fade, distance)); 等价于 vec3(1.0 - smoothstep(thickness - fade, thickness, distance));
-  第17行代码说明 -  简要说明 原先是递增,改后是递减 
-  翻转图示   原先小于0.095为0,大于0.1是1=>现变成小于0.095为1,大于0.1为0 
-  结合代码和效果图具体说明 - 原先的效果-递增
 c2 = vec3(1 - smoothstep(0.1 - 0.005, 0.1, distance)); // distance < 0.095 为0,distance > 0.1为1 c2 = vec3(1 - smoothstep(0.095, 0.1, distance));length(uv)在(0, 0.9)范围内的distance为(1, 0.1),smoothstep后为1,被1减去后,为黑色0 length(uv)在(0.9, 0.905)范围内的distance为(0.1, 0.095),smoothstep后为不变,被1减去后,为平缓的白色(0.9, 0.905)之间 length(uv)在(0.905, 1)范围内的distance为(0.095, 0),smoothstep后为0,被1减去后,为白色1 - 改后的效果-递减
 说明当edge0 > edge1时函数的意义发生变化,这个变化上面介绍smoothstep时也说了,只不过并没有官方说明,也没问过人,不知是否正确,如有错,欢迎指正。 c2 = vec3(smoothstep(0.1, 0.1 - 0.005, distance)) // distance < 0.095 为1,distance > 0.1为0, c2 = vec3(smoothstep(0.1, 0.095, distance))length(uv)在(0, 0.9)范围内的distance为(1, 0.1),>0.1,smoothstep后为黑色0 length(uv)在(0.9, 0.905)范围内的distance为(0.1, 0.095),smoothstep后为不变,被1减去后,为平缓的白色(0.9, 0.905)之间 length(uv)在(0.905, 1)范围内的distance为(0.095, 0),<0.095,smoothstep后为白色1 所以结果不变。 
 
-  
-  验证: 这段有点不好说明,可以跳过,是用OpenGL的glsl测试smoothstep函数 -  glsl关键代码 .... // fragment阶段 void main() { float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离 float circle = smoothstep(0.5, Input.Fade, distance); o_Color = vec4(circle, circle, circle, 1); }可见,Input.Fade是变量,可以调节它是否小于0.5还是大于0.5,来验证上述是否正确 
-  当Fade=0.51大于0.5时  float circle = smoothstep(0.5, 0.51, distance); -  圆内白色: distance在(1, 0.51)范围,>(大于)0.51,smoothstep后circle是白色1。 
-  圆外黑色: distance在(0.5, 0)范围,<(小于)0.5,smoothstep后circle是黑色0。 
 
-  
-  当Fade=0.483小于0.5时  float circle = smoothstep(0.5, 0.483, distance); -  圆内黑色: distance在(1, 0.5)范围,>(大于)0.5,smoothstep后circle是黑色0。 
-  圆外白色: distance在(0.483, 0)范围,<(小于)0.483,smoothstep后circle是白色1。 
 
-  
 
-  
用smoothstep的小Bug
1.Bug说明
-  当thickness=1时,会导致中间有一个很小很小的黑色洞  
-  解释——待实际验证 由smoothstep的减法导致的 // distance < 0.995 为1,distance > 1为0 c2 = vec3(smoothstep(1, 0.995, distance))注意:由图像所示,不止>1,接近1的位置也是0  length(uv)在(0, 0.002)范围内的distance为(1, 0.998),在(0.995,1)之间,但是0.998靠近1,smoothstep后为接近黑色0,所以原点呈现黑色。 tips:这是我自己猜的,有待验证和询问别人,还是那句话,欢迎指正。 
2.解决方法
方法一
初始化thickness += fade,可以解决洞的问题

-  解释——待实际验证 // distance < 1 为1,distance > 1.005为0 c2 = vec3(smoothstep(1.005, 1, distance))length(uv)在(0, 0.002)范围内的distance为(1, 0.998),不在(1.005,1)之间,而是<1,smoothstep后为白色1。 tips:欢迎指正 
方法二
推荐,代码更好看吧
-  解决方式 将thickness+fade代码写入smoothstep中  
-  解释——同上 // distance < 1 为1,distance > 1.005为0 c2 = vec3(smoothstep(1.005, 1, distance))length(uv)在(0, 0.002)范围内的distance为(1, 0.998),不在(1.005,1)之间,而是<1,smoothstep后为白色1。 tips:如有错,欢迎指正 
-  新问题 会有新问题,即thickness=0时,fade=0.005时,有个0.005的厚度薄圆轮廓(如上两个箭头所指) 
-  解决方法 这问题迫不得已,cherno没说解决方案。 我自己测试,当thickness=0时,只需调整fade为0就不会有薄圆了 
-  说明为何有效 1.先说薄圆轮廓产生原因 设fade= 0.1, thickness = 0 float distance = 1.0 - length(uv); vec3 col = vec3(smoothstep(0, 0.1, distance)); // distance < 0 为1,distance > 0.1为0 col *= vec3(smoothstep(0.1, 0, distance));-  uv为圆内黑色范围的点 length(uv)在(0, 0.9)范围 1.distance > 0.1 2.col = 1 3.col = 1 * 0 = 0;// * 0因为distance > 0.1为0所以呈现黑色 
-  uv为圆上薄圆轮廓范围的点 length(uv)在(0.9, 1)范围 1.0 < distance < 0.1 2.0 < col < 0.1 3.col = (0,0.1) * (0, 0.1) = (0, 1);所以呈现薄圆 
 2.将fade=0时,薄圆消失 设fade= 0, thickness = 0 float distance = 1.0 - length(uv); vec3 col = vec3(smoothstep(0, 0, distance)); col *= vec3(smoothstep(0, 0, distance));不管distance是多少,smoothstep(0, 0, distance)返回0,所以col是黑色,与背景融合在一起,所以轮廓消失。 
-  
测试smoothstep(edg0, edg1, distance)
-  edge0=edge1=0 void main()// 部分glsl的fragment代码 { float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离 float circle = smoothstep(0, 0, distance); o_Color = vec4(circle, circle, circle, 1); }结果  说明smoothstep(0, 0, distance);返回0 
-  edge0=edge1=0.2 void main()// 部分glsl的fragment代码 { float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离 float circle = smoothstep(0.2, 0.2, distance); o_Color = vec4(circle, circle, circle, 1); } 白色范围因distance>0.2所以smoothstep(0.2, 0.2, distance)返回1 黑色范围因distance<0.2所以smoothstep(0.2, 0.2, distance)返回0 
-  edge0=edge1=0.8 void main()// 部分glsl的fragment代码 { float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离 float circle = smoothstep(0.8, 0.8, distance); o_Color = vec4(circle, circle, circle, 1); } 白色范围因distance>0.8所以smoothstep(0.8, 0.8, distance)返回1 黑色范围因distance<0.8所以smoothstep(0.8, 0.8, distance)返回0 
结论
smoothstep(0, 0, distance);返回0
smoothstep(0.2, 0.2, distance);退化成step(0.2, distance);distance大于0.2返回1,小于0.2返回0
smoothstep(0.8, 0.8, distance);退化成step(0.8, distance);distance大于0.8返回1,小于0.8返回0



















