手绘与码绘的比较——实战之梵高《星空》

版权声明:本文为博主原创文章,未经博主允许不得转载。

最近博主的老师在交互媒体设计课上布置了一个作业,是关于“运动”主题的作品创作,恰巧博主之前就有想过要实现一下类似希腊艺术家Petros Vrellis做的基于梵高名作《星空》的交互程序,叫做“Starry Night”。这款程序在苹果的App Store中可以买到,价格是15块钱。原作者用的工具是openframeworks,而博主为了节省时间(作业老多了),选择的是processing。因为本文的主题是“手绘与码绘的比较”,所以整篇文章会以两者异同之处的梳理过程作为主要框架,中间穿插博主实现码绘作品的关键代码。

作品展示

首先,博主先放上自己手绘作品和码绘作品的结果展示(虽然有点丑),原作是由纽约艺术家Aja Kusick模仿梵高的作品创作的。

原作:

手绘作品:

码绘作品:

思考

在看完上面两组作品之后,博主想请大家思考一个问题:为什么要用码绘的方式进行作画?对于“绘画”,编程能够做些什么?其实答案很简单:编程可以实现画不出的效果,接轨前沿艺术。我们通过编程,可以高效率地做出自己想要的图形效果,而这种图形效果的创作过程和原理完全不同于传统的手绘方式:前者本质上是创造了一个小型的空间,我们就是这个空间的主宰者,这个空间中的物体都是客观存在的,它们都有自身的客观属性,都服从我们所定好的规则;后者则不然,手绘所能表现的内容深度可能比码绘要强,但其广度是不如码绘的,比如如果想要以手绘的方式做出动画效果,它所能依赖的只能是人眼本身的视觉暂留机理,我们甚至可以粗鲁地认为两幅内容相同的手绘作品“并不相同”,因为这两者并不存在必然的客观联系,我们所认为的一些联系其实都只是自己的主观臆想而已

比较

接下来的这一个部分,博主准备从工具、技法、创作体验、呈现效果、载体、局限性、应用这个几个方面进行手绘创作和码绘创作的比较。

(1)工具

工具原指工作时所需用的器具,后引申为达到、完成或促进某一事物的手段。博主的手绘作品是使用了一款叫做Procreate的手绘软件,其功能十分强大,包含了丰富的画笔效果,不好看只是因为博主的手绘能力不行。至于博主所用的码绘工具,当然就是前文所提到的java版的processing。

(2)技法

技法是指艺术家运用他们的工具和材料以获得表现性效果的方法或技术。这一部分也是博主本文所要描述的重点。常用的手绘技法包括对各种色笔的灵活使用、利用例如尺子等工具的作图手段······专业的手绘创作者能够利用这些工具将线条、色调、色彩运用到极致,这是码绘目前很难企及的,像博主所作的码绘作品在对色彩的运用上就远不如手绘灵活和丰富。而对于码绘而言,其技法多基于所使用的编程语言的特性,例如,像博主使用的processing是基于java语言的(当然processing也有js版、python版),而java语言一个很重要的概念就是类。通过类的继承多态性,我们甚至可以创造出世界上所有的物体,因为所有的物体都是“物体”,而“物体”就是物质世界的根类。在博主的码绘作品中,一共定义了7个类,其中跟粒子有关的3个类之间的关系如下:

继承
继承
Particle
Circle_Particle
Flow_Particle

粒子类的具体代码如下:

