【p5.js創作教學】Coral Carnival 珊瑚嘉年華

前言

乘著生成式藝術的浪潮,讓我們一同體驗<珊瑚嘉年華>這件藝術作品的創作過程。使用 p5.js 的技術創作出絢爛夢幻、隨波蕩漾的珊瑚,看著它在海底深處搖曳擺盪,在暗夜中充滿生命力地熠熠生輝。

開場

這一次分享的內容比較特別,除了紀錄如何使用 P5.js 創作藝術之外,同時也記錄生成式藝術的創作過程。從初步的概念發想、創作中的顏色/動態/細節調整嘗試,一路到完成作品後的圖片保存處理、文案構思與撰寫,帶領大家一同體會藝術創作的趣味。

<珊瑚嘉年華>作品完成截圖
<珊瑚嘉年華>作品完成截圖

這次直播筆記會帶大家學會以下內容:

  • 瞭解一幅生成式藝術作品的完整創作過程
  • 使用 coolors 快速選擇色票並進行色彩搭配
  • 使用 frameCount() 在作品中加入逐幀動態效果,賦予作品生命力

事前準備

  1. 開發環境: 本次開發會使用 openprocessing 線上撰寫程式碼,如果想知道較詳細的設定,可以到老闆作品的 成品 查看相關的設定。
  2. 本次範例使用到的 API:

步驟講解

一、初步靈感發想

最初的靈感發想可以從自己喜歡的事物著手,像是老闆喜歡鋼琴、琴譜、植物,因此這次腦海中的雛型是「V字型、輻射狀、往外擴張」的圖案。

<珊瑚嘉年華>作品步驟一:靈感發想
<珊瑚嘉年華>作品步驟一:靈感發想

有了初步的想法後,接著老闆便參考自己在 Pinterest 上蒐集的各種海報、平面設計、生成式藝術等等,看它們的配色、使用的材質、文字樣式、3D等等,給自己更多作品靈感。此外,老闆常用的手法還有使用合適的材質跟顏色疊色,能快速地提升作品質感。

二、Sketch 起手式

使用 openprocessing 開啟一個新的 Sketch 之後,可以看到程式碼頁面已經有一段預設的程式碼:隨著滑鼠的移動,會沿路產生小球。

  • setup(): 環境建立/初始化,只在開始執行的當下會呼叫一次。以下的程式碼使用了兩個 API
    • createCanvas(width, height):創建畫布,參數中分別傳入寬跟高,如果直接寫螢幕的寬高( windowWidth, windowHeight),就會成為滿版的互動區塊。但老闆在創作<每日生成式藝術>系列時,習慣把寬高設為 (1000,1000) ,有一個比較固定的格式。
    • background(colorCode):加上背景色,可依照文件傳入色碼參數。
  • draw(): 會以每秒 60 次的循環重新呼叫並進行裡面的程式碼,想製作互動效果都可以在這個 function 中呼叫。
    • ellipse(posX, posY, width, height):在 (posX, posY) 上繪製一個寬高(width, height)的橢圓形,這邊用 (mouseX, mouseY) 的話便是隨著滑鼠移動的軌跡產生橢圓形
function setup() {
  createCanvas(1000,1000);
  background(100);
}

function draw() {
  ellipse(mouseX, mouseY, 200, 200);
}

三、繪製 V 圖案,複製並旋轉為輻射狀圖形

接下來,根據原本的靈感先畫出一串 V 型圖案,然後旋轉複製這些圖案。在開始前,先用 background()、fill()、rect() 這三個 API 將背景設為畫框的樣式。接著到中心點開始構圖,使用兩個長方形去組合成V型。要注意的是,只要有用到旋轉相關的API,都要記得 push() 跟 pop(),不然會影響到後續的程式碼。

  • background():設定背景顏色。
  • fill():選擇填入的顏色。
  • rect(x, y, width, height):在 (x, y) 的位置畫一個寬度 width、高度為 height 的方形。
  • translate(x,y):將畫筆移動到 x, y 的位置。
  • push():紀錄目前畫筆狀態。
  • pop():恢復畫筆狀態。
  • rotate(angle:依照傳入的參數進行旋轉。
  • PI():180度角。
  • rectMode(mode):設定四方型從什麼地方開始繪製。模式分別有 CENTER、CORNER、RADIUS 三種,注意模式的字必須是大寫。
function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  fill(255);
  noStroke();
	
  push();
    rotate(-PI/4*3);
    rect(75,0,200,50);
    rotate(PI/4*2);
    rect(75,0,200,50);
  pop();
}
<珊瑚嘉年華>作品步驟三:從簡單的圖樣開始畫起
<珊瑚嘉年華>作品步驟三:從簡單的圖樣開始畫起

