伴隨 P5.js 入坑創意編程

上一篇文章:填坑!完結娛樂圈明星關系圖譜 發布后,古柳印象里過往留下的坑貌似只剩下 圖像檢索(一):因緣際會與前瞻 的后續實踐代碼(原文里給了參考代碼鏈接)和在豆瓣Top250電影海報上的嘗試效果了。

一想到所有坑都被填了(如果還有啥是我不記得的,請千萬不要提醒我),就覺得真是業界良心,倍感輕松。

于是古柳某日點開 圖像檢索(一):因緣際會與前瞻一文,回顧“佳作”之余,也找了下里面清華美院向帆老師的作品集網站 zeelab Projects

PS:如果你沒看過這個演講,推薦一看,古柳至今難忘:【一席】向帆:如果把每年的春晚都像蚊香一樣卷起來的話,它就是這樣的

而在這些作品中,古柳更中意且也想實現下類似網頁展示效果的是:AwardPuzzel - zeelab 。下面援引下“官方”介紹,建議去網頁體驗一下:

AwardPuzzel 是一個全國美展油畫類獲獎畫作的數據視覺化作品,收錄了美展第六屆至第十二屆的2276幅獲獎作品,通過動態交互的方式呈現了中國油畫30年間的藝術歷程、形態、色彩、尺寸和地區之間的變化和關系以及中國油畫大師們的藝術思路。
本作品可以被當作研究工具為研究者和評論家使用,亦可作藝術作品欣賞。
我們希望通過這個平臺分享我們的視角,也希望使用者通過自己的瀏覽和觀察得到自己的結論。
全國美展是中國美術界最重要事件,每五年舉辦一次,第六屆是1984年舉辦,第十二屆為2014年舉辦。

雖然古柳不怎么會前端,但自從接觸爬蟲以來,右鍵“審查元素”,查看網頁源代碼的習慣還是有的。

于是不看不知道,一看又引出了后續的諸多故事,借用書上的一句話:“那日也是合該有事”,且聽古柳慢慢道來......


點開網頁源代碼后,找到數據展示和交互的區域對應的代碼自然是不難的。這里為了展示方便,特地丟到 Carbon 里,重點突出下這段代碼。

可以看到 HTML 里主要用了 canvas 標簽,這也沒什么,古柳反正不懂 canvas,睜眼瞎罷了,也看不出什么名堂。但是卻發現標簽里的 data-processing-soucres 屬性對應的 .pde 文件,特別與眾不同,“聞所未聞,見所未見”,并且想起當初也曾各種搜羅,希冀能復現向帆老師的春晚或美展油畫項目,雖不了了之,但對 processing 這一能實現各種藝術創意的編程語言有了印象。

于是谷歌了下 “HTML+Canvas+Processing” 等關鍵詞,意外地發現:基于 JavaProcessing 語言的家譜中,還有對應 JavaScriptPython 版本,前者即:P5.js,而這不禁使古柳看到了能在網頁中復現上述效果的希望。

說起來,之前古柳壓根一丁點都沒聽說過 P5.js,搜了下對應的中文資料也不算多,更偏愛看視頻學習的我,看到萬能的B站上有人搬運了油管上Daniel Shiffman 的教學視頻(1-12節),于是立馬刷了下,p5.js 基礎教程 1-7,并全部跟著敲了遍代碼,雖然無字幕,但還蠻好啃的,有很多針對初學編程的知識講解。(原始鏈接:Code! Programming with p5.js - YouTube

習得新技能后,立馬用明星關系圖譜的圖片簡單粗暴的拼了下照片墻,雖然離美展油畫的效果差了十萬八千里,但也算是賣出了第一步。



其實以前就沒少拼照片墻,想來大家也都見過爬取微信好友然后拼圖的文章,但古柳還是安利下這篇舊文,里面的圖片絕對值得一看(如果你看完覺得也不咋地,那......也就隨它去吧):用python的PIL庫輕松拼接一百張照片

再就是幾天前,看到 @愛可可-愛生活 老師的這則微博:Processing 創作的生成藝術 via:おかず?,配圖漂亮就不說了,重點是帶著 Processing 關鍵詞,于是就埋下了想用 P5.js 實現一波的念頭。

幸運地找到了作品的出處:Generative Art #146 via:おかず,欣喜地發現附有 Processing 實現代碼,而且該系列有更多不錯的作品,遂萌發了想將其所有作品用 P5.js 實現一波并開源的想法。

當然因為目前 P5.js 不夠熟練,JavaScript / ES6 之類也只是入門,難免有所擔心和顧慮。但在復現這個作品時發現 ProcessingP5.js 真的很像,很多函數接口官方設計成統一的,極大降低了門檻。

上圖就是古柳用 P5.js 復現的效果,雖然還有些小問題,代碼也不一定最規范,但先行分享,后續再優化哈!可在此網址體驗作品生成效果: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();
  }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容