//Particle父类
class Particle{PVector location;  //位置PVector velocity;  //速度PVector acceleration; //加速度color p_color; //颜色float lifespan; //寿命float p_scale; //缩放大小PShape s,s1,s2,s3; //形状//构造函数Particle(color C, float lp, float sc){  lifespan = lp;p_color = C;p_scale = sc;noStroke();fill(p_color);s = createShape(GROUP);s1 = createShape(RECT,0,0,40,10);s2 = createShape(ELLIPSE,0,5,10,10);s3 = createShape(ELLIPSE,40,5,10,10);s.addChild(s1);s.addChild(s2);s.addChild(s3);}void run(){update();display();}void update(){}void display(){}boolean isDead() {if (lifespan < 0.0) {return true;} else {return false;}}void applyForce(PVector force) {PVector f = force.get(); acceleration.add(f);}
}
//Circle_Particle类,继承于Particle类
class Circle_Particle extends Particle{PVector center;  //旋转中心PVector radius;  //旋转半径PVector now_dir; //当前位置float palstance; //角速度float r_max; //接受向心力的最大半径Circle_Particle(PVector l,PVector c, color C, float rmin, float rmax, float lp, float sc){super(C,lp,sc);  //调用父类的构造函数location = l.get();center = c.get();location.x = center.x-(center.x-location.x)*random(rmin,rmax);location.y = center.y-(center.y-location.y)*random(rmin,rmax);palstance = 0.02;radius = PVector.sub(location,center);r_max = radius.mag() + 20;float velocity_size = radius.mag()*palstance;PVector tangent = radius.copy();tangent = tangent.rotate(0.5*PI);velocity = tangent.normalize().mult(sqrt(velocity_size));acceleration = radius.normalize().mult(-palstance*sqrt(radius.mag()));}//重写updata()函数void update(){velocity.add(acceleration);location.add(velocity); now_dir = PVector.sub(center,location);if(now_dir.mag()<= r_max){acceleration = now_dir.normalize().mult(palstance*sqrt(now_dir.mag()));}else{acceleration = new PVector(0,0);  }lifespan -= 1;}//重写display()函数void display(){pushMatrix();translate(location.x,location.y);rotate(-(HALF_PI-now_dir.heading()));  scale(p_scale,p_scale);  shape(s,0,0);popMatrix();}
}
//Flow_Particle类,继承于Particle类
class Flow_Particle extends Particle{Flow_Particle(PVector l, PVector v,  color C, float rmin, float rmax, float lp, float sc){super(C,lp,sc);location = l.get();location.x = location.x*random(rmin,rmax);location.y = location.y*random(rmin,rmax);velocity = v.get();acceleration = new PVector(0,0);}void update(){velocity.add(acceleration);location.add(velocity);lifespan -= 1; acceleration.x = 0;acceleration.y = 0;}void display(){pushMatrix();translate(location.x,location.y);rotate(velocity.heading());  scale(p_scale,p_scale);shape(s,0,0);popMatrix();}
}

两个子类Circle_Particle和Flow_Particle都继承了它们父类Particle的成员变量和方法,并利用多态性进行了某些方法的重写,以及添加新的成员方法。在这两个类中还用到了random方法,为粒子的初始位置和颜色添加了随机性。如果我们还想继续丰富我们的粒子类,只需要不断地继承和修改、添加就可以了。当然,既然有了粒子类,就少不了管理粒子的粒子系统类(Particle System)。我们可以将所有对粒子的操作全都交给粒子系统去执行,这样就大大降低了代码的复杂度。最终,我们只需要创建几个粒子系统去管理几堆粒子就可以实现片头码绘作品中所呈现的动态效果了

粒子系统类的具体代码如下:

import java.util.Iterator;
//父类ParticleSystem
class ParticleSystem{PVector origin; //所管理的粒子的初始位置color[] Color; //粒子的颜色int c_length;  //Color数据的长度float rmin; float rmax;float lifespan; //粒子寿命float p_scale; //缩放程度float range = 50; //进行交互时的作用范围ParticleSystem(PVector l, color[] C, float min, float max, float lp, float sc){origin = l.get();Color = C;c_length = Color.length;rmin = min;rmax = max;lifespan = lp;p_scale = sc;}//添加粒子void addParticle(){}//对粒子添加作用力void applyForce() {}void run(){}
}
import java.util.Iterator;
//Flow_PS类,继承于父类ParticleSystem
class Flow_PS extends ParticleSystem{ArrayList<Flow_Particle> particles;PVector velocity;Flow_PS(PVector l, PVector v, color[] C, float min, float max, float lp, float sc){super(l,C,min,max,lp,sc);velocity = v.get();particles = new ArrayList<Flow_Particle>();}void addParticle() {int temp_c;temp_c = floor(random(0,c_length));color p_color = Color[temp_c];  particles.add(new Flow_Particle(origin, velocity, p_color, rmin, rmax, lifespan, p_scale));}//重写void applyForce(PVector f, PVector clicked) {for (Flow_Particle p: particles) {float temp = PVector.sub(clicked,p.location).mag();if(temp < range){p.applyForce(f);}}}//子类新添加的成员函数void applyAttractor(Attractor a, int t, int range) {for (Flow_Particle p: particles) {PVector force = a.attract(p,t,range);        p.applyForce(force);}}//重写void run() {Iterator<Flow_Particle> it = particles.iterator();while (it.hasNext()) {Flow_Particle p = it.next();p.run();if (p.isDead()) {it.remove();}}}
}

