### 技术控

今日:293| 主题:58027

# [其他] Using MetalKit part 2*3^2

aenji10 投递于 2016-10-1 12:03:48
181 8
 Yes, as the title suggests, we’re going to have another of those posts with math (and fun) in it. I was thinking the other day, what can we do while commuting for an hour or so, without internet and possibly without a laptop as well, just carrying an iPad with us. Luckily, the iPad now has the awesome Swift Playgrounds app.    Let’s start with a new playground that runs a basic compute kernel. Since the current version of the Swift Playgrounds app does not yet let us edit the Auxiliary Source Files , where all our Swift and Metal files usually reside, we will have to write our code in the main playground page, but it is not that complicated. All we have to do is modify our MetalView initializer and let it take in an extra argument – our shader/kernel code. Then we start building our code by adding more lines to this long string.   Let’s start with a light blue sky background color:     let shader ="#include \n" +"using namespace metal;" +"kernel void k(texture2d 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);" +"}"复制代码   If you run the playground now, the output image should look like this:     Using MetalKit part 2*3^2    Next, let’s draw a gradient. we divide the current pixel coordinates to the screen dimensions and we get UV – a pair of floats between (0-1) . we then multiply the fixed color with Y – the vertical component of UV which gives us the gradient:     "   int width = o.get_width();" +"   int height = o.get_height();" +"   float2 uv = float2(gid) / float2(width, height);" +"   color *= uv.y;" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    Let’s work on a nicer background next. A smooth gradient would look like a great sunset. We can use mix to blend colors. We tell the function to blend vertically, and take the complement of Y to switch the colors:     "   float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    From here we could go to drawing a black hole. We would achieve that by using a distance function ( length ) to draw black in the middle of the screen (0.5, 0.5) and add more and more background color outside of it, until we reach the maximum value in the screen corners. Replace the last line with:     "   float2 q = uv - float2(0.5);" +"   color *= length(q);" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    Next we use smootstep to draw a round shape that is black inside, blue outside and a blended color between r and (r + 0.01) . Replace the last line with:     "   float r = 0.2;" +"   color *= smoothstep(r, r + 0.01, length(q));" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    If we’re not satisfied with a circular perimeter, we could make it bumpy by using math functions such as cos and atan2 . We generate here 9 spikes ( frequency ) with a spike length ( amplitude ) of 0.1 :     "   float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0);" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    Adding the X coordinate to the cosine phase introduces a spike bend-like effect:     "   float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0 + 20.0 * q.x);" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    You can rotate them by adding a small number such as 1.0 to the cosine value:     "   float r = 0.2 + 0.1 * cos(atan2(q.x, q.y) * 9.0 + 20.0 * q.x + 1.0);" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    If you think this is starting to look like a palm tree canopy, I see it too! We can draw its trunk using abs which gives us horizontal/vertical distances instead of euclidian distances (to a given point) like length did, so let’s take the X distance and add these lines (we are reusing both r and color ) after the existing ones:     "   r = 0.015;" +"   color *= smoothstep(r, r + 0.002, abs(q.x));" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    We can remove the unneeded part of the trunk by using another smoothstep on the Y coordinate:     "   color *= 1.0 - (1.0 - smoothstep(r, r + 0.002, abs(q.x))) * smoothstep(0.0, 0.1, q.y);" +复制代码   The output image should look like this:     Using MetalKit part 2*3^2    Since both the canopy and trunk are using q , modifying its value will move both:     "   int width = o.get_width();" +"   int height = o.get_height();" +"   float2 uv = float2(gid) / float2(width, height);" +"   color *= uv.y;" +0复制代码   The output image should look like this:     Using MetalKit part 2*3^2    By introducing a sin function we can bend the trunk. A too small frequency does not bend it enough while a too high frequency bends it too much so 2.0 seems right. An amplitude of 0.25 also moves the base of the trunk towards the edge of the screen so it looks right (as an aside, changing the sign from + to – will shift the base to the other side):     "   int width = o.get_width();" +"   int height = o.get_height();" +"   float2 uv = float2(gid) / float2(width, height);" +"   color *= uv.y;" +1复制代码   The output image should look like this:     Using MetalKit part 2*3^2    The trunk, however, is too smooth. To add irregularities to its surface we use cos again. A high frequency and low amplitude seem to be what we need to make it look right:     "   int width = o.get_width();" +"   int height = o.get_height();" +"   float2 uv = float2(gid) / float2(width, height);" +"   color *= uv.y;" +2复制代码   The output image should look like this:     Using MetalKit part 2*3^2    Also, trunks are usually shaping the ground a little around their base, so an exp function is what we need here because it grows slowly in the beginning and then it soars to the skies. We use an attenuation factor of -50.0 :     "   int width = o.get_width();" +"   int height = o.get_height();" +"   float2 uv = float2(gid) / float2(width, height);" +"   color *= uv.y;" +3复制代码   The output image should look like this:     Using MetalKit part 2*3^2    We can increase the presence of the second color by using sqrt which gives us bigger numbers (when used on sub-unitary numbers) to work with. The sunset is about to end soon:     "   float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));" +复制代码   The final image on the iPad should look like this:     Using MetalKit part 2*3^2    In conclusion, we saw how to use sqrt to shape transitions, then cos to create variations of ups and downs in shapes, then exp that allows us to create curves, then smoothstep for thresholding, then abs for symmetry and mix for blending. Still commuting? Why don’t you take a look at how this nice clover was created:     Using MetalKit part 2*3^2    I want to say thanks to Inigo Quilez again, for keep inspiring me to write more and more about drawing with math. All the math in this tutorial belongs to him. The source code is posted on Github as usual.   Until next time!

wx_yQ4OPAAx 投递于 2016-10-2 14:55:09
 哥不说话，笑着路过！

 大人，此事必有蹊跷！

 我也是坐沙发的

 姐不是电视机，不要老是盯着姐看。

 aenji10的帖子香飘飘

じ★ve梦悱灬 投递于 2016-10-11 15:50:43
 不回帖的话就太任性了

 敢进男厕所的女汉子别隐身

wenziyo 投递于 2016-11-8 17:39:58
 为保住菊花，这个一定得回复！

• ## 不穿条纹，怎能美美地去南法度假？

微信号 graziachina [...]

• ## 据说，所有开车来过这里的人，都不想再离开

微信号 autohomewei [...]

• ## 香港打折季！各大品牌相继打骨折！Dior低至

微信号 zhengtai-HK [...]

• ## 甘肃成县县委：电商近在咫尺的几条“泥路”

【亿邦动力网讯】5月27日消息，在 2017中国电子 [...]

• ## 夏天这么做美甲，包你美翻天！

微信号 NailBeauty [...]

• ## 想被赞年轻？除了看脸这些保养更重要

微信号 voguechina [...]

• ## 天使投资人孙江涛：创业15年，我的成功与反

题图：天使投资人，钱袋宝与神州付创始人 孙 [...]

• ## ä¸äťśTć¤ďźćĺŽĺ

ĺžŽäżĄĺˇ [...]

• ## 扎克伯格回母校哈佛演讲，透露曾差点被哈佛

据外媒报道，Facebook CEO马克·扎克伯格(Mark [...]

• ## 这个季节牛仔裤应该配什么衣服！

微信号 dp9978 阅读 [...]

© 2001-2017 Comsenz Inc.