前言
第一次接触shadertoy是在一篇博客里,进入shadertoy里面以后就如同进入了一个新的世界,里面各种唯美的效果,令人叹为观止。看到了一些非常有趣的想法,而且还有非常好的实现,对于喜爱shader的同学简直是欲罢不能了。
shadertoy主要还是使用glsl来开发的,但略有不同,在知乎上看到一篇文章,里面总结了很多关于shadertoy入门和学习的资料,https://www.zhihu.com/question/22514128/answer/156052812,个人感觉冯乐乐的这篇写得很仔细,https://blog.csdn.net/candycat1992/article/details/44039077;关于自己使用时踩的一些小坑,之后也尽量记录在博客中。
一、主要内容
本章主要基于笛卡尔定理,做出一个简单的2D图形效果。
关于笛卡尔定理的主要内容,可以在搜狗百科上看------https://baike.sogou.com/v158462442.htm?fromTitle=%E7%AC%9B%E5%8D%A1%E5%B0%94%E5%AE%9A%E7%90%86
如果对公式不够理解,那么看这篇博客也许会有所帮助,https://blog.csdn.net/WuBaizhe/article/details/77429915
公式非常简单,下面就直接讲解这个shader的制作过程了。
首先要绘制一个大圆,也就是最外面的那个,这个很简单,就是通过圆心和半径来判断像素点是否在圆内,
float r = distance(uv,center);
if (r < radius) {
return r / radius;
}
return -1;
其次再分别绘制两个小圆,也就是内圆里左边和右边的两个,这个只需要注意设置圆心和半径即可。
随后便可通过笛卡尔定理,三个小圆内切于一个大圆,四个半径之间的关系公式,计算出第四个圆的半径;
使用一元二次方程的求根公式即可,但是要注意,需要判断delta>0,也就是b*b-4*a*c>0,可能读者会奇怪,按照公式以及图形来看,一定会有至少一个圆是可以满足内切条件的,为什么还要判断?那么,我们假设有这样几个圆,大圆为r1,两个小圆分别为r2,r3,如果r2+r3>r1,那么是不是就不可能有r4了,那么问题来了,我们提前设定r1为0.5,r2为0.3,r3为r1-r2不就行了吗??注意,这里即使r3=r1-r2,那么delta也不一定大于等于0,这里和浮点数的相加计算有关系,可能有细微的差距导致;所以以后如果再shader中出现一些偶现的闪动bug,可以想一想这个点。
还要注意,外面那个最大的圆,要放在最后进行判断,因为小圆的颜色是要覆盖大圆的,所以如果判断了像素点在小圆内,就不用再判断是否在大圆内了,直接返回相应的颜色值即可。
计算半径的时候,解出方程会遇到两个解,这个很容易理解,不懂的看一下上面推荐的博客里,会有相关阐述,我们要取值最小的解,比如看某一个方向,圆都是逐渐缩小的。
好,到此,半径就已经求出来了,接下来就要计算各个圆的圆心了。
其实圆心非常好计算,比如
如果圆3的坐标就通过圆1和圆2来求,这里可以根据相切圆的特点,圆1和圆3之间的距离就是r1+r3,圆2和圆3之间的距离就是r2+r3,那么圆3的圆心就可以理解为以圆1为圆心,以r1+r3为半径画圆,再以圆2为圆心,以r2+r3为半径画圆,两圆交点即为r3和r4的圆心(3和4是对称的),那么就是计算两个相交圆的交点,这个可以列出两个方程,然后通过降次消元解决。
需要注意的是,这里同样会得到两个解,如何判断自己要拿到哪个解呢,通过方向,圆3以及圆5与圆2的关系都是逆时针方向,那么我们就可以通过向量的叉乘来判断,叉乘使用的是右手法则,然后就可以分别得到所有逆时针方向的圆心坐标和顺时针方向的坐标了。
二、结语
细节就不能再多了,主要思路都在这里,实现细节大家可以看我的源码,https://github.com/zhimo1997/ShaderToy
有什么异议的可以留言交流,后续还会对效果继续进行改善,欢迎大家指教,下篇博客,再见。