还有一个Circle_PS子类的代码并未贴出,留给感兴趣的童鞋去思考。

不难看出,码绘设计物体的思路是不同于手绘的。通过分析并挖掘出物体之间的某些共性,我们就能利用代码快速设计出不同属性的物体。除了类的继承和多态之外,码绘还能利用条件语句、循环语句等基本手段来减少绘画的复杂性。例如,通过运用循环语句,我们只要写几行代码就可以绘制成千上万个粒子,这要是换成手绘,其工作量将变得十分巨大。

(3)创作体验

无论是手绘还是码绘,在创作过程中都免不了修改。对于前者来说,“修改”是在原来的作品上除去不满意的部分并进行重新绘制;而对于后者而言,“修改”是抛弃原来所创造的物体,在修改掉世界规则后重新生成一批全新的物体。就博主个人而言,博主觉得前者会带给人一种类似悉心照顾小树苗直至其长成大树的成就感,而后者带给人的则是更加客观、直接的创造感

(4)呈现效果

根据文章开头的三张图片,我们可以看出虽然手绘作品已经尽量在图形、色彩等方面花心思来表现想要的流动的动态效果,但其本质上仍是静止的;然而码绘作品却能够轻松写意地将星空转动起来。不过,博主并不觉得两者的呈现效果有何高低之分,反而觉得它们各有自己独特的魅力和韵味。

(5)载体

手绘作品的载体包括纸张、墙壁、存储像素数据的图像矩阵等等;而码绘作品的载体则是计算机、显示器等等。

(6)局限性

显然,手绘在表达动态效果的能力上是比较欠缺的,而码绘在对图形、色彩的运用程度上不如手绘灵活。

(7)应用

我们可以通过手绘和码绘的方式进行设计创作,或者用于表现自身的思想情感······码绘甚至能做出各种各样的交互方式,将人们带入到画中去。博主这次也做了简单的交互方式:用户只要用鼠标在画面上进行拖拽,就可以带动附近的粒子朝着鼠标移动的方向运动。

交互部分代码如下(写在draw方法内):

  if(mousePressed){float force = dist(mouseX,mouseY,pmouseX,pmouseY);PVector temp = PVector.sub(new PVector(mouseX,mouseY),new PVector(pmouseX,pmouseY));temp.x = temp.x * force * 0.001;temp.y = temp.y * force * 0.001;fps1.applyForce(temp ,new PVector(mouseX,mouseY));fps2.applyForce(temp ,new PVector(mouseX,mouseY));}

效果如下:

结语

由于这是博主第一次写东西,可能很多语言都不太连贯恰当,论证方式也不够严谨,还望大家多多包含。希望大家在看了博主的文章之后,能够对手绘和码绘这两种方式有了自己的理解和思考。文章中贴的代码也并不全,如果有需要的童鞋可以在下面留言。

参考链接

(1)0.1 用代码画画——搞艺术的学编程有啥用?https://blog.csdn.net/magicbrushlv/article/details/77922119.
(2)1.1 开始第一幅“码绘”——以编程作画的基本方法
https://blog.csdn.net/magicbrushlv/article/details/77840565
(3)The Nature Of Code
https://natureofcode.com/

