[MetalKit]28-Using-MetalKit-part-2-3^2使用MetalKit18

本系列文章是對 metalkit.org 上面MetalKit內容的全面翻譯和學習.git

MetalKit系統文章目錄github


是的,正如標題所示,咱們又有一個和數學有關的帖子了.有一天我在想,當咱們通勤時間長達一小時左右,沒有互聯網沒有筆記本電腦,只有一臺iPad時,咱們能作什麼.幸運的是,如今iPad有了神奇的Swift Playgrounds應用了.swift

讓咱們以一個全新的playground開始,只運行基本的計算內核.由於當前版本的Swift Playgrounds不支持編輯Auxiliary Source Files輔助資源文件,就是咱們一般存放SwiftMetal文件的地方,因此咱們將不得不在playground主頁面寫代碼,還好不太複雜.咱們要作的是修改咱們的MetalView初始化器,給它輸入一個額外的參數-咱們的着色器/內核代碼.而後咱們開始生成代碼,只需給這個長的字符串添加幾行就好.函數

讓咱們以一個亮藍色的背景顏色開始:post

let shader =
"#include <metal_stdlib>\n" +
"using namespace metal;" +
"kernel void k(texture2d<float,access::write> o[[texture(0)]]," +
" uint2 gid[[thread_position_in_grid]]) {" +
" float3 color = float3(0.5, 0.8, 1.0);" +
" o.write(float4(color, 1.0), gid);" +
"}"
複製代碼

若是你如今運行playground,輸出圖像會像這樣:學習

chapter18_1.png

下一步,咱們繪製一個漸變.咱們將當前像素座標劃分到屏幕尺寸上,獲得UV-一對 (0-1) 之間的浮點數.而後將固定的顏色與Y相乘-UV的垂直份量會給咱們一個漸變:ui

" int width = o.get_width();" +
" int height = o.get_height();" +
" float2 uv = float2(gid) / float2(width, height);" +
" color *= uv.y;" +
複製代碼

輸出圖像會像這樣:spa

chapter18_2.png

接下來咱們換個更好的背景.一個看起來像日落的平滑漸變.咱們能夠用mix來混合顏色.咱們告訴函數垂直混合顏色,用Y份量來切換顏色:翻譯

" float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));" +
複製代碼

輸出圖像會像這樣:3d

chapter18_3.png

從這裏,咱們就能畫一個黑色的洞.我將用距離函數(length)在屏幕中間 (0.5, 0.5) 畫黑色來實現,並在外面添加愈來愈多的顏色,直到屏幕角落達到最大值.把最後一行替換爲:

" float2 q = uv - float2(0.5);" +
" color *= length(q);" +
複製代碼

輸出圖像會像這樣:

chapter18_4.png

下一步,咱們用smootstep來繪製一個圓形,裏面填充上黑色,外面藍色,在r(r + 0.01) 之間用混合色.用下面替換最後一行:

" float r = 0.2;" +
" color *= smoothstep(r, r + 0.01, length(q));" +
複製代碼

輸出圖像會像這樣:

chapter18_5.png

若是咱們對圓形邊緣不滿,能夠用數學函數好比cosatan2讓它 凹凸不平 .咱們產生了9個凸起(頻率),凸起高度(振幅)是0.1:

" float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0);" +
複製代碼

輸出圖像會像這樣:

chapter18_6.png

添加X座標到餘弦相位,產生一個彎曲效果:

" float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0 + 20.0 * q.x);" +
複製代碼

輸出圖像會像這樣:

chapter18_7.png

你能夠添加一個很小的值如0.1到餘弦中來旋轉它們:

" float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0 + 20.0 * q.x + 1.0);" +
複製代碼

輸出圖像會像這樣:

chapter18_8.png

你以爲這看起來像棕櫚樹的樹冠了麼,我也以爲像!咱們能夠用abs來畫樹幹,這個函數給咱們水平/垂直距離而不是歐幾里得距離(對一個給定的點)如長度,因此讓咱們用X距離在原有基礎上再添加幾行代碼(咱們將重用rcolor):

" r = 0.015;" +
" color *= smoothstep(r, r + 0.002, abs(q.x));" +
複製代碼

輸出圖像會像這樣:

chapter18_9.png

咱們能夠用另外一個Y軸的smoothstep來移除不須要的樹幹部分:

" color *= 1.0 - (1.0 - smoothstep(r, r + 0.002, abs(q.x))) * smoothstep(0.0, 0.1, q.y);" +
複製代碼

輸出圖像會像這樣:

chapter18_10.png

由於樹冠和樹幹都用到了q,修改這個值將會移動全部的圖像:

" float2 q = uv - float2(0.67, 0.29);" +
複製代碼

輸出圖像會像這樣:

chapter18_11.png

經過引入一個sin函數咱們能夠彎曲樹幹.頻率過小彎曲不夠,但頻率過高又彎曲太多,因此2.0正好. 2.5振幅將樹幹的基準向屏幕邊緣移動到正好的距離(把符號從 + 改爲 - 會把基準向另外一邊移動):

" color *= 1.0 - (1.0 - smoothstep(r, r + 0.002, abs(q.x - 0.25 * sin(2.0 * q.y)))) * smoothstep(0.0, 0.1, q.y);" +
複製代碼

輸出圖像會像這樣:

chapter18_12.png

樹幹又太光滑了.再用cos來添加些不規則變化.高的頻率低的振幅看上去正是咱們想要的:

" r = 0.015 + 0.002 * cos (120.0 * q.y);" +
複製代碼

輸出圖像會像這樣:

chapter18_13.png

還有,樹幹根部一般會改變地面附近的形狀,因此exp函數正是咱們須要的,由於他在開始時增加緩慢,而後向着天空快速增加.咱們用衰減因子爲 -50.0:

" r = 0.015 + 0.002 * cos (120.0 * q.y) + exp(-50.0 * (1.0 - uv.y));" +
複製代碼

輸出圖像會像這樣:

chapter18_14.png

咱們能夠用sqrt來獲得一個更大的數(當用於小數時),用來加強第二種顏色的表現.日落即將完成:

" float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));" +
複製代碼

最終iPad上的圖片應該看起來像:

chapter18_15.png

總結,咱們看到了如何用sqrt來塑造形狀的過渡,用cos來在形狀在建立凸起和凹陷,用exp來創造麴線,用smoothstep來處理閾值/臨界點,abs來得到對稱性,mix來得到混合.又在通勤路上了?爲何不來看看這個漂亮的三葉草是怎麼建立的呢:

chapter18_16.png

我要再次感謝Inigo Quilez,由於他激勵我寫下更多的關於用數學繪圖的文章.本教程中的數學都歸功於他.

源代碼source code 已發佈在Github上.

下次見!

相關文章
相關標籤/搜索