組合出 V 型後,接著就用迴圈來複製它,然後加上 translate() 進行角度偏移,讓它每繪完一次圖案就往上移動一點再繼續繪製,這樣就能得到一串V的圖形。在迴圈外面要記得包一層 push()、pop(),讓它不影響到後續程式。

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  fill(255);
  noStroke();
	
  push();
    for(let i=0;i<10;i++){
      translate(0,-45);
      push();
        scale(0.5)
        rotate(-PI/4*3);
        rect(75,0,200,50);
        rotate(PI/4*2);
        rect(75,0,200,50);
      pop();
    }
  pop();
}
<珊瑚嘉年華>作品步驟三:利用迴圈快速大量複製簡單的圖樣
<珊瑚嘉年華>作品步驟三:利用迴圈快速大量複製簡單的圖樣

四、進行配色、旋轉與各種細節嘗試

基本的圖形完成之後,接下來就可以進行各種不同的嘗試與色彩搭配。老闆在這邊嘗試了:

  • 迴圈數增多:增加迴圈的數量、搭配 scale() 把圖形縮小、降低 translate() 數值讓圖形排列緊密。
  • 圖形旋轉:使用 rotate() 讓圖形旋轉。rotate()的參數除了代入數字,也可以帶入 sin(i) 之類的,嘗試不同的數值帶來的變化;或甚至可以代入rotate(sin(i/(mouseY/100))),讓圖形隨著滑鼠移動的角度旋轉,然後記得加個 background(0) 把背景軌跡清掉 (有些作品也會留下軌跡,但這邊先不用)
  • 色彩搭配:可以從蒐集的海報作品中找搭配靈感,或是 coolors 網站提供的色票搭配來快速搭配出喜歡的顏色。

找到喜歡的色票之後,可以直接從 coolors 的網址上複製色票的數值。

在 Coolors 找到喜愛的色票組合後複製
在 Coolors 找到喜愛的色票組合後複製

但複製完後,還需要先把色票轉成陣列的色彩,才能在P5.js 中使用。因此這邊會需要用到 JS 的語法 split() 與 map() 把色票轉成色彩字串的陣列。

const colors = 'cacf85-8cba80-658e9c-4d5382-514663'.split('-').map(a=>`#${a}`);

完成後就能把我們的圖形加入色彩啦!

const colors = 'cacf85-8cba80-658e9c-4d5382-514663'.split('-').map(a=>`#${a}`);

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  fill(255);
  noStroke();
  background(0); // 清除軌跡
	
  push();
    for(let i=0;i<20;i++){
      translate(0,-45);
      rotate(sin(i/(mouseX/100))); // 旋轉角度跟隨滑鼠移動
      fill(colors[i%colors.length]);
      push();
        scale(0.5)
        rotate(-PI/4*3);
        rect(75,0,200,50);
        rotate(PI/4*2);
        rect(75,0,200,50);
      pop();
    }
  pop();
}
<珊瑚嘉年華>作品步驟四:加上色彩、旋轉等變化
<珊瑚嘉年華>作品步驟四:加上色彩、旋轉等變化

五、構成萬花筒

只有一條太單調了,接下來一樣使用迴圈跟旋轉的方法,把圖形變成類似萬花筒的形狀吧!這樣一來就達成原本的構想 — 同心圓放射狀的V圖形。

const colors = 'cacf85-8cba80-658e9c-4d5382-514663'.split('-').map(a=>`#${a}`);

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  fill(255);
  noStroke();
  fill(0);
  rect(0,0 ,width,height);
	
  for(let o=0; o<8; o++){
    rotate(PI/4);
    push();
      for(let i=0;i<20;i++){
        translate(0,-45);
        rotate(sin(i/(mouseX/100)));
        fill(colors[i%colors.length]);
        push();
          scale(0.5)
          rotate(-PI/4*3);
          rect(75,0,200,50);
          rotate(PI/4*2);
          rect(75,0,200,50);
        pop();
      }
    pop();
  }
}
<珊瑚嘉年華>作品步驟五:慢慢建構成了萬花筒
<珊瑚嘉年華>作品步驟五:慢慢建構成了萬花筒