手绘与码绘的比较——实战之梵高《星空》相关推荐

  1. 手绘vs码绘1——Q版小人

    手绘与码绘静态对比 前言 在互动媒体的课程上,我了解了P5.js这项技术,并且学会了运用它进行简单的网页绘图.可能有很多人认为,绘画是一种艺术形式,必须要拿起画笔才能产生好的作品,而代码听起来和绘画毫 ...

  2. 手绘vs码绘 动态对比

    用手绘和码绘两种方式创作"运动"主题的作品,并作出对比 手绘图: 码绘图: 比较 技法:不考虑美观的话手绘比较方便,可以怎么想怎么做,而码绘却比较复杂,需要转换为代码. 工具:手绘 ...

  3. 手绘与码绘的比较---模拟风吹树动

    手绘与码绘的比较-模拟风吹树动 一.内容介绍 本文主要介绍用手绘和码绘两种方式模仿一种自然现象–风吹树动的过程,以及在实现过程对这两种方式的比较和思考.之所以选择风吹树动,是因为每次速写画一些场景时( ...

  4. 手绘VS码绘——动态篇(视觉错觉)

    前言 在介绍这次的实验前,先让我们看看一组图片: 相信大家看完这组图片已经有点难受的想点一下右上角的X了,其实不止你们,我在写这篇文章的时候也想关掉它-- 接下来我就按照正常的介绍流程告诉大家,这些图 ...

  5. 手绘与码绘对比(一)

    最近在老师的带领深入学习研究了手绘与码绘啊. 话不多说,直接上图. enmmm.....我知道这图不怎么样,有点沙地奥,但我们的主要目的是感受手绘与码绘的不同创作体验啊! 码绘我这次用的是p5.js ...

  6. 手绘与码绘————动态对比

    本项目通过Python的turtle包的 简单练笔项目对手绘和码绘进行动态对比 思维异同 手绘:人类自古以来的传统绘画方式,千百年来无论是艺术家还是普通人都可以通过绘画来记录景色,传达情感,记录思考. ...

  7. 手绘vs码绘2——动态弓箭

    手绘与码绘动态对比 前言 在上一次博客中,我们已经成功用代码重现了手绘的Q版小人,对手绘和码绘进行了几个方面的对比分析.不得不承认,码绘由于形状和编写时间的限制,在绘制静态图像的方面和手绘还是有很大差 ...

  8. 手绘和码绘的对比(2)——动态比较

    码绘 手绘 代码实现过程 var numBalls = 30; var spring = 0.05; var gravity = 0.01; var friction = -0.9; var ball ...

  9. “运动”主题创作——手绘与码绘的比较

    "运动"主题创作--手绘与码绘的比较 本次主题是运动,在此便以最基本的运动形式--跑步来展现两者的区别. 手绘 手绘是静态的图片,为了展示"运动",可以把跑者的 ...

最新文章

  1. Linux/ubuntu:Chrome报错解决: error while loading shared libraries: libnss3.so libXss.so.1 libasound.so.
  2. c语言的语言扩展的数据类型,C语言之数据类型
  3. 成功解决object at 0x000002463192BAC8
  4. 暑假集训考试反思+其它乱写
  5. gitlab修改配置重启_centos7下gitlab安装说明
  6. ajax mode,DWR的三种Reverse Ajax Mode配置详解
  7. oracle cur notfound,%notfound的理解——oracle存儲過程 | 學步園
  8. [Firefox] 方便实用的firefox 插件
  9. 前后端分离,nginx解决跨域问题
  10. 小白系列:修改美化pycharm主题
  11. 台式计算机键盘灯打开方式,台式机开机黑屏但键盘指示灯亮的解决方法
  12. 本地html图片载入很慢,打开网页时图片加载很慢怎么办?网页图片打开慢的解决方法...
  13. 论文书写之如何引用参考文献(简单明了)
  14. MATLAB求复杂函数积分
  15. 使用建造者模式做一个密室逃脱类游戏
  16. Laya页面嵌套和Scene.destory导致的Bug
  17. vue3+ts+element-plus动态图标生成方式
  18. 先验概率与后验概率是什么
  19. redis源码解析(二)——SDS(简单动态字符串)
  20. visio消除直线连接圆弧

热门文章

  1. python爬取历史天气数据
  2. 机器学习day10——机器学习的系统设计
  3. 计算机主机名有后缀,一起学DNS系列(二)理解计算机的主DNS后缀选项
  4. 【程序员的数学基础课-黄申】学习笔记 1-10
  5. 流利说反编译抓包笔记
  6. Alink连接Kafka数据源(Python版本)
  7. 使用hugo生成静态页面,并部署到腾讯云的云开发环境。
  8. windows安装go
  9. Android WiFi直连 双向通信
  10. 王者荣耀资深游戏建模师分享游戏角色制作过程,技术分享