# P5.js 學習之路 ## Day1 - 在開始之前 ### 前言 Hi,大家好,我是從新手工程師CC,學習前端的時間約兩年,遇到了很多問題(坑?)也都慢慢找到方法解決,越來越有解bug經驗了。不過在演算法上面還是有點吃力,不但沒有受過正式訓練,也缺乏想像力,因緣際會和同事一起糾團買了P5.js線上課程,整個程式回饋感超濃厚的!希望大家也可以透過幾何圖形一起學程式~ ### 主題與目標 本次鐵人賽會教大家一步一步使用p5.js,製作出隨機、獨一無二、具有動態效果的生成式藝術。30天的安排內容大部份會講到函式的使用方法,並針對2D為主,也會有幾天是實作演練,算是初級的課程 別擔心~我也是小菜菜一枚,大家可以放寬 心跟著我慢慢來就好了~~ ### 規劃 * 在開始之前 * 生成式藝術介紹 * 介紹編碼工具P5.js 與線上開發平台 OpenProcessing 與 P5.js editor * 基礎程式架構介紹 * 定位座標 * 畫個形狀吧,有沒有這麼簡單 * 上色處理,顏色模式介紹 * 上色處理[加開場],那些顏色的物件函數 * 體驗P5.js提供的幾種隨機模式 * p5.js中的條件、迴圈、變數 * 實作範例 - 製作第一個patten * 實作範例 - 製作第一個patten - 2 * preload - 文字變化 * 建立多個畫布與事件處理 * 線段的操作與不規則形狀 * 進階色彩設定 blendMode() * 進階色彩設定 lerpColor()以及 filter * p5.js 中的漸層 - 1 * p5.js 中的漸層 - 2 * 陰影效果與霓虹燈 * preload - 圖像引用與定位 * 實作範例 - 來個Netflix and Chill * 遮罩的三種方法 - 1 - erase() noErase() * 遮罩的三種方法 - 2 - mask() * 遮罩的三種方法 - 3 - Canvas原生方法 * 圖像的像素拆解與組合利用(上) - 1 * 圖像的像素拆解與組合利用 - 2 * 向量與它的函數家族 * 利用class生成物件 - 1 * 利用class生成物件 - 2 * 鐵人完賽~ * ...... ### 階段性成果 預計到第9天,各位就可以開始自由揮灑內心中的設計師之魂了 ![](https://i.imgur.com/Yku3xtd.jpg) ### 小結語 謝謝大家點近來閱讀第一篇,在網頁美化的路上一起努力吧~ ## Day2 - 生成式藝術介紹 ### 先來一點文謅謅的介紹 生成藝術是一種新媒體藝術風格,也可以稱為程式藝術、互動藝術或生成設計,是現在十分引人注目的設計手法,在世界各地迅速引起話題,威尼斯雙年展甚至在今年規劃了程式藝術的展館,台灣也陸續舉辦吳哲宇《混沌實驗室》、《Hello Ouchhh AI數據藝術展》等相關展覽。生成藝術從現代藝術中汲取靈感,以程式為媒介來創作,拓展藝術無限的可能,藉由程式的隨機性創造出獨一無二的作品,結合藝術家的審美品味及靈感,與程式的規模化以及規則性,將靈感變成可視的藝術。例如透過讀取歌手聲音製作成動態背景、偵測舞者人體動作行為變化進行後製產生互動投影、根據生日等個人資料進行即時演算轉換成客製化的卡片,這些都屬用程式藝術能應用的範疇。 生成式藝術賦予使用者與其互動以及具有關聯性之連結,呈現在硬體上,產生完全獨特的結果,達成給予每個使用者專屬於自己、客製化的豐富體驗。 --- 以上白話翻譯就是以程式為媒介所創作出來的藝術品,若結合隨機性創作,每張產出的藝術品將擁有風格一致且獨一無二的特性。生成式藝術大部分為使用幾何圖案或者線段的波普藝術,但也有擬真型態的作品,只是較為少見。 ### 作品範例 展期到9/18的 《Hello Ouchhh AI數據藝術展》是非常棒的生成式藝術,也有與人互動的作品展出,如果還有機會的話大家可以趕快把握去看一下喔~ * 《Hello Ouchhh AI數據藝術展》,土耳其團隊 [Ouchhh](https://ouchhh.tv/) 的作品 ![](https://i.imgur.com/qF5h0oK.gif) ![](https://i.imgur.com/VDqxDcd.gif) * [Gabriele Generative Art](https://linktr.ee/GabrieleGenArt) ![](https://i.imgur.com/45AQY6C.jpg) ### 目前常見的應用範圍 目前使用於展覽、展場布置、演唱會背景布置、藝術表演(音樂會或者舞蹈表演)等文藝活動,或者運用在NFT上、被收藏為藝術品比較多,在國內外也有人在討論是否有其他的應用範圍,不過使用場景稍微比較限縮一點,要說前端網頁的運用的話,是可以做為設計美化的素材(但演算法挺耗效能的)。 ### 可供參考的線上作品展廳 大家可以看看以下這些網站,也可以對生成式藝術所執行的方向有點概念 > [生成式藝術彙整| Creative Coding TW - 互動程式創作台灣站](https://creativecoding.in/category/inspiration/%E7%94%9F%E6%88%90%E5%BC%8F%E8%97%9D%E8%A1%93/) 吳哲宇老師的網課也教學得非常仔細 > [互動藝術程式創作入門 (Creative Coding)](https://hahow.in/courses/5d1ba52a0d5f3b0021dbb996/main?item=5eeb4a4978b256a15839b592) 另外在國外頗知名的生成式藝術交易平台 > [Art Blocks](https://www.artblocks.io/) > [fxhash](https://www.fxhash.xyz/) > [Async.Art](https://async.art/zh) ## Day3 - 介紹編碼工具P5.js 與線上開發平台 OpenProcessing 與 P5.js editor ### 使用工具介紹 目前開發生成式藝術的語言有很多,Processing、Python、R、TouchDesigner、Max MSP等族繁不及備載,其中Processing是Java的基底,這是原先Processing 的 JavaScript 移植版,ㄈ我個人推薦(也是目前使用語言) P5.js,。 P5.js是一個使用在進行創意編碼的的JavaScript函式庫,是免費的開源程式,也有提供document以及 [網站](https://p5js.org/),在查找的時候非常方便。基本上寫作方式與JavaScript別無二致,只是把canvas的相關API包成簡易、方便使用的函式,更把數學物理等繁雜的函示封裝好,讓駛近創作的時候可以更專注在創意上。 ### 線上編輯平台 官方提供的開發平台,整合官方範例和其他創作者的程式資源 > [P5.js Editor](https://editor.p5js.org/) 滿主流的開發平台,超級多大神在上面秀作品秀技術XD,版面做的很像藝廊很漂亮~如果使用processing在上面也可以通喔 > [Openprocessing](https://openprocessing.org/) #### 1. P5.js Editor 先來看一下P5.js Editor的介面,左邊是程式碼區,右邊是執行結果 ![](https://i.imgur.com/gtNFiFI.png) 左上的區域有執行與暫停的按鈕,把Auto-refresh勾起來的話,每次更新程式就會自動執行 ![](https://i.imgur.com/mcqe2Az.png) #### 2. Openprocessing 再來是Openprocessing,有提供搜尋作品的功能,還會在discover區時時更新世界各地創作者的美美作品,只要點選左上角的create a sketch按鈕,就可以開始做自己的第一幅作品囉! ![](https://i.imgur.com/4X8qCC2.jpg) 在sketch區域中可以選擇只看到代碼區或者只看到執行結果,播放與暫停按鍵在上方中間,右側有些設定可以調整外,如果需要上傳編輯用的圖片,也可以在這邊進行操作喔 ![](https://i.imgur.com/oPrsNyq.png) 如果希望程式與執行結果都可以看到的話,可以點擊書頁形狀的按鈕,這樣就可以開啟左側式程式區,右邊是執行結果的編輯樣式了 ![](https://i.imgur.com/nHYz3ka.png) ![](https://i.imgur.com/0el0wLv.png) ### 小結 以上就是接下來要使用的工具與平台介紹,當然各位如果希望可以有一些snippet或者程式可以上色的話,也可以用vscode開發喔,要看執行結果只要右鍵用live server開啟就好了 ## Day4 - 基礎程式架構介紹 打開線上編輯平台後,就會看到兩段預設開啟的程式碼,setup 和 draw,這兩段是最常使用的兩個函式 1. setup 只會被執行一次,用來設定執行動畫前的初始化流程 2. 在 setup 執行後,draw 這個程式就會不斷地被呼叫執行,canvas預設是每秒會自動跑 60 次 執行 60 次稱為幀率(fps),像是一般高品質動畫或者電影基本上使用超過 24fps 就足夠流暢了,可以使用函式 frameRate 來設置每秒幀數。不過演算法的寫法撼動化的風格速度等等解會影響電腦效能,實際上可能不一定達的到24fps。 下圖為範例程式代碼 ![](https://i.imgur.com/A1vlyhq.png) 可以看到程式當中有 ``` createCanvas(windowWidth, windowHeight); ``` 這段程式是用來設定畫布寬高,預設都是與視窗同寬同高。 ``` background(100); ``` 是設定顏色的函數,background(100) 表示設置畫布背景為灰階 100,相當於 background(100, 100, 100)。 P5.js有相當多的顏色模式可以使用,這後續會逐一講到。 ### 其他常用函式介紹 * frameCount() 目前已顯示的fps數量,在 setup 中為 0,draw執行後為 1 * frameRate() 用來設置每秒幀數 * print() 用來把需查看的數據寫入瀏覽器的控制台 * noLoop() 停止 p5.js 一直持續執行draw()中的程式 * width() 當前canvas畫布的寬度,與windowWidth指向對象不同 * height() 當前canvas畫布的高度,與windowHeight指向對象不同 以上是在一開始開發作品的時候,會常常使用到的函式,下一篇就會開始進入到創作動畫了~也謝謝大家今天的瀏覽喔 ## Day5 - 定位座標 canvas是整張畫布,而在上面要定位任何形狀、圖片、文字都需要使用到座標,座標的操作可以幫助物件定位,而HTML canvas是一的二維網格,起始點(0,0)位於左上角,往右延伸則x增加,同理往下延伸則y軸遞增。 x,y軸的方向如下圖 ![](https://i.imgur.com/dVHTrT4.png) 那如果我今天要定位一個點呢?我們先使用點來呈現定位位置,其實 **點** 是沒有被賦予形狀的,它只有位置,不過可以使用strokeWeight()函數更改點的大小,讓 **點** 有形狀可以利用。 點點的函式是 ``` point(x,y) ``` 外框粗細度函式 ``` strokeWeight(width) ``` ![](https://i.imgur.com/FmZ3ZT6.png) 可以看到我們定位了一個點點在x軸100,y軸200的地方。 另外可以利用width, height這些 canvas本身的寬高特性,並且結合程式語言的for迴圈,就可以製作出一條點點線 ![](https://i.imgur.com/v6wuaiP.png) ![](https://i.imgur.com/WHLgzn6.png) 甚至可以做一條斜線 ![](https://i.imgur.com/QojBhwY.png) ### 小結語 座標的操作在後續非常重要,延伸操作還可以製作有關連性的波浪、圓形,一樣謝謝大家今天的瀏覽,我們明天見~ ### REF https://shinainai.com/home/html5-canvas-tutorial3-coordinates https://www.coding.academy/blog/drawing-shapes-using-html5-canvas-part-2-drawing-a-rectangle ## Day6 - 畫個形狀吧,有沒有這麼簡單 今天要介紹P5.js中,幾種常見的形狀工具函式,前面有說過,生成式藝術最常見的類型大部分為波普藝術,像是幾何交疊,線段表現等等,因此形狀的利用在這當中也相當重要,以下就讓我們一步一步開始吧。 ### 幾何函式 * #### circle() 這邊是指正圓形,正圓形是一個簡單的封閉形狀。函式總共有3個API可以利用 ``` circle(30, 30, 20); //x軸,y軸,寬高 ``` ![](https://i.imgur.com/RlwAToe.png) * #### ellipse() 可以繪製橢圓形,寬度與高度可以不同。函式總共有5個API可以利用,前三個為x,y,寬,但在不填寫第四個參數的情況下,會默認高度跟隨寬度,而第五個參數是在繪製3D的時候才會用到,是為了指定構成橢圓周長的頂點數才設定的 ``` ellipse(56, 46, 55, 55); //x軸,y軸,寬, 高 ``` ![](https://i.imgur.com/Ui0wiVq.png) * #### line() 可以繪製線段,主要是指兩點之間的路徑,因此可以使用 strokeWeight()改變寬度 ``` line(x1,y1,x2,y2) //x起點,y起點,x終點,y終點, line(x1,y1,z1,x2,y2,z2) //x起點,y起點,z起點,x終點,y終點,z終點 ``` ![](https://i.imgur.com/sO3Jijw.png) * #### rect() 可以繪製矩形,因為也是封閉型狀,所以可以設定XY寬高就好,與橢圓形一樣,前三個為x,y,寬,不填寫第四個參數時,會默認高度跟隨寬度,第5-8個參數是用來設定左上角、右上角、右下角和左下角(順時針)的角半徑(弧度),可以想成是css中的border radius ``` rect(x, y, w, [h], [tl], [tr], [br], [bl]) //x軸,y軸,寬, 高 , 左上角, 右上角, 右下角, 左下角 ``` ![](https://i.imgur.com/NWMWdjm.png) * #### square() 可以繪製四邊形,四個點的xy指定是從右上角順時針或逆時針(端看第二個點設定的位置)進行,有WEBGL模式(3D)可以設定 ``` quad(x1, y1, x2, y2, x3, y3, x4, y4, [detailX], [detailY]) ``` ![](https://i.imgur.com/8oIcumY.png) * #### triangle() 可以繪製三角形,三角形是通過連接三個點創建的平面圖案,分別可以指定1至3的點的xy位置 ``` triangle(x1, y1, x2, y2, x3, y3) ``` ![](https://i.imgur.com/EGFYhZt.png) ### 應用 應用實例 ![](https://i.imgur.com/TcRpA14.png) ### 小結語 以上就是各式形狀的介紹與應用,謝謝大家今天的瀏覽喔~~ ## Day7 - 上色處理,顏色模式介紹 今天進入顏色模式的分享,會介紹到怎麼指定顏色模式,以及基礎的上色與相關操作 ### 顏色模式 顏色模式主要分兩種,分別為以下,默認模式為 RGB * RGB * HSB ### RGB模式 首先我們先來看看RGB模式以及上色的應用 ![](https://i.imgur.com/kUYw3fe.png) 在指定上色的時候可以用 color() 這個函數 ``` color() ``` * 當函數只放入一個數值的時候,如 color(255) , 他將返回灰階的色彩 * 放入兩個數值,如 color(255,255),他將被視為灰階 + Alpha 透明度 * 當指定三個值時,則會被解釋為 RGB 或 HSB 值。 * 當指定四個值時,則為 RGB 或 HSB 值 + Alpha 透明度。 > 注意: color()裡面也可以放入字串喔~,例如 '#fe700e'或者 'rgb(340,100%, 100%)',但再放入字串的時候就不支援放透明度了 當我們成功設定好顏色後,就可以得到一個有透明度的圓形 ``` function setup() { createCanvas(windowWidth, windowHeight); background(100); } function draw() { noLoop() let c = color(255, 201, 100, 40) fill(c) circle(100, 100, 20); } ``` ![](https://i.imgur.com/mJ1HPzf.png) 再來試試看使用字串得到的結果 ![](https://i.imgur.com/TwsOHu4.png) ### HSB模式 HSB模式是一個360度的環,有色相(hue),飽和度(saturation),彩度(value) ![](https://i.imgur.com/5i9cax9.png) ![](https://i.imgur.com/gJRJXO8.png) 那要如何設定成HSB模式呢? 我們可以使用 colorMode() 這個函式 ``` colorMode(HSB) ``` 這樣就設定好HSB模式了,但要注意在此之後,最大值就不是255了,而是360,設定好HSB模式之後的預設會是colorMode(HSB, 360, 100, 100, 1),只說色相一整圈,飽和度彩度與透明都最高 為了明顯看到顏色的變化效果,這邊使用到mouseX, mouseY兩個P5.js提供的函數,可以直接偵測到游標的座標定位,進而觀測到顏色跟隨滑鼠移動所做出的變化 那接下來我們就來實際看看範例吧 ``` function setup() { createCanvas(windowWidth, windowHeight); background(100); } function draw() { colorMode(HSB) fill(mouseX ,100,100) circle(mouseX, mouseY, 40); } ``` ![](https://i.imgur.com/DnTHAjY.png) ### 小結 以上就是顏色模式的簡單介紹,也謝謝大家今天的觀看~~ ### REF https://www.sprekelmeyer.com/file-prep-101-start-here/cmyk-color-mode/ https://nycdoe-cs4all.github.io/units/1/lessons/lesson_3.2 ## Day8 - 上色處理[加開場],那些顏色的物件函數 昨天講到了如何設定顏色以及 ### 顏色相關可以使用的物件 P5.js有提供一些物件給developer們開發使用,如下,默認是RGB模式,但也可以使用在HSB模式喔~ * setRed * setGreen * setBlue * setAlpha ### 範例 #### HSB + setRed() 假使我們今天寫了段程式如下,得到了一個紫色的圈圈,但希望紅色可以全部消除掉(變成藍色),並在一開始設定顏色模式為HSB ![](https://i.imgur.com/BzOFeTs.png) 於是我們可以進行以下的操作,我這邊畫了兩個圓,可以看到一開始沒有使用 setRed()的呈現和使用過得呈現 ![](https://i.imgur.com/OkGLCiE.png) #### RGB + setAlpha() 另外測試了使用 setAlpha() 的範例程式,要注意的是因為動畫會一直跑,也就是 frameCount 會不斷增加,所以透明度也會被疊加(ಥ﹏ಥ),所以這邊給了 noLoop(),讓它動畫暫停以方便顯現 ![](https://i.imgur.com/0CXDZJo.png) ### 顏色相關可以使用的函數 我把它分成這兩大類,第一大類型主要用於提取色素和飽和度,第二大類型用來提取飽和度和色相,至於為什麼分成兩類呢?我想大家應該很熟悉RGBA,可對RGB模式、HSB模式或者圖片操作,這也是之後可能比較常用到的函數,而二類相對少用,主要針對HSB。 --- 1. * alpha() * blue() * green() * red() --- 2. * hue() * saturation() --- 但用法是一樣的~都是使用來提取數值的,這樣講很玄妙模糊,我們直接來看看範例 #### red(), blue(), green()應用 下圖我們先提取了 color(195 ,210,100) 這個顏色的紅色數值,並且把這個數值單獨畫了一個方形在隔壁,中間也有console在瀏覽器上面,大家可以看到紅色數值是195 ![](https://i.imgur.com/sfPP45s.png) 以下是HSB 模式,大家可以發現提取出來的是RGB色的數值,也就是說第一大類的函數可以用在各種色彩模式下,返回紅綠藍的比例 像我這樣寫這一行直接填回去會變成指定HSB的色相(不同於RGB數值),請大家要特別注意 ``` fill(v, 50, 100) ``` ![](https://i.imgur.com/SNx5saF.png) #### hue() 下圖我們提取color(240, 210,100)的色調,可以看到返回240,也就是color中色相的數值 ![](https://i.imgur.com/OEku1Vm.png) #### saturation() 下圖我們提取color(300 ,60,40, 0.6)的飽和度,可以看到返回60,也就是color中飽和度的數值(0.6) ![](https://i.imgur.com/boOyA5t.png) ### 小結 有關顏色的眉角很多,也起來也嘮嘮叨叨的,但還是很謝謝大家今天的觀看 ## Day9 - 體驗P5.js提供的幾種隨機模式 p5.js 有提供一些隨機參數供我們在創作的時候可以利用,分別是 * randomGaussian * random * noise 但等等,隨機參數有什麼作用呢?什麼情況會用到隨機阿? 如果我們今天的作品需要加入一點不規則,而且要可以定義不規則的範圍,就可以使用到上面三個參數,像下圖我們想要做出大小不同,裡面留白也不一樣大的滿版方形,就可以帶入使用 ``` let colors= "072448/54d2d2/ffcb00/f8aa4b/ff6150".split("/").map(a=>"#"+a) let margin = 10; function setup() { createCanvas(displayWidth, displayHeight); frameRate(2); background(220); rectMode(CENTER) for(let x = margin; x < width; x += 100){ for(let y = margin; y <= height; y += 100){ r = random(colors); let rectSize = random(30,100) noStroke(); fill(r); rect(x+50,y, rectSize); fill(220) rect(x+50,y, random(6,28)); } } } function draw() { } ``` ![](https://i.imgur.com/7idax3k.png) ### random() 上面例子就是使用到了 random(),參數會返回一個隨機浮點數,最多可以塞兩個API,也可以都不給(會返回0-1之間的浮點數) ``` random() //return 0-1 ``` ``` random(1,20) //return 1-20之間 ``` ``` let code = ['java', 'js', 'ruby', 'golan']; let result = random(code); result 會出現陣列中隨機一名 ``` ### randomGaussian() 正常來說random 只會返回設定的最大與最小值之間,不會超過,也不會小於設定值,但如果我們需要一種浮動的常態分佈,我們就會用到randomGaussian(),它模擬高斯或一般分佈的隨機數,與random()不同的是,它大部分會浮動在第一個參數(標準值)上下,至於上下的範圍多少呢?我們可以用第二個參數設定(浮動值),返回偏離平均值的概率非常低,若不給與參數也是可以的,標準值會預設為0,而浮動值會自動落在1,來看看範例吧 ``` randomGaussian(100,20) ``` > 100 + 20 ,100-20 結果大部分會在120,80之間, 少數會超出120或少於80 ![](https://i.imgur.com/OvIlBTf.png) #### 範例 ![](https://i.imgur.com/gYAASKJ.jpg) ``` let circle1 = new Array(360); //360度 let circle2 = new Array(360); //360度 let hues = []; let nScl = 0.006; function setup(){ frameRate(4); createCanvas(windowWidth, windowHeight); background('#fff1e6'); for(let i=0; i<10; i++){ hues.push(random(360)); } colorMode(HSB, 360, 100, 100, 100); for (let i = 0; i < circle1.length; i++) { circle1[i] = floor(randomGaussian(120, 180)); //每條線的長度 大部分在120+-180之間 circle2[i] = floor(randomGaussian(0, 500)); } } function draw(){ if(frameCount >1) return background('#fff1e6'); translate(windowWidth / 2, windowHeight / 2); // console.log(PI, TAU) for (let i = 0; i < circle1.length; i++) { rotate(TAU / circle1.length); //PI 轉半圈 0.0087 //TAU 轉一圈 0.0174 //color let h = hues[int(noise(windowWidth*i*nScl , windowHeight*i*nScl ) * 10)];//color stroke('green'); strokeWeight(2) let dist1 = abs(circle1[i]); let dist2 = abs(circle2[i]); line(dist2, 0, dist1, 0); } } ``` ### noise() 可以看到前兩個隨機,都是返回完全不固定,沒有規律可言的 真!隨機數列,如果今天我們想要返回有規律的隨機呢?等等,這句話不會太累了嗎,隨機就隨機我還要辦固定勒,到底用在哪阿。像這樣的東西當然就是因為有需求所以產生,想想如果我們今天要畫海浪,自創的地形圖,就會用到noise了。它會返回該個坐標處的 Perlin 噪聲值。Perlin 噪聲是一種隨機序列生成器,它會產生自然有序、諧波的數字序列。 Perlin 噪聲本人長這樣,不要懷疑,它就是一個圖面,而且有Z軸可以塞 ![](https://i.imgur.com/m2cutqq.png) 通常可以給與x,y,z三個座標,三個坐標之間的差異越小,產生的噪聲序列就越平滑。通常0.005-0.03 最適合大多數應用。 ``` let ranges = 100; function setup() { createCanvas(windowWidth, windowHeight); background(100); } function draw() { background(0); noFill(); strokeWeight(2); for (let i = 0; i < ranges; i++) { let paint = float(map(i, 0, ranges, 0, 255)); stroke(paint); beginShape(); for (let x = -10; x < width + 11; x += 20) { let n = float(noise(x * 0.001, i * 0.01, frameCount * 0.02)); let y = float(map(n, 0, 1, 0, height)); vertex(x, y); } endShape(); } } ``` ![](https://i.imgur.com/BUlr80Q.png) ### 結語 開始累了,才第九天QQ,我要偷討拍一下QQQ ## Da10 - p5.js中的條件、迴圈、變數 p5.js 是基於js創設的函式庫,因此也擁有了程式語言的特性可以使用,可以設變數、立條件立flag、使用迴圈來取代重複性的工作。兼天會與大家分享利用寫程式的技巧來輕鬆創作圖騰。(其實我是假設大家都會寫一點基本程式QQ,請不要砍我) ### 變數 我們可以使用變數來統一管理會重複出現、且影響範圍一致的數值,像下面這張範例一樣,使用 scope1 與 scope2 來管理圓圈在產生時的隨機範圍,不但是視覺上不會有太多雜七雜八的數值,改起來也方便~ ![](https://i.imgur.com/1RAYzsO.png) ### 條件 同樣上一張範例也可以看到我設定了條件來判斷要畫大圈圈還是小圈圈,條件是 mouseIsPressed 這個p5提供的api,意思是指說當游標按下去的時候會產生大圈圈,否則根據滑鼠位置隨機產小圈,程式的部分如下提供給大家 ``` let scope1 = 100; //大圓圈隨機產生的位置的範圍 let scope2 = 30; //小圓圈隨機產生的位置的範圍 function setup() { createCanvas(windowWidth, windowHeight); colorMode(HSB) background('white'); } function draw() { if(mouseIsPressed){ noStroke(); fill(random(360),70,40,random(0,1)); circle(random(mouseX-scope1, mouseX+scope1), random(mouseY-scope1, mouseY+scope1), random(20, 48)); }else{ stroke('#c0c8d2') noFill() circle(random(mouseX-30, mouseX+30), random(mouseY-30, mouseY+30), random(5, 18)); } } ``` ### 迴圈 剛開始可以利用 width, height來操作迴圈,用線段或者幾何形狀來做出具有重複性藝術美感的圖案 ![](https://i.imgur.com/V8YP1b5.png) ``` let margin = 100 function setup() { createCanvas(800,800); colorMode(HSB, 360, 100, 100); background(100); noLoop() noFill() } function draw() { for(let y = margin; y <= height- margin; y+=25){ line(margin,y,width-margin,y) for(let x = margin; x <= width -margin ; x+=25){ line(x,margin,x,height-margin) } } } ``` ![](https://i.imgur.com/hBNB7I6.png) ``` function setup() { createCanvas(800,800); colorMode(HSB, 360, 100, 100); background(100); noLoop() noFill() } function draw() { for(let y = 0; y <= height - 25; y+=25){ for(let x = 0; x <= width-25; x+=25){ circle(x,y,25); line(x,y,x,y) } } } ``` ### 小結 條件、迴圈、變數的利用在執行的時候是非常重要的方法,可以組合成千變萬化的演算法,大家可以試試看去找一些簡單的幾何形狀範例圖片模擬一下,謝謝大家今天的收看 ## Day11 - 實作範例 - 用p5.js製作第一個pattern 今天我們要來小總結一下有提過的函數,並且來試試看組合變化,我們已經用過幾何形狀、定位系統、顏色函數與隨機模式,納今天我們就來試試看產出一個小波普藝術吧 ### 題目 下面這張來自pinterest的設計圖,我們擷取一小部分作為題目 ![](https://i.imgur.com/2qWYkAD.png) 黃色圈起來的地方 ![](https://i.imgur.com/ZLiXSvc.png) --- ### 解析 拿到題目我們先不用緊張,首先我們可以來觀察一下。主要可以分三個部分,逐一突破就行了 * 底圖 * 色塊 * 白點 顏色可以用google tool 吸顏色 ![](https://i.imgur.com/W6EelPN.png) 底圖,色塊顏色準備好了以後 我們先來把基本設定準備好,不需要動畫,也不要邊框 ``` function setup() { noLoop() createCanvas(windowWidth, windowHeight); noStroke() } ``` 接下來背景上色 ``` background(251,146,251); ``` 色塊的部分是一個三角形一個矩形,分別定位在右邊及下方 ``` fill(244,166,175) triangle(width,height/5,width,height, 0,height) fill(243,139,170) rect(0, height/4*3, width, height/4); ``` 我們就得到了完整的背景了~ ![](https://i.imgur.com/VB2PcFk.png) 在白色點點得部分可以使用迴圈來操作,先產出重複的規則白色塊 ``` for (let v = 0; v < height; v+=100) { for (let k = 0; k < width; k+=30) { for(let i = 0; i< width ; i+=10) { rect( k , height /2 +i , 20,5) //下半部 rect( k, height /2 -i , 20,5) //上半部 } } } ``` ![](https://i.imgur.com/TCQzebm.png) 再利用for迴圈中的變化值給予變化條件,就可以完成了~~~ ``` for (let v = 0; v < height; v+=100) { nn = 0 for (let k = 0; k < width; k+=30) { bb = 0 for(let i = 0; i< width ; i+=10) { bb += i/10; nn = ((k*i)/(height)) * (map(height, 0, width, 2, 4)) rect( k , height /2 +i +bb + nn , 20,5) //下半部 rect( k, height /2 -i -bb - nn, 20,5) //上半部 } } } ``` ![](https://i.imgur.com/xonDbL6.png) 完整的程式碼如下 ``` let nn = 0; let bb = 0 function setup() { noLoop() createCanvas(windowWidth, windowHeight); noStroke() } function draw() { background(251,146,251); fill(244,166,175) triangle(width,height/5,width,height, 0,height) fill(243,139,170) rect(0, height/4*3, width, height/4); fill('white') for (let v = 0; v < height; v+=100) { nn = 0 for (let k = 0; k < width; k+=30) { bb = 0 for(let i = 0; i< width ; i+=10) { bb += i/10; nn = ((k*i)/(height)) * (map(height, 0, width, 2, 4)) rect( k , height /2 +i +bb + nn , 20,5) //下半部 rect( k, height /2 -i -bb - nn, 20,5) //上半部 } } } } ``` ### 小結 下一段我們就會進入加入隨機值的操作了喔~!謝謝大家今天的觀看 ## Day12 - 實作範例 - 用p5.js製作第一個pattern - 2 ![](https://i.imgur.com/7HXs7GA.jpg) 昨天我們講到了利用迴圈製作有規則的波普小作品,今天我們要來加入隨機值操作看看,用昨天的程式來稍微改造一下 1. 首先設定的部分我想大家應該都沒有什麼問題,把noStroke(),noLoop() 等等設定好 2. 另外我使用了兩個從[配色網站](https://colors.muz.li/)上取出的色列 3. 把底色的彩色點點圖用一個function()包起來 4. 在畫點點的時候,可以隨機上色 5. 點點的距離可以用noise來營造出不規律中帶有一點規律的隨機感 6. 在draw()裡面大家可以放上自己歡的形狀喔 ``` let nn = 0 let bb = 0 let palette2 = ["#2E294E", "#541388", "#F1E9DA", "#FFD400", "#D90368"]; let palette = ["#3AC3FD", "#2988B1", "#FD3AA3", "#B12972", "#FDE33A"]; function setup() { createCanvas(windowWidth, windowHeight); colorMode(HSB); noStroke() noLoop() start() } function draw() { colorMode(RGB); let cc = color(255,215,0) cc.setAlpha(200); fill(cc) push() rotate(-0.25); rect(1150, 180, 800, 550) pop() let CCCC = color('#292a73') CCCC.setAlpha(170); fill(CCCC) triangle(640, 440 ,1200, 1000, 180, 600) } function start(){ //用同一章畫布 for (let k = 0; k < width; k+=20) { bb += k/10; for(let i = 0; i< width ; i+=10) { let colorBall = parseInt( random(0, 5)) fill(palette[colorBall]) let noiseTemp = noise(0.03 * i, 0.03 * i) let noiseTemp2 = noise(0.04 * i, 0.05 * i) let newX = map(noiseTemp,0,1, 0 ,width) let newY = map(noiseTemp2,0,1, 0 , height) ellipse( newX , newY - bb , k/random(20, 40)) //上半部 ellipse( newX , newY + bb , k/random(20, 40)) //上半部 } } } ``` ### 小結 身為排版苦手的我,覺得上層上什麼都不對,最後只好~~自暴自棄~~隨意地放了兩個幾何,大家有覺得好看的排版可以在跟我分享一下XD 是良葛格!!! 謝謝大大的留言和餵食資源,寫的超級好又很完整根本就是大神 這個留言我要做成NFT跟朋友炫耀>"< ## Day13 - preload - 文字變化 今天我們要講到文字變化了,耶~~~~ p5.js彈性非常大,揉合度也很高,可以把圖檔字形通通都丟進去做變化,load文字的方式非常非常簡單 需要加載字形的話,首先把文字檔載下來,然後用loadFont()丟進 preload() 裡面就好了ㄏㄏ,乍看之下是不是滿簡單的呢~ preload() 需要在setup ()之前被調用,是以非同步(異步加載)的方式事先加載外部文件,像是圖片和文字等等,只要定義了preload() ,setup()將等到其中的文件都完成加載後才執行。 可能有人會問,不能寫在一起嗎?放在setup不行嗎?其實流程可以這樣解釋,如果我們在setup來引入外部文件,在文字或圖片載完之前,可能就執行完setup呼叫draw了,這樣在畫圖上會攢生很嚴重的問題,所以我們要使用preload(),而除了loadImage、loadJSON、loadFont、 loadStrings等這些有特別與p5進行註冊函式之外,其他都不能在 preload 中。 好,大概解釋差不多了~那我們來看一下程式結構吧,下面範例使用loadFont()函式來引入文字字體,在引入文字的時候只要是用相對路徑,但其實絕對路徑也行 ### 引入程式結構 ``` let font; function preload(){ font = loadFont('index18/TextMeOne-Regular.ttf'); } ``` ### 整體結構 它的整體結構大概會長這樣 ``` let font; function preload(){ //引入文字 font = loadFont('index18/AlexBrush-Regular.ttf'); } function setup(){ //設定字體大小 //設定整個畫布使用引路的字形 } function draw(){ //放上文字,用文字作畫做動畫 } ``` ### 實作範例 這裡用到了以下函數 * textFont() 使用什麼字形 * textAlign() 文字對齊 * textSize() 文字大小 * textWidth() 取得文字字串的寬度 * text() 上文字的函數,需標註文字內容與位置 ![](https://i.imgur.com/4bhlBjg.png) ### 小結 文字也可以做成圖騰的一部分喔~大家可以稍微試試看文字的其他變化