六、提升質感

剛開始創作藝術作品時通常會稍微缺乏質感,主要是「材質、顏色、細節、變化」這四種狀態技巧掌握度不足。因此,想提升質感就要進行一些優化,例如:

1. 添加顏色

const colors = '18206f-17255a-f5e2c8-d88373-bd1e1e-cacf85-8cba80-658e9c-4d5382-514663'.split('-').map(a=>`#${a}`);

2. 增添大小變化:

scale(random(1))scale(noise(1)) 將每一個 V 的大小變不一致。要注意的是,使用 random() 會在每次繪製時重新產生亂數,所以畫面會感覺比較不受控;使用 noise() 則是類似在一個亂數表上取值,跟 random() 概念不同,呈現的畫面也比較沒那麼亂。

scale(random(0.6, 1.1)); 
or 
scale(noise(i,o)/5+0.9);

3. 添加動態變化:

除了使用 mouseX 去控制變化之外,也可以加上 frameCount() 讓圖形隨著時間變動。另外,如果想同時保留 mouseX 跟 frameCount,記得幫 mouseX 加上0.1,否則滑鼠一旦不動,畫面也就不會更動 。

rotate(sin(i/(mouseX/100+0.1)+frameCount/50));<

4. 使用 BlendMode() 進行一些色彩混搭組合:

使用BlendMode() 這個 API 可以進行依些色彩混搭,多些顏色的變化。如果是黑色的背景,參數建議選 SOFT_LIGHT、SCREEN 來提亮。

blendMode(SCREEN);

5. 改變材質

可以上網找 Canvas texture,就可以找到許多種材質的圖片並下載使用。如果想下載本次範例使用素材,可以到 成品 這邊,點開查看原始碼、以及右邊的 File 檔案區,找到 <canvas.jpeg>並下載到自己電腦裡

下載<珊瑚嘉年華>作品使用的材質素材說明
下載<珊瑚嘉年華>作品使用的材質素材說明

再來一樣到自己的 Sketch 頁面右側欄一樣的 File 內,點選上傳就可以上傳這張圖片了。接著會使用 preload()loadImage() 這兩個API 在程式碼內載入這張背景,然後使用 blendMode() 進行材質疊加。

push()
  blendMode(MULTIPLY);	
  image(canvasTexture, -width/2,-height/2)
pop()

完整程式碼如下

const colors = '18206f-17255a-f5e2c8-d88373-bd1e1e-cacf85-8cba80-658e9c-4d5382-514663'.split('-').map(a=>`#${a}`);

var canvasTexture;
function preload(){
  canvasTexture = loadImage("canvas.jpeg")
}

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  fill(255);
  noStroke();
  fill(0);
  rect(0,0 ,width,height);
	
  push()
    blendMode(SCREEN);
    for(let o=0; o<16; o++){
      rotate(PI/8);
			
      push();
        for(let i=0;i<20;i++){
          translate(0,-20);
          rotate(sin(i/(mouseX/500+0.1)+frameCount/100));
          scale(noise(i,o,frameCount/50)/5+0.9);
          fill(colors[i%colors.length]);
					
          push();
            scale(0.1)
            rotate(-PI/4*3);
            rect(75,0,200,50);
            rotate(PI/4*2);
            rect(75,0,200,50);
          pop();
        }
      pop();
    }
  pop()
	
  push()
    blendMode(MULTIPLY);	
    image(canvasTexture, -width/2,-height/2)
  pop()
}

範例

<珊瑚嘉年華>作品步驟六:透過改變顏色、大小、材質、動態等,增加作品質感
<珊瑚嘉年華>作品步驟六:透過改變顏色、大小、材質、動態等,增加作品質感

七、細節調整

接下來就進入好玩的部分啦~這邊開始可以做一些大膽的嘗試或調整,像是:

  • 把四方型加點圓角
  • 減輕旋轉幅度
  • 改變背景顏色
  • 多加一組色彩進行搭配
  • 改變四方型的高度、寬度,營造錯落感
  • 使用 ellipse() 增加小點點

