简介
和上次使用静态画来比较手绘和码绘的区别不同,本次我们要用“动态”的图像来更深的体会艺术的不同表现方法和形式。
第一次实验我们仅仅通过对手绘和码绘的静态作品进行了比较,从感官上来看似乎区别不大。在这一篇博文中,我将以一个非常有名的图形作为线索,围绕它来展开论述。
创作灵感
创作的原始灵感来自于一个数学公式:
ρ=1-cosθ
what?你在逗我?
别急,来看看这个公式的曲线图案:
这个心形线是不是很眼熟,没错,就是那颗著名的“笛卡尔之心”。我觉得没什么比这个更能体现数学的和谐与美感了。
有了一颗心还不够,我们得让它“跳起来”!方法多种多样,这一次我们选择一个比较基础的,使用向量来实现。
我在此推荐3Blue1Brown的科普视频,原作者通对数学的可视化处理方法让我获益匪浅。我就是通过他的视频才认识到数学之美的,而他对于线性代数的讲解也是我灵感的重要来源。
关于向量概念的直观认识,我推荐如下视频
线性代数的本质 - 01 - 向量究竟是什么?
开始绘图!
手绘
这是手绘的概念图,实现跳跃效果的思路是把这颗心分成有限个向量,让每个向量都从很小的一个点上往外扩张,这就形成了动的效果。
画的有点简陋抽象,别介意,知道个概念就好。
码绘
我使用Processing作为绘制的工具,其语言以java为基础,可以说是非常亲民了。
首先,我们用向量来绘制一个静态的笛卡尔之心。向量集的初始化函数如下:
void initHeartVectors(ArrayList<PVector> heart, int vectorNum, int r)
{
float x,y,a;
float crossOver;
crossOver = 1.6;
x=y=0;a=r;
pushMatrix();
translate(width/2,height/2);
//这里是核心,是笛卡尔之心在笛卡尔坐标系中的表现形式
for(float t = -PI;t < PI;t += 2*PI/vectorNum){
x = a*(crossOver*cos(t)-cos(2*t));
y = a*(crossOver*sin(t)-sin(2*t));
heart.add(new PVector(x,y));
}
popMatrix();
}
在这个函数中,我们向heart向量集中塞入了指定数量vectorNum的“点”充当心型线的向量。
将所有点连起来后的效果图如下:效果不错,接下里我们要让它跳起来。这里要引入一个概念,向量的线性插值。我们通过不断的在起点和终点之间插入中间值,让图形逐渐由一个形状变为另一个。这有点类似于动画中“关键帧”的概念。
在放上代码前,先看看跳动的效果图:
效果还不错,下面贴上实现代码(别在意函数的名字):
void drawExplosion(ArrayList<PVector> tar, ArrayList<PVector> ori, ArrayList<PVector> morph, int[] colorValue, int delayValue)
{
delay(delayValue);
float totalDistance = 0;
for (int i = 0; i < ori.size(); i++) {
PVector v1;
if (state) {
v1 = ori.get(i);
}
else {
v1 = tar.get(i);
}
//v1 = ori.get(i);
PVector v2 = morph.get(i);
//v2.lerp(v1, random(0,0.08));
v2.lerp(v1, 0.1);
totalDistance += PVector.dist(v1, v2);