
接下来我选择4个作品逐步完成上述图片,在processing上写,并做出一些代码优化。
难度一:

原理很简单,追踪鼠标坐标画圆就是了。
void draw1(){
if(mousePressed) {
strokeWeight( 3 );
circle( mouseX, mouseY, size );
}
}
难度二:根据速度改变圆的大小

定义圆的大小与速度成反比
v += sqrt( Veloc.x*Veloc.x + Veloc.y*Veloc.y ) - v; // ADD
v *= 0.6;
float r = size - v; // ADD
定义画笔速度同当前帧与上一帧的位置差成正比
Veloc.x += ( mouseX - Pos.x ) * spring;
Veloc.y += ( mouseY - Pos.y ) * spring;
Veloc.x *= friction;
Veloc.y *= friction;
代码中spring参数与friction参数分别模拟了笔刷的惯性与摩擦力,但是效果不怎么理想,两个参数效果的区别不明显,都是值小了画笔运动慢,值大了画笔运动快。。。可能是我太顿感了吧,看不出区别。
下图中上方的笔迹是摩檫力较大的时候,下方笔记是较小的时候,可以看出画圆的数量不同

难度三:模拟毛笔刷,实现连贯
最初看例子的时候玩到这里就一直很好奇要如何让圆连续地生成,这么想是因为看到前面画圆的Demo里,当鼠标运动慢时,多个圆彼此重叠,就很有毛笔笔迹的效果,所以猜测后面的笔迹应当让圆生成地更连贯,类似于插值操作,但怎么做呢?
答案是:直接画线就行了,那么麻烦干什么![/黑脸]
当然,插值还是要做的,主要的工作是平滑笔刷的大小变化,让两帧的笔刷大小有一定数量的过渡值,代码如下:
for( int i = 0; i < splitNum; ++i ) { // ADD
oldX = Pos.x;
oldY = Pos.y;
Pos.x += Veloc.x/splitNum; // AMEND: vx -> vx/splitNum
Pos.y += Veloc.y/splitNum; // AMEND: vy -> vy/splitNum
oldR += (r-oldR)/splitNum; // ADD
if(oldR < 1) { oldR = 1; } // AMEND: r -> oldR
strokeWeight( oldR ); // AMEND: r -> oldR
line( Pos.x, Pos.y, oldX, oldY );
} // ADD

但这个画笔的变化也不是那么平滑。。
难度四:模拟笔刷分叉
这个是当时看起来最炫酷的效果,但了解后,原理很简单,只要细心观察一下分叉部分线的数量,都是三。。。。
那就很简单了,将上面画线的函数复制两个,定义一个位移变量,令该变量同速度成正比,也就是说当速度小时,位移小,三条线混合在一起,当速度增大,位移增大,三条线分离开就有分叉的效果辽
for( int i = 0; i < splitNum; ++i ) { // ADD
oldX = Pos.x;
oldY = Pos.y;
Pos.x += Veloc.x/splitNum; // AMEND: vx -> vx/splitNum
Pos.y += Veloc.y/splitNum; // AMEND: vy -> vy/splitNum
oldR += (r-oldR)/splitNum; // ADD
if(oldR < 1) { oldR = 1; } // AMEND: r -> oldR
strokeWeight( oldR+diff ); // AMEND: r -> oldR
line( Pos.x, Pos.y, oldX, oldY );
strokeWeight( oldR ); // ADD
line( Pos.x+diff*2, Pos.y+diff*2, oldX+diff*2, oldY+diff*2 ); // ADD
line( Pos.x-diff, Pos.y-diff, oldX-diff, oldY-diff );
} // ADD
效果如下:

至此目标达成,但还有一些问题:
1.笔刷不够平滑,三条分叉也太僵硬了点
2.代码也不够简洁
有时间再优化吧。。。好累,作业好多。。
网友评论