因本学期接触了《互动媒体》这门课程,了解到了“码绘”的神奇,所以总结两篇文章,记录自己码绘路上的辛酸喜乐。《那个站在科学与艺术路口撸码绘的女同学(一)》主要为静态码绘,而(二)主要为动态码绘分享,若有错误请指出,欢迎下方留言区评论交流。(本文已收录于知乎《动效》、《大学生程序员》等专栏、简书《工具癖》《@IT.互联网》等专栏)
首先作说明:为了增加博客可读性和趣味性用了很多诙谐的话,但是实际实验报告是很正经的。
“运动”主题操作——动态码绘
嘿,醒醒,该撸“动态”码绘了。不知道上一期最后的大佬比赛作品有没有把你看得激情澎湃忍不住想试试水。这几天,我终于摆脱手残的深渊,画了一幅稍微能看的动态图(希望你们看完能夸夸我)。
直女的直线思维
(1)动态码绘入门思考
阅读老师分享的《代码本色》一书,首先使我想到,物理世界中,万事万物怎么运动,又是因为什么而运动起来的呢?通过初中到大学学习的物理知识我们都知道,力是一个关键因素。但是,力只是可以改变物体的运动状态,并不是只要物体受力作用其运动状态就一定会改变。而与“力”、“运动”的物理量还有速度、位移、时间、阻力、摩擦力等等。那么在代码中实现动态又可以通过哪些“力”来实现呢?
(2)动态码绘实践
我的动态绘画中主要用的有粒子系统、随机数、循环结构,所涉及的改变对应到物理中就是加速度、位置和运动周期。
与此相比,在手绘中,查阅资料看到表现动态的手法,最基本的是通过画物体运动中某一时刻的状态体现一种“未完成”的运动中的姿态。还有画阴影、突出骨骼等等也能表现出动态,在漫画中,甚至可以通过夸大的画法来表现。
直女的动态码绘
客观来说,确实没有上次丑陋,并且还有了场景性,甚至有点卡哇伊了。话不多说,直接上代码(其中包括旋转、粒子系统等已做备注):
let snowflakes = []; // array to hold snowflake objects
var song;
var yi=0.0;
var x = 1;
var y = 1;
var easing = 0.05;
function preload() {
song=loadSound('1.mp3');
}
function setup() {
createCanvas(1280, 650);
fill(240);
noStroke();
song.loop();
//frameRate(5);
}
function draw() {
background('brown');
/球
fill(100);
arc(640, 290, 380, 380, PI, 2.5*TWO_PI);
fill(204);
arc(640, 290, 330, 330, PI, 2.5*TWO_PI);
//树
c = color('hsb(160, 100%, 50%)');
fill(c);
triangle(520, 320, 600, 240, 680, 320);
triangle(530, 280, 595, 220, 650, 280);
triangle(540, 240, 590, 180, 640, 240);
球里1房
fill(160,82,45);
triangle(610, 280, 680, 220, 750, 280);
fill(163,148,128);
rect(630, 280, 100, 120);
var h = random(0, 360);//窗子
fill(255,h,90);
rect(660, 300, 10, 10);
rect(675, 300, 10, 10);
rect(660, 315, 10, 10);
rect(675, 315, 10, 10);
fill(160,82,45);
rect(675, 370, 20, 30);
/2房
fill(160,82,45);
triangle(530, 340, 600, 280, 670, 340);
fill(210,180,140);
rect(550, 340, 100, 60);
var h = random(0, 360);//窗子
fill(255,h,90);
rect(570, 350, 10, 10);
rect(585, 350, 10, 10);
rect(570, 365, 10, 10);
rect(585, 365, 10, 10);
fill(160,82,45);
rect(610, 370, 20, 30);
//跑马灯
var h = random(0, 360);
fill(h,90,90);
ellipse(620, 219, 10, 10);
ellipse(613, 224, 10, 10);
ellipse(605, 229, 10, 10);
ellipse(596, 235, 10, 10);
ellipse(587, 240, 10, 10);
ellipse(580, 244, 10, 10);
ellipse(587, 250, 10, 10);
ellipse(595, 256, 10, 10);
ellipse(604, 260, 10, 10);
ellipse(612, 265, 10, 10);
ellipse(620, 270, 10, 10);
ellipse(612, 275, 10, 10);
ellipse(604, 280, 10, 10);
ellipse(595, 285, 10, 10);
ellipse(585, 287, 10, 10);
ellipse(575, 290, 10, 10);
ellipse(565, 293, 10, 10);
ellipse(555, 296, 10, 10);
ellipse(547, 299, 10, 10);
/星
var c = color(255, 204, 0);
fill(c);
push();
translate(590, 180);
rotate(frameCount / -100.0);
star(0, 0, 10, 30, 5);
pop();
/雪人
fill(255);
arc(730, 340, 50, 50, PI, 2.5*TWO_PI);
arc(730, 380, 65, 80, PI, 2.5*TWO_PI);
fill(0);
arc(720, 330, 10, 10, PI, 2.5*TWO_PI);
arc(740, 330, 10, 10, PI, 2.5*TWO_PI);
fill(227,23,17);
arc(730, 340, 8, 8, PI, 2.5*TWO_PI);
fill(138,54,15);
rect(756, 350, 5, 20);
rect(698, 350, 5, 20);
//底座
fill(245,222,179);
rect(460, 400, 360, 150);
fill(0);
strokeWeight(0);
textSize(16);
textStyle(ITALIC);
text('Merry Christmas', 580, 480);//字
/盒子
push();
var targetX = mouseX;
var dx = targetX - x;
x += dx * easing;
var targetY = mouseY;
var dy = targetY - y;
y += dy * easing;
he(x,y);
pop();
/铃铛
push();
translate(110.0, 50.0);
if (second() % 2 == 0) {
yi = random(20, 30);
rotate(PI/yi);
}
ling();
pop();
push();
translate(900.0, 50.0);
if (second() % 2 == 0) {
yi = random(20, 30);
rotate(PI/yi);
}
ling();
pop();
//雪
fill(255);
let t = frameCount / 60; // update time
// create a random number of snowflakes each frame
for (var i = 0; i < random(5); i++) {
snowflakes.push(new snowflake()); // append snowflake object
}
// loop through snowflakes with a for..of loop
for (let flake of snowflakes) {
flake.update(t); // update snowflake position
flake.display(); // draw snowflake
}
///
}
// snowflake class飘雪粒子系统
function snowflake() {
// initialize coordinates
this.posX = 0;
this.posY = random(-50, 0);
this.initialangle = random(0, 2 * PI);
this.size = random(2, 5);
// radius of snowflake spiral
// chosen so the snowflakes are uniformly spread out in area
this.radius = sqrt(random(pow(width / 2, 2)));
this.update = function(time) {
// x position follows a circle
let w = 0.6; // angular speed
let angle = w * time + this.initialangle;
this.posX = width / 2 + this.radius * sin(angle);
// different size snowflakes fall at slightly different y speeds
this.posY += pow(this.size, 0.5);
// delete snowflake if past end of screen
if (this.posY > height) {
let index = snowflakes.indexOf(this);
snowflakes.splice(index, 1);
}
};
this.display = function() {
ellipse(this.posX, this.posY, this.size);
};
}
//旋转星星
function star(x, y, radius1, radius2, npoints) {
var angle = TWO_PI / npoints;
var halfAngle = angle/2.0;
beginShape();
for (var a = 0; a < TWO_PI; a += angle) {
var sx = x + cos(a) * radius2;
var sy = y + sin(a) * radius2;
vertex(sx, sy);
sx = x + cos(a+halfAngle) * radius1;
sy = y + sin(a+halfAngle) * radius1;
vertex(sx, sy);
}
endShape(CLOSE);
}
点击播放/暂停背景音乐
function mousePressed() {
if ( song.isPlaying() ) { // .isPlaying() returns a boolean
song.pause(); // .play() will resume from .pause() position
background(255,0,0);
} else {
song.play();
background(0,255,0);
}
}
///
///铃铛
function ling(){
fill(34,139,34);
ellipse(145, 210, 170, 170);
fill(245,222,179);
ellipse(145, 210, 140, 140);
translate(100 , 100 );
rotate(PI / 6.0);
fill(255,153,18);
ellipse(56, 46, 55, 55);
rect(20, 40, 70, 30, 20);
ellipse(55, 100, 20, 20);
quad(25, 60,15, 100, 95,100, 85, 60);
rotate(PI /- 6.0);
rotate(PI /- 6.0);
translate(-30 , 50 );
ellipse(56, 46, 55, 55);
rect(20, 40, 70, 30, 20);
ellipse(55, 100, 20, 20);
quad(25, 60,15, 100, 95,100, 85, 60);
rotate(PI / 6.0);
fill(227,23,13);
quad(20, 0, 20, -30, 70, 0, 70, -30);
rect(39, -23, 15, 20, 10);
}
/盒子
function he(){
translate(x,y);
fill(255,192,203);
rect(15, -7.0, 65, 65);
fill(65,102,225);
rect(5, -7.0, 83.5, 15);
rect(15, 8, 5, 50);
rect(25, 8, 5, 50);
rect(35, 8, 5, 50);
rect(45, 8, 5, 50);
rect(55, 8, 5, 50);
rect(65, 8, 5, 50);
rect(75, 8, 5, 50);
fill(255,192,203);
quad(20, 0, 20, -30, 70, 0, 70, -30);
rect(39, -23, 15, 20, 10);
}
祝每个程序员不脱发不掉发,过好每个加班熬夜的圣诞节。
动态码绘感受
(1)有了实验一《对比代码和手绘静态画》的铺垫后,本次实验,增加的一点要求就是“让图画动起来”。按照实验要求,我按照以前的思路先构思好要画的图,把他们分解成每一个基础的单一图形,比如点、线、圆形、矩形等等,然后确定每个图形的坐标和大小,最后用P5.js来编写代码。分别画出基本元素后再把他们拼起来,变成一副完整的图片,最后再通过添加不同的运动函数,使他们平移、旋转、抖动等等。而用手绘的方法,除了画出静态图,表现动态则通过曲线、运动线等等来表现。
(2)在进行本次实验前,想到以前做的的js+html+css动态时钟,以及就在上周刚用js完成的哈夫曼动态树的实现,都是动态的,所以就可以借鉴之前用到的代码和实现方法。这两个实验中,一个主要是通过rotate来实现时针旋转,而另一个通过鼠标键盘的交互事件来控制树中新节点的绘制。我的动态绘画中主要用的有粒子系统、随机数、循环结构,所涉及的改变对应到物理中就是加速度、位置和运动周期。
(3)与此相比,在手绘中,查阅资料看到表现动态的手法,最基本的是通过画物体运动中某一时刻的状态体现一种“未完成”的运动中的姿态。还有画阴影、突出骨骼等等也能表现出动态,在漫画中,甚至可以通过夸大的画法来表现。
搞点干货
(一)码绘工具(除了P5.JS)
a.)Echarts是上一次数据分析在网页上制作统计表时,偶然发现的,通过简单的导入包,就可以实现动态的绘制各种统计表格。此工具同样可以用于地图绘制并且实现交互,非常高大上,但是用于单纯的动态代码绘制却没有那么灵活。
b.)GoJS是在绘制动态哈夫曼树的时候发掘的工具,用来绘制动态树、组合关系等等都非常方便,但是也只是实现了这些关系图的动态,也难以用于其他图像的绘制。
c.) Processing是一个开源项目,在搜集资料过程中,我发现processing在国外其实已经非常普及,经常被设计师用于创意编绘,从「Level:Beginner」最基础的怎么画一个简单图形,修改颜色,简单的鼠标、键盘交互。到真正的代码基础,包含Arrays数组、Function函数、Class类的基础概念和运用。以及 Processing 自带的一些方法,Curve曲线、shape形状、matrix矩阵变换等等。可以做出一些能看的效果了。还有二维数组操作等等,是「Level:Intermediate」进阶准备。以及声音交互、硬件交互、网络。这里 Processing 自带的 PVector 这个方法是个重点。它在数学里是「向量」的概念,在物理里是「力」的概念,在交互动画里是一种驱使对象动起来的很科学的手段。P3D是在 Processing 里实现3D效果的方法。
(二)学习文档
(1)《Learning Processing》他是纽约大学Tisch艺术学院助理艺术教授。Processing 官方教程里有几个章节是他写的。他出过两本书,第一本是Learning Processing,但是看过官方教程的也就不用看这本书了。
(2)《The Nature of Code》讲了很多自然模拟算法、交互动画、视觉效果的内容。甚至还包括了遗传算法、神经网络的原理。书里有配图,有例子,行文有趣又清晰明了。而且很书面语,通俗易懂。除了这两本,在processing官网上也有很多别的书目推荐,可以学习运动原理、代码思路等等。
(三)社区
Algorithmic Design 很多人在上面上传自己的码绘作品,并且有源码,很适合入门选手(我这样的小白)进步。但是必须要说的是:抄袭可耻!希望每个人都尊重作者,保护版权,切勿剽窃。
最后说点事情
虽然可以手绘、可以PS,但是学点脚本代码什么的,确实很有必要。
“随着时代的变迁,新的动画形式和载体不断被创造出来。但旧有的形式并没有消亡,他们都承载着自身的价值。
传统手绘依然是理论基础,基本功,艺术学院必修课。CG 是后来随着电影行业的需求发展起来的领域。同时游戏也是在发展的。但是由于电影的工业化程度太高了,技术积累越来越深厚。后来的游戏设计使用的工具开始偏向电影那一套。再看网站、移动设备。放在动画大流里只能说是冰山的那一角。而且使用的设计工具「很不正派」。这个领域也是实时渲染,早两年前顺藤摸瓜,只能摸到flash、游戏引擎。继续看 VR/AR/MR 这块。由于游戏引擎天然的支持3D环境,VR设计几乎回到了游戏设计的范式。不管是 Native 还是 Web ,如果要支持 VR/AR/MR ,想都别想,引擎搞起!对于动效设计来说,是不是也会回到老路上呢?
另外的新媒体艺术,那群人我很佩服。我也在了解他们的设计流程,并且初有成效。但是反过来在大的「动画设计」的语境下来看,搞代码不是技术美术干的事情吗?我到底怎么才能绕出去?答案很可能是「绕不出去」,动画就像一个黑洞一样,吞噬着设计师的青春。
不过对我来说,学点脚本代码什么的,还是很有用的。我认为这是个潮流。不信你可搜索一下关键词「非线性参数化建筑设计」。还有一些平面作品,线条的感觉很有序,又很自然那种。人家很可能就是用脚本写出来的。”——Guoen Sun
以上就是来自刚接触码绘并且被大佬码绘震惊吸引的小白——珠珠同学。第一次写技术性干货分享文章,居然觉得很有趣哈哈。欢迎各位大佬点赞、留言评论,带小白我一起飞。
本篇首发于CSDN,引用请注明出处。
那个站在科学与艺术路口撸码绘的女同学(一)
那个站在科学与艺术路口撸码绘的女同学(二)
知乎链接:Karmy有大大梦想的小小女孩
个人简书:Karmy
也欢迎微信联系交流:DDA-zhu-