造型函数(续)

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

任意函数曲线的绘制

虽然上篇的例子很简单,但是其实我已经讲了一种绘制任意曲线(直线是特殊的曲线)的方法。

float line3 ( vec2 st , float w, float k, float b){
                return smoothstep(.0,w,  st.y - st.x*k - b   ) - smoothstep(w, 2. * w ,st.y - st.x*k - b );  // step(a,b) 就是 a>b? 1: 0 ;
}   
复制代码

只要把 y = kx +b 换成你想画的函数曲线,就可以画出对应的形状,其原理昨天也说了,就是判断点是否在图形内。 比如, 我们要画函数y=f(x) 的形状, 只需要判断点是否在 y= f(x) -w 和 y = f(x) +w之间,当然我这个宽度是有点问题的,按我这个画法宽度应该是2w左右。

为了便于观察,我把坐标原点移动到中心,以后都会这么干。

float lineSin ( float x ,float y , float w){ // 由于x 和y 在[-0.5,0.5] 之间,所以需要处理一下
                return smoothstep(.0,w, y*2.1 - sin(x*7.0)   ) - smoothstep(w, 2.1 * w , y*2. - sin(x*7.)  );  // step(a,b) 就是 a>b? 1: 0 ;
}   
float lineCos ( float x ,float y , float w){ // 由于x 和y 在[-0.5,0.5] 之间,所以需要处理一下
            //     return smoothstep(.0,w, y*2.1 - cos(x*7.0)   ) - smoothstep(w, 2.1 * w , y*2. - cos(x*7.)  );  // step(a,b) 就是 a>b? 1: 0 ;
                return smoothstep(w,0., abs(y*2.1 - cos(x*7.0))   ) ;  
}  

float lineTan ( float x ,float y , float w){ // 由∂于x 和y 在[-0.5,0.5] 之间,所以需要处理一下
                return smoothstep(w,0., abs(y*1000. - tan(x*3.0))   ) ;  
}
float lineCircle ( float x ,float y , float w , float r  ){ // 圆还用这种方式显然不太和适 直接用平方的结果不开方,开方的成本较高
                return smoothstep(w,0., abs(y*y + x*x - r*r  ) );  
}

float lineOval ( float x ,float y , float w , float r1 ,float r2  ){ // 圆还用这种方式显然不太和适 直接用平方的结果不开方,开方的成本较高
                return smoothstep(w,0., abs(y*y/r1 + x*x/r2 -1.  ) );  
}

复制代码

image.png 我直接把全部坐标都减(0.5,0.5) 就完成了坐标系转换,关于坐标转换有疑问的,建议使用特殊值法,例如以前的中心点是(.5,.5) ,转换后它应该是(0,0),由此我们得出应该把原坐标减去0.5,而这个规则是通用的,因为这里只有平移。

再来看,这幅图,椭圆是在最上面的,因为我们最后画椭圆,所以它会覆盖其他的曲线。

再看,正弦曲线,并不完全都是红色,这是因为用了另一种使用smoothstep的方法,下面就来好好说道一下这个函数

image.png

关于smoothstep

我们可以先看一下文档说明, 在两个值之间执行埃尔米特插值,下面说明了参数类型

image.png

具体规则就是,计算这么一个值 t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);

简单的说就是,

如果 x 位于区间[edge0,edge1] 内,那么返回(x - edge0) / (edge1 - edge0) ,

如果 x < edge0 那么返回 0

如果 x > edge1 那么返回 1

image.png

用法

之前就说了,所有的计算都是为了得到 0 1之间。 有人可能注意到,之前的函数里 edge0 < edge1,这是完全可行的, 这样的话,越界的返回值刚好就能反过来, 大于右边界返回0 ,小于左边界返回1。

再来看第一种使用方法。 我把 y-x的绝对值限制在了 (.02 ,0)之间,为什么这里要把边界参数倒过来,因为绝对值肯定是很大一部分大于.02的,这样画的话,大于的那部分肯定都是一个色了,就会看到一片,我希望大于.02的全部为0,所以倒过来,而小于0 的部分绝对值帮我处理了。 所以,最后你看见了一条线

第二种用法, 就是两个smoothstep相减。

关于那个线条颜色不太对,其实是我函数写错了。

两个smoothstep 的差别就是区间不同,区间发生了偏移,显然这会导致最后返回值也发生偏移,错位相减。

比如说原本的区间是[l, r] ,偏移后的区间是[l+f, r+f]

那么小于 l 的结果都是0,大于r +f的结果都是1 ,相减肯定是0 ,就只有 [l,r+f]之内的返回值是大于0的

return  smoothstep(0.02,0.0, abs(st.y -st.x)) 
return smoothstep(.0,w, y*2.1 - sin(x*7.0)   ) - smoothstep(w, 2. * w , y*2.1 - sin(x*7.)  ); 
复制代码

再回过来看书

第一个例子,画了一个渐变的背景,它直接把颜色和x值关联在一起就实现了这个渐变,

还画了一条斜线, 这个pct就是造型函数的返回值,01之间, 然后和背景色mix. 就是这么简单,造型函数采用了第一种绝对值的用法。

第二个例子,就是把造型函数的曲线函数换了,smoothstep的用法换了第二种。背景色渐变的函数也换了指数函数。

step 和 smoothstep

step是01突变,smoothstep多了01之间的过渡,这两张图非常好,我就直接拿来了,从背景色上的变化可以很直观的感受到两个函数的差异,我就不啰嗦了。

float y = step(0.5,st.x);
    // Smooth interpolation between 0.1 and 0.9
 float y = smoothstep(0.1,0.9,st.x);
复制代码

image.png
image.png

这一章后面的部分本人也就看了个大概,学的不怎么样,就到此为止了。

猜你喜欢

转载自juejin.im/post/7128712549796675591