在這個階段,可以根據自己的喜好自由調整與搭配,好好感受藝術的趣味~

const colors = '26f0f1-bd93bd-f2edeb-ffdd4a-fabc2a'.split('-').map(a=>`#${a}`);
const colors2 = '0b3954-bfd7ea-ff5a5f-c81d25-44ffd1-6153cc-a60067-961d4e'.split('-').map(a=>`#${a}`);
var canvasTexture;
function preload(){
  canvasTexture = loadImage("canvas.jpeg")
}

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

function draw() {
  translate(width/2, height/2);
  noStroke();
  fill('#3a3b47');
  rect(0,0 ,width,height);
	
  push()
    // blendMode(SCREEN);
    for(var o=0; o<8; o++){
      rotate(PI/4);
			
      push();
        // 讓每一條觸手大小各異
        scale(sin(i/5+o/5)/20+0.8);
				
        let useColors =([colors, colors2][int(o%2)])
        for(var i=0;i<20;i++){
          translate(0,-30);
          rotate(sin(i/((sin(frameCount/10))/2000+0.1)+frameCount/100)+o/80);
          // 使用pow() 讓大的更大,小的更小
          scale(pow(noise(i,o,frameCount/100), 1.2)*0.5+1);
          fill(useColors[i%useColors.length]);
					
          push();
            let useWidth = 50*noise(i,o+5000)+20;
            scale(sin(i/5+o/50)/5+0.2);
            rotate(-PI/4*3);
            rect(75,0,200+noise(i/40,o/40)*500,useWidth,useWidth);
            rotate(PI/4*2);
            rect(75,0,100+noise(i,o)*100,useWidth,useWidth);
          pop();
          // 增加小點點
          for(let k=0; k<8;k++){
            let useSize = 10*noise(k,50000)
            fill(useColors[k%5]);
            ellipse(noise(k+frameCount/100)*50,noise(k+frameCount/200,5000)*50,useSize,useSize);
          }
        }
      pop();
    }
  pop()
	
  push()
    blendMode(MULTIPLY);	
    image(canvasTexture, -width/2,-height/2)
  pop()
}
<珊瑚嘉年華>作品步驟七:細修作品
<珊瑚嘉年華>作品步驟七:細修作品

八、作品輸出

作品完成後,接下來就是輸出啦!輸出時很重要的一件事情是 — 要先把輸出畫作的品質提升,因此要用的API是:

接著我們要決定存下這幅藝術畫作的哪個畫面。程式藝術雖然是由創作者產出的作品,但它總會有某些時刻比較好看,因此當那些時刻出現時我們要把畫面存下來,這邊使用到的 API 是:

  • mousePressed(): 滑鼠點擊時
  • save():儲存畫面
function mousePressed(){
  save();
}

九、額外添加細節

儲存圖片之後,如果有什麼靈感也都可以再調整作品,像是點點上加入一些線條等等 (不過有點耗電腦效能,請自行斟酌使用)

const colors = '363636-242f40-cca43b-e5e5e5-ffffff'.split('-').map(a=>`#${a}`);
const colors2 = 'ffcb3d-2b2d42-8d99ae-edf2f4-ef233c-d80032'.split('-').map(a=>`#${a}`);

// 26f0f1-bd93bd-f2edeb-ffdd4a-fabc2a
// 0b3954-bfd7ea-ff5a5f-c81d25-44ffd1-6153cc-a60067-961d4e

var canvasTexture;
function preload(){
  canvasTexture = loadImage("canvas.jpeg")
}

function setup() {
  createCanvas(1000, 1000);
  background(400);
  pixelDensity(2);
  fill(0);
  rect(0,0 ,width,height);
  rectMode(CENTER);
}

// 按下儲存
function mousePressed(){
  save();
}

