1.9 開始第一幅“碼繪”——掌握大殺器”迴圈“,一招搞定百千萬個懵逼臉
阿新 • • 發佈:2019-01-04
引言:重複與美
這一節裡,我們將要學到一項強大的技能——迴圈。 有了迴圈,我們就能夠指揮計算機幫我們去做大量重複性的事情。 直覺上,提到“重複”,往往聯想到枯燥乏味。的確,從操作而言,重複性地做單調乏味地任務繪讓人感到煩躁不安。 然而,重複卻又是不可避免的。而且,很有有趣的東西也是通過重複操作實現的。 在繪畫中,重複性也體現得非常多。並且相當多的畫作都是通過“重複”來體現其趣味性。 為此,我們先賞析一些畫作。埃舍爾
這一幅是荷蘭著名畫家埃舍爾的作品。 從它的結構可以明顯看出,這就是將平面空間分割成了重複的結構。實際上每一塊貼磚都是完全一樣的。
這幅作品在重複中增添了一定的變化,這種變化製造了強烈的趣味感,讓觀賞者總有一種好奇心,想去搞清楚它的規律。
這幅作品在重複中增加了尺度的變化,它實際上是一幅“分形“(fractals)圖案。
草間彌生
下面再看看怪婆婆草間彌生的作品。這幅照片中,她的服飾/飾品/盒子/桌面/背景全都是她本人的標誌性圖案”波點“。 她作品的最大特色就是不斷重複的”波點”。然而,仔細觀察,其實每一樣樣物品上的波點都有所不同,波點的形狀/顏色/排列方式都有所變化。通過這些重複中的變化,將最簡單元素“點”構成了豐富的形態。 再看其它作品,雖然都是“波點”,都是重複,但卻樣樣不同!各有各的趣味。
梵高
上述兩位都是搞“圖案”的。圖案也是很容易聯絡上“重複”一詞。但是,在表意性繪畫中,重複也同樣重要。仔細觀察它們,可以看出,梵高也是一位善用“重複”的大師。他喜歡用重複的圖案來填充平面區域,他喜歡用重複的筆觸來表現物件。 但是,他在重複的過程中,卻注入了強烈的即興表現。他的每一個筆觸都有所不同,其中既有他主觀的控制,也有他當時的情緒/下意識/動作的不確定性。
分形藝術
近幾十年來,還有一門專門運用”重複“的美術流派——分形藝術。 下面時幾幅分形藝術圖案。另外附一個程式驅動的動圖: 仔細看這些圖片,發現它們的美感完全來自於重複,而且主要是兩種特徵:1.區域性和整體重複;2.重複中略有變化。
Craig Mullins
可別以為只有非寫實繪畫才喜歡重複。下面這位搞電腦繪畫的,風格方面主要時寫實的。但又在寫實中加入了強烈的寫意性。觀察這幅巨集大的場景,可以發現,景觀結構都是重複的:道路/燈/遠處的建築物/建築物的細節部件等等。但在這種重複的有序結構中,整體上存在一種變化的節律,而且重複的細節結構也包含變化,例如每一個燈都略有不同。
在這一幅《狙擊手》作品中,也存在大量重複結構,而且他的筆觸其實也是重複的。同樣的,這些重複性中由融入了節律和變化,從而製造了極大的豐富性。
第四維上的重複
第四維即時間(根據愛因斯坦相對論),在時間上的重複,在傳統靜態繪畫中是不可能實現的,但用程式設計就可以做到,請看下面作品:
先看靜止狀態:
怎麼樣,很無聊吧。。。
下面再看看動起來的樣子:
是否感到突然就有了耐人尋味的趣味?
這麼比較,是希望讀者明白,可以將動態看作一種全新的“媒介”,它可以用於表現以往的靜態構成方式所無法表達的美感。
看了這麼多例子,相信大家也明白了,重複本身就是一項高階的繪畫手法,只要運用得當,可以製造出極大的豐富性/特殊的風格/引人入勝的趣味感。 這裡,筆者總結一下用重複製造“美”的基本法則: 雷同的重複導致無聊,變化的重複製造美。 然而,重複雖然很棒,但是要操作重複卻又是一件很惱火的事情。 好訊息是,現在有了計算機,有了這個”俯首甘為孺子牛“的勞模,我們就有了更好的駕馭”重複“的幫手了,計算機最擅長的就是幹這種重複的勞動。 為了讓計算機聽命於我們,我們必須要學會給他下命令,也就是我們即將要學會的強大技能——迴圈。用while迴圈來繪製懵逼臉的頭髮
迴圈有幾種寫法,最簡單的即while迴圈。 我們先直接用它來改造之前的drawConfuseFace()函式,用其實現重複繪製一簇頭髮:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
// 函式setup() : 準備階段function setup() { // 建立畫布,寬度640畫素,高度480畫素 // 畫布的座標系統為,左上角座標為(0,0), // x方向水平向右,y方向垂直向下,單位畫素 createCanvas(600,400);}// 函式draw():作畫階段function draw() {// 在數百哦位置畫懵逼臉 drawConfuseFace(mouseX,mouseY,200,0.4,0.2,0.3);}// 畫懵逼臉function drawConfuseFace( posX, posY, // 臉部中心位置 faceSize, // 臉部尺寸 scaleMouth, // 嘴巴尺度比例,相對於臉部尺寸 scaleLEye, // 左眼尺度比例, 相對於臉部尺寸 scaleREye) // 右眼尺度比例, 相對於臉部尺寸{ // -------------- 1 畫臉 --------------- fill(255);// 填充白色 ellipse(posX,posY,faceSize,faceSize);// 圓圈 // -------------- 2 畫眼睛 --------------- // 2.1 計算眼睛相對於臉中心點的偏移量 var EyeOffsetX = 0.2 * faceSize; // 眼睛橫向偏移量為臉部尺寸的0.2倍 var EyeOffsetY = 0 * faceSize; // 眼睛縱向偏移量為臉部尺寸的0倍 // 2.2 計算眼睛尺寸 // 左右眼尺寸 var LEyeSize = faceSize * scaleLEye; var REyeSize = faceSize * scaleREye; // 左右眼珠尺寸 var LIrisSize = LEyeSize * 0.4; var RIrisSize = REyeSize * 0.4; // 2.2 畫出左眼 fill(255);// 填充白色 ellipse( posX-EyeOffsetX, // 臉的中心位置向左偏移EyeOffsetX posY+EyeOffsetY, // 臉的中心位置向下偏移EyeOffsetY LEyeSize, LEyeSize); // 2.3 畫出右眼 fill(255);// 填充白色 ellipse( posX+EyeOffsetX, posY+EyeOffsetY, REyeSize, REyeSize); // 5 左眼珠 fill(0);// 填充黑色 ellipse( posX-EyeOffsetX, // 位置與左眼一樣 posY+EyeOffsetY, LIrisSize, // 尺寸則採用比左眼小的尺寸 LIrisSize); // 6 右眼珠 fill(0);// 填充黑色 ellipse( posX+EyeOffsetX, posY+EyeOffsetY, RIrisSize, RIrisSize); // -------------- 3 畫嘴巴 --------------- // 3.1 計算嘴巴相對於臉部中心位置的偏移量 var MouthOffsetX = 0.0; var MouthOffsetY = 0.3*faceSize; // 3.2 計算嘴巴尺寸 var MouthWidth = faceSize * scaleMouth; var MouthHeight = MouthWidth/2.0; // 3.3 畫出嘴巴 fill(255); // 填充白色 ellipse( posX + MouthOffsetX, posY + MouthOffsetY, MouthWidth, MouthHeight); // -------------- 4 畫頭髮 --------------- var offsetX01 = -0.3; // while(bool Condition){}: // 當條件滿足時,就執行{}內容,然後再判斷()的條件 while(offsetX01<0.4) { drawOneHair(posX,posY,faceSize,offsetX01); // 警戒:必須要讓while()括號中的條件會變成false,否則,// 就會形成死迴圈,程式陷入永世輪迴,// 不斷地執行{}中的語句而無法退出。 offsetX01 += 0.1; // += 運算子用途:A+=B 等價於 A=A+B; } }// 繪製一根頭髮function drawOneHair( faceX,faceY, // 臉的中心位置 faceSize, // 臉的尺寸 offsetXOnFaceSize) // 頭髮X座標的的偏移量,以臉部尺寸為單位尺寸{ // ------------- 1 計算尺寸和位置 ---------// // 頭髮相對臉部中心的Y偏移量 var HairOffsetY = faceSize * 0.3; // 計算X偏移量 var offsetX = offsetXOnFaceSize * faceSize; // 頭髮長度 var HairLength = faceSize * 0.4; // --------------- 2 畫頭髮 --------------- |