一、神奇的线条
手绘通过线条表现动感,例如中国画中最基础的技法“勾法”,以笔线勾取物象的外廓,以线造型,又称之为“线描”。
给出几张名作感受一下线描:
通过手绘,仅仅是几根简单的线条,就可以描绘出各种形态,线条真是个神奇的东西。既然线条如此神奇,我也要尝试一下,于是,我也模仿前人,画些线条,放几张拙作,不禁感叹:线条真神奇,几根线就成了一幅画!
虽然线条如此神奇,却花了我很多时间,说起来比较简单,不过是几根线条,但是真正画起来却不是那么容易。
要想画出一条长长的并且流畅的线条,也是需要很多时间练习并且掌握一定技法才可以。
那么,如果用电脑来画线条,又会出现怎么样的情况呢?
试想,如果用程序控制线条的走向,岂不是会更加精确,在绘制多条线时,速度可以极大地提升,效率将会得到大大的提升。
古人花了多个月的时间绘制一幅画,而我们可以利用程序在几秒钟之内完成一部作品,一想到这一点,成就感大大提升,但是,当我打开processing,准备绘制一幅“名作”的程序时,结果是却这样的:
嗯嗯嗯???说好的名作呢?太真实了……
果然,缺少想象力还真的只能是几根线而已。
大师们可以通过流畅的线条表现事物的灵动,我虽然没有大师们的觉悟,但是我拥有一颗灵动的心,于是,我让我的线条动起来了!
虽然有点简陋,但是这样的运动模式手绘一定没有
再加几条线,让他看上去不那么孤单:
仅仅只是个别几根线还是略显枯燥,于是乎:
这样看来,是不是感觉好多了,似乎也没那么单调了,而且,可以很明显地看出线条的运动规律,你也可以跟着线条一起扭动,顺便锻炼一下身体。
给出最后一幅群线乱舞的代码:
float t;
int NUM_LINES=5;
void setup(){
background(255);
size(600,600);
}
void draw(){
//background(255);
stroke(random(t),random(t/3+80),random(t/5+10));
strokeWeight(5);
translate(width/2,height/2);
for(int i=0;i<NUM_LINES;i++){
line(x1(t+i),y1(t+i),x2(t+i),y2(t+i));
}
t++;
}
float x1(float t){
return sin(t/10)*100+cos(t/15)*20;
}
float y1(float t){
return cos(t/10)*100+cos(t/10)*3;
}
float x2(float t){
return sin(t/10)*200+cos(t)*2;
}
float y2(float t){
return cos(t/6)*200+sin(t/5)*20;
}
二、线条运动的智慧
上面的程序中,线条的运动规律都是本人发挥了天马行空的想像力胡乱敲的,没有规律的规律, 为了得到更好的视觉效果,我去查阅了各种奇奇怪怪的资料,拿出小本本开始画圈圈(计算),看下图:
哇哦哦哦哦哦哦,终于不是之前乱糟糟的线条了,这样有一定的规律的线条看上去要舒服多了,并且还具有一定的美感,杂乱而不失身份,真是棒极了!
转眼再来看之前的静止画作,线条的精准位置和规律是手绘绘不出来的,手绘的动态是通过线条的流畅性、线条的走势来体现,而码绘可以真正地表现出线条的运动,并且可以通过明确的数学公式计算出线条的运动规律。
接下来,分享一波数学艺术:
http://benice-equation.blogspot.com/2012/01/fractal-spirograph.html
我根据上面的链接给出的图像用processing实现了部分(画圈圈画圈圈画圈圈):
圆上的点的坐标与圆的半径和角度有关,第二个圆圈与第一个大圆外切,那么运动点的坐标的最大位置是两个圆的半径之和。改变圆的运动方式、位置和速度,可以呈现出更多不一样的的效果。
部分代码如下:
ArrayList<PVector> path;
float angle = 0;
int resolution = 50;
Orbit sun;
Orbit end;
void setup() {
size(600, 600);
path = new ArrayList<PVector>();
sun = new Orbit(width/2, height/2, width/4, 0);
Orbit next = sun;
for (int i = 0; i < 10; i++) {//添加圆的个数,修改循环次数,可以改变圆的个数
next = next.addChild();
}
end = next;
}
void draw() {
background(50);
for (int i = 0; i < resolution; i++) {
Orbit next = sun;
while (next != null) {
next.update();
next = next.child;
}
path.add(new PVector(end.x, end.y));
}
Orbit next = sun;
while (next != null) {
next.show();
next = next.child;
}
beginShape();
stroke(255);
noFill();
for (PVector pos : path) {
vertex(pos.x, pos.y);
}
endShape();
}
//轨道
int k = -4;
class Orbit {
float x;
float y;
float r;
int n;
Orbit parent;
Orbit child;
float speed;
float angle;
Orbit(float x_, float y_, float r_, int n_) {
this(x_, y_, r_, n_, null);
}
Orbit(float x_, float y_, float r_, int n_, Orbit p) {
x = x_;
y = y_;
r = r_;
n = n_;
speed = (radians(pow(k, n-1)))/resolution;
parent = p;
child = null;
angle = -PI/2;
}
Orbit addChild() {
float newr = r / 1.8;//添加新圆的半径
float newx = x + r + newr;//位置(外切/内切)
float newy = y;
child = new Orbit(newx, newy, newr, n+1, this);
return child;
}
//更新位置坐标
void update() {
if (parent != null) {
angle += speed;
float rsum = r - parent.r;
x = parent.x + rsum * cos(angle);
y = parent.y + rsum * sin(angle);
}
}
void show() {
stroke(255, 100);
strokeWeight(1);
noFill();
if (parent != null) {
line(parent.x, parent.y, x, y);
}
ellipse(x, y, r*2, r*2);
}
}
从创作体验上来说,手绘可以让我接触真实,通过实实在在的画笔、纸张或是其他工具来实现一幅作品,其过程漫长而艰辛。而码绘则是通过一连串的代码实现作者本人的思想,对画面的可控性低,无法很快的决定落笔在何处,但是可以很快地完成一幅复杂的图像,精确度高。精确度体现在画规则图形,比如说码绘可以无限次画出同一个图形,而手绘则很难实现。
手绘和码绘的呈现效果各有所长,手绘更具灵动性,线条优雅,可曲可直,可以完全按照作者的心理来作画;码绘在复杂且有规律的图像上面有较大的优势,但是缺少一定的自由度,无法完全按照作者心中所想来实现。
面对如今快节奏的生活和广大人民群众对视觉效果的追求,码绘在一些展馆或活动上面可以发挥极大的优势,提升服务质量。
利用数学思想绘制图形可以带来更多的惊喜,下一回我将为大家带来视觉效果更为突出的图形!
三、参考资料
路径跟踪:
https://processing.org/reference/PVector.html
数学艺术:
http://benice-equation.blogspot.com/2012/01/fractal-spirograph.html
《用代码画画》:
https://blog.csdn.net/magicbrushlv/article/details/77922119
《开始第一幅码绘》:
https://blog.csdn.net/magicbrushlv/article/details/77840565
《以编程的思想来理解绘画》:
https://blog.csdn.net/magicbrushlv/article/details/82634189