function draw() {
  translate(width/2, height/2);
  noStroke();
  fill('#3a3b47');
  rect(0,0 ,width,height);
	
  push()
    // blendMode(SCREEN);
    for(var o=0; o<8; o++){
    rotate(PI/4);
			
    push();
      // 讓每一條觸手大小各異
      scale(sin(i/5+o/5)/20+0.8);
				
      let useColors =([colors, colors2][int(o%2)])
      for(var i=0;i<20;i++){
        translate(0,-30);
        rotate(sin(i/((sin(frameCount/10))/2000+0.1)+frameCount/100)+o/80);
        // 使用pow() 讓大的更大,小的更小
        scale(pow(noise(i,o,frameCount/100), 1.2)*0.4+0.9)
        fill(useColors[i%useColors.length]);
					
        push();
          let useWidth = 50*noise(i,o+5000)+20;
          scale(sin(i/5+o/50)/5+0.2);
          rotate(-PI/4*3);
          rect(75,0,200+noise(i/40,o/40)*500,useWidth,useWidth);
          rotate(PI/4*2);
          rect(75,0,100+noise(i,o)*100,useWidth,useWidth);
        pop();
        // 增加小點點
        for(let k=0; k<8;k++){
          let useSize = 10*noise(k,50000)
          fill(useColors[k%5]);
							
          // 加上點的線條
          stroke(useColors[k%5]);
          line(0, 0, noise(k+frameCount/100)*50,noise(k+frameCount/200,5000)*50);
          noStroke();
          ellipse(noise(k+frameCount/100)*50,noise(k+frameCount/200,5000)*50,useSize,useSize);
        }
      }
      pop();
    }
  pop()
	
  push()
    blendMode(MULTIPLY);	
    image(canvasTexture, -width/2,-height/2)
  pop()
}
<珊瑚嘉年華>加上線條後的完成品

十、作品命名、發布、與構思搭配文案

圖片儲存下來後,接著便是構想作品的名稱,並為作品搭配能相呼應的一段文字。由於作品充滿絢爛的色彩,又有點像是海底生物一樣隨波擺盪,所以老闆決定將它命名為<珊瑚嘉年華>,並搭配它的顏色與整體感受加了一段文字:

又變得更熱了,連回憶都開始白化,
小丑魚永遠的離開了,沒有了他的珊瑚,
其實也是只剩多彩的空殼了吧,
畢竟還是群居的動物離不開彼此,
卻走散僅留下了時間的遺跡。

結語

這次帶大家從零到一體驗了生成式藝術的創作過程。從一開始只是腦中有 V 字型的靈感,經過一系列的調整與操作,最終才產出<珊瑚嘉年華>這個作品,讓我們快速回顧一下<珊瑚嘉年華>的創作過程:

  1. 從平日蒐集的藝術素材中發想靈感,決定做一個「V字型、輻射狀、往外擴張」的圖案。
  2. 使用 P5.js 先繪製出單一個 V 圖案。
  3. 使用迴圈與位移的API,將 V 圖案複製並形成放射狀的圓圈。
  4. 參考藝術素材或配色網站,將圖形搭配上色彩。
  5. 增加材質、變化、顏色搭配、動態等細節修飾與調整,來提升作品質感。
  6. 大膽的嘗試各種細節調整,一邊試一邊看自己喜歡的風格。
  7. 作品命名、輸出、發佈與文案撰寫。

藝術創作的有趣之處在於它有無數可能與千萬種解讀,在這個過程中,每一次的細節調整都賦予這幅創作不一樣的感受,也能看到這個作品慢慢的演化成果,最後再決定這個作品想成為什麼樣子。這次的直播創作透過逐步的調整以及一些大膽嘗試,創造出許多意想不到的感受。

藝術很多時候不僅反映當下的心情狀態,也能透過創作的過程突破自己的舒適圈,或是療癒自己的內心。所以不必糾結於該如何寫出完美的作品,直接照著老闆的教學上手試一試吧,也許在嘗試的過程中,會迸發出意料之外的藝術品!這邊附上本次範例的成品<珊瑚嘉年華>,提供大家在開發時參考。

看到這裡,你對 Creative Coding 更有興趣了嗎?
歡迎加入互動藝術程式創作入門(Creative Coding)線上課程,課程中你可以認識程式與互動藝術產業應用,開啟對工程跟設計的想像,學會使用 p5.js 開發互動介面,整合繪圖、音訊、視訊、文字、3D、互動與機器創作完整的作品,並將創作輸出應用在個人品牌或網站、主視覺或海報,甚至互動裝置、遊戲與教材製作等場景,讓你對進修的資源與路線更有方向。

此篇直播筆記由幫手 金金 協助整理

墨雨設計banner
PHP Code Snippets Powered By : XYZScripts.com