请选择 进入手机版 | 继续访问电脑版

技术控

    今日:4| 主题:54680
收藏本版 (1)
最新软件应用技术尽在掌握

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

[复制链接]
aenji10 发表于 2016-10-1 12:03:48
176 8

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
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:
   
  1. let shader =
  2. "#include <metal_stdlib>\n" +
  3. "using namespace metal;" +
  4. "kernel void k(texture2d<float,access::write> o[[texture(0)]]," +
  5. "              uint2 gid[[thread_position_in_grid]]) {" +
  6. "   float3 color = float3(0.5, 0.8, 1.0);" +
  7. "   o.write(float4(color, 1.0), gid);" +
  8. "}"
复制代码
   If you run the playground now, the output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-1-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   int width = o.get_width();" +
  2. "   int height = o.get_height();" +
  3. "   float2 uv = float2(gid) / float2(width, height);" +
  4. "   color *= uv.y;" +
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-2-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   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

Using MetalKit part 2*3^2-3-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   float2 q = uv - float2(0.5);" +
  2. "   color *= length(q);" +
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-4-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   float r = 0.2;" +
  2. "   color *= smoothstep(r, r + 0.01, length(q));" +
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-5-技术控-background,internet,building,carrying,possibly

   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 :
   
  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

Using MetalKit part 2*3^2-6-技术控-background,internet,building,carrying,possibly

   Adding the X coordinate to the cosine phase introduces a spike bend-like effect:
   
  1. "   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

Using MetalKit part 2*3^2-7-技术控-background,internet,building,carrying,possibly

   You can rotate them by adding a small number such as 1.0 to the cosine value:
   
  1. "   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

Using MetalKit part 2*3^2-8-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   r = 0.015;" +
  2. "   color *= smoothstep(r, r + 0.002, abs(q.x));" +
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-9-技术控-background,internet,building,carrying,possibly

   We can remove the unneeded part of the trunk by using another smoothstep on the Y coordinate:
   
  1. "   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

Using MetalKit part 2*3^2-10-技术控-background,internet,building,carrying,possibly

   Since both the canopy and trunk are using q , modifying its value will move both:
   
  1. "   int width = o.get_width();" +
  2. "   int height = o.get_height();" +
  3. "   float2 uv = float2(gid) / float2(width, height);" +
  4. "   color *= uv.y;" +0
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-11-技术控-background,internet,building,carrying,possibly

   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):
   
  1. "   int width = o.get_width();" +
  2. "   int height = o.get_height();" +
  3. "   float2 uv = float2(gid) / float2(width, height);" +
  4. "   color *= uv.y;" +1
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-12-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   int width = o.get_width();" +
  2. "   int height = o.get_height();" +
  3. "   float2 uv = float2(gid) / float2(width, height);" +
  4. "   color *= uv.y;" +2
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-13-技术控-background,internet,building,carrying,possibly

   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 :
   
  1. "   int width = o.get_width();" +
  2. "   int height = o.get_height();" +
  3. "   float2 uv = float2(gid) / float2(width, height);" +
  4. "   color *= uv.y;" +3
复制代码
   The output image should look like this:
   

Using MetalKit part 2*3^2

Using MetalKit part 2*3^2-14-技术控-background,internet,building,carrying,possibly

   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:
   
  1. "   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

Using MetalKit part 2*3^2-15-技术控-background,internet,building,carrying,possibly

   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

Using MetalKit part 2*3^2-16-技术控-background,internet,building,carrying,possibly

   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!



上一篇:ggplot2 2.2.0 coming soon!
下一篇:redis配置文件参数说明及命令操作
wx_yQ4OPAAx 发表于 2016-10-2 14:55:09
哥不说话,笑着路过!
回复 支持 反对

使用道具 举报

千雁 发表于 2016-10-2 21:18:32
大人,此事必有蹊跷!
回复 支持 反对

使用道具 举报

景艳 发表于 2016-10-6 09:53:15
我也是坐沙发的
回复 支持 反对

使用道具 举报

黄荣 发表于 2016-10-9 10:57:23
姐不是电视机,不要老是盯着姐看。
回复 支持 反对

使用道具 举报

悲伤述说微笑 发表于 2016-10-9 11:20:06
aenji10的帖子香飘飘
回复 支持 反对

使用道具 举报

じ★ve梦悱灬 发表于 2016-10-11 15:50:43
不回帖的话就太任性了
回复 支持 反对

使用道具 举报

堇年纸鸢 发表于 2016-10-15 10:39:07
敢进男厕所的女汉子别隐身
回复 支持 反对

使用道具 举报

wenziyo 发表于 2016-11-8 17:39:58
为保住菊花,这个一定得回复!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读


回页顶回复上一篇下一篇回列表
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )

© 2001-2017 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表