上一篇文章:填坑檩小!完結(jié)娛樂圈明星關(guān)系圖譜 發(fā)布后,古柳印象里過往留下的坑貌似只剩下 圖像檢索(一):因緣際會與前瞻 的后續(xù)實踐代碼(原文里給了參考代碼鏈接)和在豆瓣Top250電影海報上的嘗試效果了烟勋。
一想到所有坑都被填了(如果還有啥是我不記得的规求,請千萬不要提醒我),就覺得真是業(yè)界良心卵惦,倍感輕松阻肿。
于是古柳某日點開 圖像檢索(一):因緣際會與前瞻一文,回顧“佳作”之余沮尿,也找了下里面清華美院向帆老師的作品集網(wǎng)站 zeelab Projects丛塌。
PS:如果你沒看過這個演講,推薦一看蛹找,古柳至今難忘:【一席】向帆:如果把每年的春晚都像蚊香一樣卷起來的話姨伤,它就是這樣的
而在這些作品中,古柳更中意且也想實現(xiàn)下類似網(wǎng)頁展示效果的是:AwardPuzzel - zeelab 庸疾。下面援引下“官方”介紹乍楚,建議去網(wǎng)頁體驗一下:
AwardPuzzel 是一個全國美展油畫類獲獎畫作的數(shù)據(jù)視覺化作品,收錄了美展第六屆至第十二屆的2276幅獲獎作品届慈,通過動態(tài)交互的方式呈現(xiàn)了中國油畫30年間的藝術(shù)歷程徒溪、形態(tài)、色彩金顿、尺寸和地區(qū)之間的變化和關(guān)系以及中國油畫大師們的藝術(shù)思路臊泌。
本作品可以被當(dāng)作研究工具為研究者和評論家使用,亦可作藝術(shù)作品欣賞揍拆。
我們希望通過這個平臺分享我們的視角渠概,也希望使用者通過自己的瀏覽和觀察得到自己的結(jié)論。
全國美展是中國美術(shù)界最重要事件嫂拴,每五年舉辦一次播揪,第六屆是1984年舉辦,第十二屆為2014年舉辦筒狠。
雖然古柳不怎么會前端猪狈,但自從接觸爬蟲以來,右鍵“審查元素”辩恼,查看網(wǎng)頁源代碼的習(xí)慣還是有的雇庙。
于是不看不知道谓形,一看又引出了后續(xù)的諸多故事,借用書上的一句話:“那日也是合該有事”疆前,且聽古柳慢慢道來......
點開網(wǎng)頁源代碼后寒跳,找到數(shù)據(jù)展示和交互的區(qū)域?qū)?yīng)的代碼自然是不難的。這里為了展示方便竹椒,特地丟到 Carbon 里冯袍,重點突出下這段代碼。
可以看到 HTML
里主要用了 canvas
標(biāo)簽碾牌,這也沒什么,古柳反正不懂 canvas
儡循,睜眼瞎罷了舶吗,也看不出什么名堂。但是卻發(fā)現(xiàn)標(biāo)簽里的 data-processing-soucres
屬性對應(yīng)的 .pde
文件择膝,特別與眾不同誓琼,“聞所未聞,見所未見”肴捉,并且想起當(dāng)初也曾各種搜羅腹侣,希冀能復(fù)現(xiàn)向帆老師的春晚或美展油畫項目,雖不了了之齿穗,但對 processing
這一能實現(xiàn)各種藝術(shù)創(chuàng)意的編程語言有了印象傲隶。
于是谷歌了下 “HTML+Canvas+Processing”
等關(guān)鍵詞,意外地發(fā)現(xiàn):基于 Java
的 Processing
語言的家譜中窃页,還有對應(yīng) JavaScript
和 Python
版本跺株,前者即:P5.js
,而這不禁使古柳看到了能在網(wǎng)頁中復(fù)現(xiàn)上述效果的希望脖卖。
說起來乒省,之前古柳壓根一丁點都沒聽說過 P5.js
,搜了下對應(yīng)的中文資料也不算多畦木,更偏愛看視頻學(xué)習(xí)的我袖扛,看到萬能的B站上有人搬運了油管上Daniel Shiffman
的教學(xué)視頻(1-12節(jié)),于是立馬刷了下十籍,p5.js 基礎(chǔ)教程 1-7蛆封,并全部跟著敲了遍代碼,雖然無字幕妓雾,但還蠻好啃的娶吞,有很多針對初學(xué)編程的知識講解。(原始鏈接:Code! Programming with p5.js - YouTube)
習(xí)得新技能后械姻,立馬用明星關(guān)系圖譜的圖片簡單粗暴的拼了下照片墻妒蛇,雖然離美展油畫的效果差了十萬八千里机断,但也算是賣出了第一步。
其實以前就沒少拼照片墻绣夺,想來大家也都見過爬取微信好友然后拼圖的文章吏奸,但古柳還是安利下這篇舊文,里面的圖片絕對值得一看(如果你看完覺得也不咋地陶耍,那......也就隨它去吧):用python的PIL庫輕松拼接一百張照片奋蔚。
再就是幾天前,看到 @愛可可-愛生活
老師的這則微博:Processing 創(chuàng)作的生成藝術(shù) via:おかず?烈钞,配圖漂亮就不說了泊碑,重點是帶著 Processing
關(guān)鍵詞,于是就埋下了想用 P5.js
實現(xiàn)一波的念頭毯欣。
幸運地找到了作品的出處:Generative Art #146 via:おかず馒过,欣喜地發(fā)現(xiàn)附有 Processing
實現(xiàn)代碼,而且該系列有更多不錯的作品酗钞,遂萌發(fā)了想將其所有作品用 P5.js
實現(xiàn)一波并開源的想法腹忽。
當(dāng)然因為目前 P5.js
不夠熟練,JavaScript
/ ES6
之類也只是入門砚作,難免有所擔(dān)心和顧慮窘奏。但在復(fù)現(xiàn)這個作品時發(fā)現(xiàn) Processing
和 P5.js
真的很像,很多函數(shù)接口官方設(shè)計成統(tǒng)一的葫录,極大降低了門檻着裹。
上圖就是古柳用 P5.js
復(fù)現(xiàn)的效果,雖然還有些小問題米同,代碼也不一定最規(guī)范求冷,但先行分享,后續(xù)再優(yōu)化哈窍霞!可在此網(wǎng)址體驗作品生成效果:https://editor.p5js.org/DesertsX/sketches/GxYHsZg9n
let particles;
const n = 120;
function setup() {
createCanvas(900, 900);
// pixelDensity(2);
colorMode(HSB, 360, 100, 100, 100);
rectMode(CENTER);
newParticles();
}
function draw() {
for (let i in particles) {
let p = particles[i];
p.run();
if (p.isDead()) {
particles.splice(i, 1);
}
}
}
function forms() {
for (let j = 0; j < n; j++) {
let x = random(width), y = random(height);
let s = random(20, 100);
let hs = s / 2;
let c = getCol();
noStroke();
fill(c);
if (random(1) > 0.5) {
for (let i = -s / 2; i < s / 2; i++) {
particles.push(new Particle(x + i, y - hs, c));
particles.push(new Particle(x + i, y + hs, c));
particles.push(new Particle(x - hs, y + i, c));
particles.push(new Particle(x + hs, y + i, c));
}
square(x, y, s);
} else {
for (let a = 0; a < TAU; a += TAU / 360) {
particles.push(new Particle(x + hs * cos(a), y + hs * sin(a), c));
}
circle(x, y, s);
}
}
}
function newParticles() {
// particles = new ArrayList<Particle>();
particles = new Array();
background("#FCFCF0");
forms();
noiseSeed(parseInt(random(100000)));
}
// function mousePressed() {
// newParticles();
// }
function keyPressed() {
// 還沒生效
if (keyCode === 's') {
saveFrame("123.png");
}
}
function getCol() {
let colors = ["#e4572e", "#29335c", "#f3a712", "#a8c686", "#669bbc", "#efc2f0"];
//let colors = ["#880D1E", "#DD2D4A", "#F26A8D", "#F49CBB", "#CBEEF3"];
let idx = parseInt(random(colors.length));
// console.log(idx + colors[idx]);
return colors[idx];
}
class Particle {
constructor(x, y, col) {
this.pos = createVector(x, y);
this.step = 1;
this.angle = random(10);
this.lifeSpan = 100;
this.noiseScale = 800;
this.noiseStrength = 90;
this.col = col;
}
show() {
noStroke();
// fill(this.col, this.lifeSpan);
fill(this.col);
circle(this.pos.x, this.pos.y, 0.5);
}
move() {
this.angle = noise(this.pos.x / this.noiseScale, this.pos.y / this.noiseScale) * this.noiseStrength;
this.pos.x += cos(this.angle) * this.step;
this.pos.y += sin(this.angle) * this.step;
this.lifeSpan -= 0.1;
}
isDead() {
return (this.lifeSpan < 0.0)
}
run() {
this.show();
this.move();
}
}