转自:http://blog.csdn.net/panda1234lee/article/details/52024465
本文参考了ShaderToy的算法,对其原理进行了简单分析,并对代码进行精简
绘制心形
先看看关键代码
[cpp]view plaincopy
floatr = length(p);
floata = atan(p.x,p.y)/3.141593;
floath = abs(a);
floatd = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h);
// Red
vec3 hcol = vec3(1.0, 0.0, 0.0);
// Draw Heart
vec3 col = mix( u_bgColor.xyz, hcol, clamp( d-r, 0., 1.));
其中,p是片元坐标x,y从[0,1]域换算到[-1,1]的vec2形式,u_bgColor是白色的背景,a的含义不用解释了,值得一提的是a的范围是[-1/2, 1/2],需要对它取绝对值,原因是a为负数的话,计算出的d也为负数,那么会被mix函数所忽略的(所以我们常常使用clamp来截断),如图(颜色越浅表示d值越小,反之亦然):
当使用了a的绝对值,计算出的d效果如图:
该算法最关键的就是计算d的函数(看起来很普通,但是别急,接下来才是鉴证奇迹的时刻),该函数图如下所示:
注意定义域只取[-1/2, 1/2]。
接着,来看r,它是坐标p距离图像中心(0,0)的半径,同样值越小越白
最后,没错!现在就是鉴证奇迹的时刻,绘制心形我们只需要将d-r即可,如图所示。
但是很明显“心”偏下了一些,所以代码中通过p.y -= 0.25,对其进行了上移矫正。
但是现在仍然存在一个问题,就是❤的颜色向外越来越淡。
作者通过smoothstep来对(d-r)进行hermite插值,函数如图所示:
顺带提一下hermite插值,代码如下:
[cpp]view plaincopy
np.clip((t - down_edge)/(up_edge - down_edge), 0.0, 1.0)
smoothstep = t * t * (3.0 - 2.0 * t)
这样就出现了我们满意的❤了!很神奇有木有!
绘制“跳动”的效果
还是来看看关键的代码
[cpp]view plaincopy
floattt = mod(fElapsedTime, 1.5)/1.5;
tt = mod(fElapsedTime, _Duration)/_Duration;
floatss = pow(tt,.2)*0.5 + 0.5;
ss = 1.0 + ss*0.5*sin(tt*6.2831*3.0 + p.y*0.5)*exp(-tt*4.0);
其中fElapsedTime是程序运行的时间,以秒为单位。通过mod运算对时间进行周期性变换。
那ss又是什么鬼呢?我们来看看ss的函数图,来点直观的感受!
它是一个逐渐衰减的效果,很神奇有木有!
最后
综上,我们就可以简单的实现一个“跳动的心”的特效了,有木有感受到“数学之美”!
网友评论