2:I[8173,["173","static/chunks/173-424fa9be91923976.js","653","static/chunks/app/blog/ray-marching-with-swift-and-metal-for-shadertoy-like-graphics/page-16c422449953595e.js"],"Image"] 3:I[9275,[],""] 4:I[1343,[],""] 5:I[2650,["173","static/chunks/173-424fa9be91923976.js","231","static/chunks/231-1e7bbdc770c66fc3.js","521","static/chunks/521-7266f541e89dccd7.js","185","static/chunks/app/layout-1a67d20efb7fbcee.js"],"Providers"] 6:I[7848,["173","static/chunks/173-424fa9be91923976.js","231","static/chunks/231-1e7bbdc770c66fc3.js","521","static/chunks/521-7266f541e89dccd7.js","185","static/chunks/app/layout-1a67d20efb7fbcee.js"],"Header"] 7:I[231,["173","static/chunks/173-424fa9be91923976.js","49","static/chunks/49-d41f7eeba1de0524.js","231","static/chunks/231-1e7bbdc770c66fc3.js","847","static/chunks/847-d03f1a8cba4db626.js","404","static/chunks/app/blog/page-527c30508ff17cd7.js"],""] 0:["zCwPuQV_WbLEohhlcHJz-",[[["",{"children":["blog",{"children":["ray-marching-with-swift-and-metal-for-shadertoy-like-graphics",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["blog",{"children":["ray-marching-with-swift-and-metal-for-shadertoy-like-graphics",{"children":["__PAGE__",{},[["$L1",["$","div",null,{"className":"sm:px-8 mt-16 lg:mt-32","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"xl:relative","children":["$","div",null,{"className":"mx-auto max-w-2xl","children":["$","article",null,{"children":[["$","header",null,{"className":"flex flex-col","children":[["$","h1",null,{"className":"mt-6 text-4xl font-bold tracking-tight text-zinc-800 sm:text-5xl dark:text-zinc-100","children":"Raymarching with Swift and Metal for Shadertoy-like Graphics"}],["$","time",null,{"dateTime":"2024-04-17T20:30:00.000Z","className":"order-first flex items-center text-base text-zinc-400 dark:text-zinc-500","children":[["$","span",null,{"className":"h-4 w-0.5 rounded-full bg-zinc-200 dark:bg-zinc-500"}],["$","span",null,{"className":"ml-3","children":"17 April 2024"}]]}]]}],["$","div",null,{"className":"mt-8 prose dark:prose-invert","data-mdx-content":true,"children":[["$","p",null,{"children":[["$","a",null,{"href":"https://www.shadertoy.com/","children":"Shadertoy"}]," is a well known website for creating and sharing shader driven graphics. It works in the browser for a tight feedback loop between changes and results. You use WebGL to write shader code. Can we do something similar with native Swift code for iOS and MacOS? Yes, at least in terms of creation."]}],"\n",["$","h2",null,{"children":"Basics"}],"\n",["$","p",null,{"children":["It is remarkable easy to get a fully shader rendered app. (Actually it is ",["$","em",null,{"children":"more"}]," remarkable when you learn more and know how tedious many of the technologies are to set up normally.) Let's create a new Multi-platform ",["$","em",null,{"children":"App"}]," Swift project in Xcode. Replace the main view in ",["$","code",null,{"children":"ContentView.swift"}]," with:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"import"}]," ",["$","span",null,{"className":"token class-name","children":"SwiftUI"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"let"}]," startDate ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"Date"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"GeometryReader"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," gp ",["$","span",null,{"className":"token keyword","children":"in"}],"\n ",["$","span",null,{"className":"token class-name","children":"TimelineView"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":"."}],"animation",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ctx ",["$","span",null,{"className":"token keyword","children":"in"}],"\n ",["$","span",null,{"className":"token class-name","children":"Rectangle"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"ignoresSafeArea"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"colorEffect"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"ShaderLibrary"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"raymarch"}],["$","span",null,{"className":"token punctuation","children":"("}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"float2"}],["$","span",null,{"className":"token punctuation","children":"("}],"gp",["$","span",null,{"className":"token punctuation","children":"."}],"size",["$","span",null,{"className":"token punctuation","children":"."}],"width",["$","span",null,{"className":"token punctuation","children":","}]," gp",["$","span",null,{"className":"token punctuation","children":"."}],"size",["$","span",null,{"className":"token punctuation","children":"."}],"height",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"float"}],["$","span",null,{"className":"token punctuation","children":"("}],"startDate",["$","span",null,{"className":"token punctuation","children":"."}],"timeIntervalSinceNow",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token other-directive property","children":"#Preview"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["That is basically all the Swift code we will write. Now it won't work yet as this ",["$","code",null,{"children":"ShaderLibrary.raymarch"}]," doesn't exist. Let's create a new Metal file by hitting ",["$","code",null,{"children":"cmd + m"}],", e.g. ",["$","code",null,{"children":"RayMarch.metal"}]," and replace the code with:"]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token macro property","children":[["$","span",null,{"className":"token directive-hash","children":"#"}],["$","span",null,{"className":"token directive keyword","children":"include"}]," ",["$","span",null,{"className":"token string","children":""}]]}],"\n",["$","span",null,{"className":"token macro property","children":[["$","span",null,{"className":"token directive-hash","children":"#"}],["$","span",null,{"className":"token directive keyword","children":"include"}]," ",["$","span",null,{"className":"token string","children":""}]]}],"\nusing namespace metal",["$","span",null,{"className":"token punctuation","children":";"}],"\n\n",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"["}]," stitchable ",["$","span",null,{"className":"token punctuation","children":"]"}],["$","span",null,{"className":"token punctuation","children":"]"}]," half4 ",["$","span",null,{"className":"token function","children":"raymarch"}],["$","span",null,{"className":"token punctuation","children":"("}],"float2 position",["$","span",null,{"className":"token punctuation","children":","}]," half4 currentColor",["$","span",null,{"className":"token punctuation","children":","}]," float2 size",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," time",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," c ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],"c",["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["Now go back to your Swift file. Ideally you should use Xcode's split view controls to get the Metal file alongside the Swift file. Start a preview with ",["$","code",null,{"children":"cmd + alt + enter"}]," and hit ",["$","code",null,{"children":"cmd + alt + p"}]," to restart if necessary. If everything is working it will should show a full screen going backwards and forwards between white and black."]}],"\n",["$","h2",null,{"children":"Live Coding (sort of)"}],"\n",["$","p",null,{"children":"Now you should be able to make changes to the low level shader code and see the results in the preview pretty quickly. It isn't going to be quite as nice as Shadertoy, though Xcode will offer better code completion than Shadertoy."}],"\n",["$","h2",null,{"children":"Okay but how did that code work?"}],"\n",["$","p",null,{"children":"Let's look at the Swift stuff first. It combines a few things, but each are individually quite simple."}],"\n",["$","ul",null,{"children":["\n",["$","li",null,{"children":["We use ",["$","code",null,{"children":"GeometryReader"}]," to get the size of the view."]}],"\n",["$","li",null,{"children":["We use ",["$","code",null,{"children":"TimelineView(.animation)"}]," to redraw the view every frame."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"Rectangle"}]," is just a simple view that will take all available space offered. We use ",["$","code",null,{"children":"ignoresSafeArea"}]," to make sure it fills the whole screen."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":".colorEffect"}]," is a SwiftUI modifier that allows us to apply a shader to a view."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"ShaderLibrary.raymarch"}]," gives us access to our shader function. We pass in the data to it. One thing might seem a little odd, the ",["$","code",null,{"children":".float2"}]," and so on. This is because Metal expects certain data types which aren't the ones we'll have been using. ",["$","code",null,{"children":"float2"}]," is just a 2D float vector (and so on for ",["$","code",null,{"children":"3"}]," and ",["$","code",null,{"children":"4"}],")."]}],"\n"]}],"\n",["$","p",null,{"children":["Now on the Shader side we do need to declare the parameters consistently. ",["$","a",null,{"href":"https://developer.apple.com/metal/","children":"Metal"}]," is not Swift, indeed this can be pretty confusing as some things will look quite similar. It is a low level ",["$","em",null,{"children":"shader"}]," language. We will be writing fragment shaders, which are massively parallel programs that run for each pixel you draw."]}],"\n",["$","p",null,{"children":["We declare a matching function and signature. For ",["$","code",null,{"children":"colorEffect"}]," we actually get a ",["$","code",null,{"children":"position"}]," and ",["$","code",null,{"children":"currentColor"}]," argument out of box. We can then add further arguments."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"["}]," stitchable ",["$","span",null,{"className":"token punctuation","children":"]"}],["$","span",null,{"className":"token punctuation","children":"]"}]," half4 ",["$","span",null,{"className":"token function","children":"raymarch"}],["$","span",null,{"className":"token punctuation","children":"("}],"float2 position",["$","span",null,{"className":"token punctuation","children":","}]," half4 currentColor",["$","span",null,{"className":"token punctuation","children":","}]," float2 size",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," time",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":["Now to draw something we first take the ",["$","code",null,{"children":"time"}]," and then take ",["$","code",null,{"children":"sin"}]," of it (this will give us a value between -1 and 1). We must return a 4d color (the ",["$","code",null,{"children":"half4"}],"). This is comprised of a red, green, blue and opacity value. For shaders we work with values between 0 and 1. To start with we just set all the color values to the same value. This will give us a greyscale color. And we set the opacity to 1 (fully opaque)."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" ",["$","span",null,{"className":"token keyword","children":"float"}]," c ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],"c",["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":["Experiment with changing some of these ",["$","code",null,{"children":"c"}]," to specific values between ",["$","code",null,{"children":"0"}]," and ",["$","code",null,{"children":"1"}],"."]}],"\n",["$","h2",null,{"children":"Make it more interesting"}],"\n",["$","p",null,{"children":["Add one new line at the start of our shader. This gives us a ",["$","code",null,{"children":"uv"}]," value (like an x,y graph) that goes between -1 and 1 in vertical (and proportionately in horizontal)."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" float2 uv ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],"position ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"2.0"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," size",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," size",["$","span",null,{"className":"token punctuation","children":"."}],"y",["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":"We can now use this to add some gradients:"}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" float2 uv ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],"position ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"2.0"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," size",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," size",["$","span",null,{"className":"token punctuation","children":"."}],"y",["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," c ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"half2"}],["$","span",null,{"className":"token punctuation","children":"("}],"uv",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","$L2",null,{"unoptimized":true,"alt":"A simple gradient in metal","src":{"src":"/_next/static/media/metal01.66e05d85.png","height":430,"width":628,"blurDataURL":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAATlBMVEUIudYyAuf+Aew2uNUSE7ymA+bcFcwAWugABOIAAO6mWuabt9Tru9kXp8AQW8/NpL3dW8wgIasQEdQQFcvNEL06Fr21IqgyWuf/WuyKE7l4KInwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAMUlEQVR4nGMQZGFhEZUUEWMQ4uTkZGRlYmMQ5uDgADP42NnZxbkkBBh4GRgYmLl5+AElTQGMr1d5rAAAAABJRU5ErkJggg==","blurWidth":8,"blurHeight":5}}],"\n",["$","p",null,{"children":["The ",["$","code",null,{"children":"uv"}]," values will include negatives and even go above 1. This is why the gradient is cut off. We can fix like:"]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"half2"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," uv",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token operator","children":"/"}],["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token punctuation","children":","}],"c",["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":["One of the nice things we can do with shaders is combine vectors and scalars without needing to convert between them. ",["$","code",null,{"children":"uv"}]," is a 2d vector and ",["$","code",null,{"children":"1"}]," is a scalar. We can add them together and then divide by ",["$","code",null,{"children":"2"}]," to get a 2d vector again."]}],"\n",["$","h2",null,{"children":"Raymarching"}],"\n",["$","p",null,{"children":"Raymarching is an awesome technique for creative rendering. It is actually quite simple yet can create complex, interesting visuals."}],"\n",["$","p",null,{"children":"We basically think of an camera being at a particular point. We shoot out rays from that point through a 'screen'. For each ray we calculate the distance to the nearest object. We then move along the ray by that distance and repeat until we are very close to the object or we have gone very far away. Let's take that in 2 parts."}],"\n",["$","p",null,{"children":["We call ",["$","code",null,{"children":"ro"}]," our 'origin' (as our location we imagine ourselves 3 units back in space). Then we shoot a ray through our screen. But we already have created a ",["$","code",null,{"children":"uv"}]," value for each pixel. So we can use that. A good enough approximation for now is to use ",["$","code",null,{"children":"uv"}]," as the ",["$","code",null,{"children":"x"}]," and ",["$","code",null,{"children":"y"}]," values of our ray direction. For ",["$","code",null,{"children":"z"}]," let's just use ",["$","code",null,{"children":"1"}],". We can then normalise (this means make the length of the vector ",["$","code",null,{"children":"1"}],") the vector."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" float3 ro ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token operator","children":"-"}],["$","span",null,{"className":"token number","children":"3"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n float3 rd ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"normalize"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],"uv",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":["Okay so we have some rays. What about the distance? We need a ",["$","em",null,{"children":"(signed) distance function"}],". To keep things simple let's just use a circle at ",["$","code",null,{"children":"(0,0,0)"}]," of radius ",["$","code",null,{"children":"1"}],". What is the distance from some point to this? Well it is actually trivial in Metal to get this. We can use ",["$","code",null,{"children":"length(p) - 1"}],"."]}],"\n",["$","p",null,{"children":"Okay let's actually do the raymarching. Setup a function to handle the distance:"}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token keyword","children":"float"}]," ",["$","span",null,{"className":"token function","children":"distanceToBall"}],["$","span",null,{"className":"token punctuation","children":"("}],"float3 p",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"length"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," ",["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"And to our existing shader:"}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"["}]," stitchable ",["$","span",null,{"className":"token punctuation","children":"]"}],["$","span",null,{"className":"token punctuation","children":"]"}]," half4 ",["$","span",null,{"className":"token function","children":"raymarch"}],["$","span",null,{"className":"token punctuation","children":"("}],"float2 position",["$","span",null,{"className":"token punctuation","children":","}]," half4 currentColor",["$","span",null,{"className":"token punctuation","children":","}]," float2 size",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," time",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float2 uv ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],"position ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"2.0"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," size",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," size",["$","span",null,{"className":"token punctuation","children":"."}],"y",["$","span",null,{"className":"token punctuation","children":";"}],"\n\n float3 ro ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token operator","children":"-"}],["$","span",null,{"className":"token number","children":"3"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n float3 rd ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"normalize"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],"uv",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":["Let's do the raymarching. Start (remember this happens for every pixel) at ",["$","code",null,{"children":"t = 0"}],". Now we iterate up to ",["$","code",null,{"children":"80"}]," times. We move forwards in the direction of our ray by the distance to the ball."]}],"\n",["$","p",null,{"children":"We repeat."}],"\n",["$","p",null,{"children":["If we get very close we stop (",["$","code",null,{"children":"d < 0.001"}],"). Or if very far off we give up."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" ",["$","span",null,{"className":"token keyword","children":"float"}]," t ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"int"}]," i ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":";"}]," i ",["$","span",null,{"className":"token operator","children":"<"}]," ",["$","span",null,{"className":"token number","children":"80"}],["$","span",null,{"className":"token punctuation","children":";"}]," i",["$","span",null,{"className":"token operator","children":"++"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float3 p ",["$","span",null,{"className":"token operator","children":"="}]," ro ",["$","span",null,{"className":"token operator","children":"+"}]," rd ",["$","span",null,{"className":"token operator","children":"*"}]," t",["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," d ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"distanceToBall"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n t ",["$","span",null,{"className":"token operator","children":"+="}]," d",["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"if"}],["$","span",null,{"className":"token punctuation","children":"("}],"d ",["$","span",null,{"className":"token operator","children":"<"}]," ",["$","span",null,{"className":"token number","children":"0.001"}]," ",["$","span",null,{"className":"token operator","children":"||"}]," t ",["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token number","children":"100"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token keyword","children":"break"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["Finally we need to return something from the shader to color the pixel. If ",["$","code",null,{"children":"t"}]," is high let's just use black or ",["$","code",null,{"children":"half4(0,0,0,1)"}],". If it is close let's try ",["$","code",null,{"children":"half4(sin(t),0,0,1)"}]," (this is a sneaky way of adding a little gradient based on ",["$","code",null,{"children":"t"}],", but we'll see more interesting ways of picking colors later)."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" ",["$","span",null,{"className":"token keyword","children":"if"}],["$","span",null,{"className":"token punctuation","children":"("}],"t ",["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token number","children":"100"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"t",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"This gives us this. Which at first glance might seem trivial. But we are doing something pretty amazing. From very basic mathematics and in about 50 lines of code we are rendering a 3D object, pixel by pixel on our GPUs."}],"\n",["$","$L2",null,{"unoptimized":true,"alt":"Actual raymarching","src":{"src":"/_next/static/media/metal02.9648fe5a.png","height":430,"width":628,"blurDataURL":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAAD1BMVEUWGBkCAQELDQ49AACiAgJ612a7AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIklEQVR4nGNgYGJgYAARTIxgAGawsEAZzMwgBgMTCDAyAAAD8QAyPYH/FQAAAABJRU5ErkJggg==","blurWidth":8,"blurHeight":5}}],"\n",["$","p",null,{"children":"Let's animate it by changing the origin with time:"}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" float3 ro ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token operator","children":"-"}],["$","span",null,{"className":"token number","children":"3.1"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"cos"}],["$","span",null,{"className":"token punctuation","children":"("}],"time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","p",null,{"children":"and make the colors more interesting:"}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[" ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"t",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token function","children":"cos"}],["$","span",null,{"className":"token punctuation","children":"("}],"t",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],"t",["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n"]}]}],"\n",["$","h2",null,{"children":"Taking It Further"}],"\n",["$","p",null,{"children":["With not that much more code we can do something like this (",["$","a",null,{"href":"https://youtu.be/5Zpu8XPIdoY","children":"video link"}],"):"]}],"\n",["$","$L2",null,{"unoptimized":true,"alt":"Infinite pattered animated raymarching","src":{"src":"/_next/static/media/metal03.9b0dbc08.png","height":430,"width":628,"blurDataURL":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAAP1BMVEV3cXJlV1eDraxtkZFxXF1mgYJyn59wamtnY2KBhoaRs7R9w8RcdXV4jYxTZGSDaWl2jI15n6FuYGF+XFySnp2JhbiSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAL0lEQVR4nAXBhwHAMAjAMBMgQHfG/7dWwnzM6E+gbSdNHZak2AtfVUbdTvTDOC9+GyQBKLTewhkAAAAASUVORK5CYII=","blurWidth":8,"blurHeight":5}}],"\n",["$","p",null,{"children":"Video version (note the actual rendering is much sharper than even the 4k version of the video):"}],"\n",["$","iframe",null,{"width":"560","height":"315","src":"https://www.youtube-nocookie.com/embed/5Zpu8XPIdoY?si=jsw61jz0LdJgcPtT&controls=0","title":"YouTube video player","frameborder":"0","allow":"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share","referrerpolicy":"strict-origin-when-cross-origin","allowfullscreen":true}],"\n",["$","p",null,{"children":["Let's update our Swift code to use ",["$","code",null,{"children":"ShaderLibrary.raymarchB"}]," and create a new shader in our existing file:"]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"["}]," stitchable ",["$","span",null,{"className":"token punctuation","children":"]"}],["$","span",null,{"className":"token punctuation","children":"]"}]," half4 ",["$","span",null,{"className":"token function","children":"raymarchB"}],["$","span",null,{"className":"token punctuation","children":"("}],"float2 position",["$","span",null,{"className":"token punctuation","children":","}]," half4 currentColor",["$","span",null,{"className":"token punctuation","children":","}]," float2 size",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," time",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float2 uv ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"("}],"position ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"2.0"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," size",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"/"}]," size",["$","span",null,{"className":"token punctuation","children":"."}],"y",["$","span",null,{"className":"token punctuation","children":";"}],"\n\n float3 ro ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token operator","children":"-"}],["$","span",null,{"className":"token number","children":"3"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n float3 rd ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"normalize"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],"uv",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"float"}]," t ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"int"}]," j ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"int"}]," i ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":";"}]," i ",["$","span",null,{"className":"token operator","children":"<"}]," ",["$","span",null,{"className":"token number","children":"80"}],["$","span",null,{"className":"token punctuation","children":";"}]," i",["$","span",null,{"className":"token operator","children":"++"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float3 p ",["$","span",null,{"className":"token operator","children":"="}]," ro ",["$","span",null,{"className":"token operator","children":"+"}]," rd ",["$","span",null,{"className":"token operator","children":"*"}]," t",["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," d ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"map"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":","}]," time",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n t ",["$","span",null,{"className":"token operator","children":"+="}]," d",["$","span",null,{"className":"token punctuation","children":";"}],"\n\n j ",["$","span",null,{"className":"token operator","children":"="}]," i",["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}],["$","span",null,{"className":"token punctuation","children":"("}],"d ",["$","span",null,{"className":"token operator","children":"<"}]," ",["$","span",null,{"className":"token number","children":"0.001"}]," ",["$","span",null,{"className":"token operator","children":"||"}]," t ",["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token number","children":"10"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token keyword","children":"break"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"if"}],["$","span",null,{"className":"token punctuation","children":"("}],"t ",["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token number","children":"100"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"0"}],["$","span",null,{"className":"token punctuation","children":","}],["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"half4"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"palette"}],["$","span",null,{"className":"token punctuation","children":"("}],"t ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"0.9"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," time ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"0.01"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token keyword","children":"float"}],["$","span",null,{"className":"token punctuation","children":"("}],"j",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"0.01"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"half3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0.5"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"half3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0.5"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"half3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"1.0"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"half3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0."}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"0.2"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"0.2"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["This is similar to before except we have made our coloring fancier using ",["$","a",null,{"href":"https://iquilezles.org/articles/palettes/","children":"Inigo Quilez's palette helper"}]," and reduced the ",["$","code",null,{"children":"t"}]," value at which we give up. We've also renamed the distance function to ",["$","code",null,{"children":"map"}]," and added a ",["$","code",null,{"children":"j"}]," value to keep track of how many iterations we've done (which we will also use in the coloring)."]}],"\n",["$","p",null,{"children":["For the distance we do a little more. Instead of using ",["$","code",null,{"children":"p"}]," directly we take the the fractional part of if in all directions (this allows for an infinite repetition of our object). We also introduce a rotation of the shape to make it more dynamic (actually we rotate our ray, but the effect is the same; many raymarching approaches apply transformations to the ray rather than the actual object)."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token keyword","children":"float"}]," ",["$","span",null,{"className":"token function","children":"map"}],["$","span",null,{"className":"token punctuation","children":"("}],"float3 p",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," time",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float3 q ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"fract"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":"."}],"xy",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," ",["$","span",null,{"className":"token number","children":"0.5"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"mod"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":"."}],"z",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"0.5"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," ",["$","span",null,{"className":"token number","children":"0.25"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n q",["$","span",null,{"className":"token punctuation","children":"."}],"xy ",["$","span",null,{"className":"token operator","children":"="}]," q",["$","span",null,{"className":"token punctuation","children":"."}],"xy ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token function","children":"rot2D"}],["$","span",null,{"className":"token punctuation","children":"("}],"time ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token number","children":"0.5"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"floor"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":"."}],"z",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"float"}]," box ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"sdBox"}],["$","span",null,{"className":"token punctuation","children":"("}],"q",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"float3"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token number","children":"0.1"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," box",["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["We then take a distance. We use a box, which is a little more complex than a sphere, but not much (and there is a known standard way to formulate). You can learn more ",["$","a",null,{"href":"https://iquilezles.org/articles/distfunctions/","children":"about this and many other 3D SDFs"}],"."]}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":[["$","span",null,{"className":"token keyword","children":"float"}]," ",["$","span",null,{"className":"token function","children":"sdBox"}],["$","span",null,{"className":"token punctuation","children":"("}],"float3 p",["$","span",null,{"className":"token punctuation","children":","}]," float3 b",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n float3 q ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"abs"}],["$","span",null,{"className":"token punctuation","children":"("}],"p",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"-"}]," b",["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token function","children":"length"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"max"}],["$","span",null,{"className":"token punctuation","children":"("}],"q",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"0.0"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"+"}]," ",["$","span",null,{"className":"token function","children":"min"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token function","children":"max"}],["$","span",null,{"className":"token punctuation","children":"("}],"q",["$","span",null,{"className":"token punctuation","children":"."}],"x",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token function","children":"max"}],["$","span",null,{"className":"token punctuation","children":"("}],"q",["$","span",null,{"className":"token punctuation","children":"."}],"y",["$","span",null,{"className":"token punctuation","children":","}]," q",["$","span",null,{"className":"token punctuation","children":"."}],"z",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"0.0"}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"The above depends on a couple of helpers; the first rotates in two dimensions and the second takes the modulo of two floats."}],"\n",["$","pre",null,{"className":"language-c","children":["$","code",null,{"className":"language-c","children":["matrix",["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token keyword","children":"float"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token function","children":"rot2D"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"float"}]," angle",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," s ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"sin"}],["$","span",null,{"className":"token punctuation","children":"("}],"angle",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"float"}]," c ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token function","children":"cos"}],["$","span",null,{"className":"token punctuation","children":"("}],"angle",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," matrix",["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token keyword","children":"float"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token number","children":"2"}],["$","span",null,{"className":"token operator","children":">"}],["$","span",null,{"className":"token punctuation","children":"("}],"c",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token operator","children":"-"}],"s",["$","span",null,{"className":"token punctuation","children":","}]," s",["$","span",null,{"className":"token punctuation","children":","}]," c",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n\n",["$","span",null,{"className":"token keyword","children":"float"}]," ",["$","span",null,{"className":"token function","children":"mod"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"float"}]," a",["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"float"}]," b",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," a ",["$","span",null,{"className":"token operator","children":"-"}]," b ",["$","span",null,{"className":"token operator","children":"*"}]," ",["$","span",null,{"className":"token function","children":"floor"}],["$","span",null,{"className":"token punctuation","children":"("}],"a",["$","span",null,{"className":"token operator","children":"/"}],"b",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":";"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"But the complete shader for this infinitely repeating, animated, psychedelic raymarching is only about 50 lines of code. And you could easily tie details of the shader rendering to your App's state (it could show loading progress, visualize music or any other dynamic data)."}],"\n",["$","h2",null,{"children":"Source code"}],"\n",["$","p",null,{"children":[["$","a",null,{"href":"https://gist.github.com/jamesporter/1b33558b3fc2771b45630ba7e0ba5122","children":"The entire, remarkably short code is in this Gist"}],"."]}],"\n",["$","h2",null,{"children":"Learn More"}],"\n",["$","p",null,{"children":"In terms of Swift stuff"}],"\n",["$","ul",null,{"children":["\n",["$","li",null,{"children":["Paul Hudson has several tutorials on shaders in Swift(UI), ",["$","a",null,{"href":"https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-metal-shaders-to-swiftui-views-using-layer-effects","children":"for example simple shaders"}]," and has a library of ",["$","a",null,{"href":"https://www.hackingwithswift.com/articles/262/introducing-inferno-metal-shaders-for-swiftui","children":"shaders you can apply to your apps"}],"."]}],"\n"]}],"\n",["$","p",null,{"children":"There are vastly more resources on shaders using WebGL/GLSL than Metal, but often they are quite easy to translate."}],"\n",["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","a",null,{"href":"https://iquilezles.org/articles/","children":"Inigo Quilez's articles"}]," are the definitive reference for Raymarching, SDFs and various other creative coding techniques."]}],"\n",["$","li",null,{"children":["He also has some astonishing live coding videos of creating incredible scenes using similar techniques, for example ",["$","a",null,{"href":"https://youtu.be/BFld4EBO2RE?si=GjG84vT-MVOEhXFy","children":"this intricate, naturalistic landscape"}],"."]}],"\n",["$","li",null,{"children":["kishimisu has ",["$","a",null,{"href":"https://www.youtube.com/@kishimisu","children":"a fantastic pair of video tutorials"}]," on shaders."]}],"\n"]}]]}]]}]}]}]}]}]}]}]],null],null]},["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children","blog","children","ray-marching-with-swift-and-metal-for-shadertoy-like-graphics","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","styles":null}],null]},["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children","blog","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","styles":null}],null]},[["$","html",null,{"lang":"en","className":"h-full antialiased","suppressHydrationWarning":true,"children":["$","body",null,{"className":"flex h-full bg-zinc-200 dark:bg-black","children":["$","$L5",null,{"children":["$","div",null,{"className":"flex w-full","children":[["$","div",null,{"className":"fixed inset-0 flex justify-center sm:px-8","children":["$","div",null,{"className":"flex w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"w-full bg-white ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20"}]}]}],["$","div",null,{"className":"relative flex w-full flex-col","children":[["$","$L6",null,{}],["$","main",null,{"className":"flex-auto","children":["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":["$","div",null,{"className":"sm:px-8 flex h-full items-center pt-16 sm:pt-32","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"flex flex-col items-center","children":[["$","p",null,{"className":"text-base font-semibold text-zinc-400 dark:text-zinc-500","children":"404"}],["$","h1",null,{"className":"mt-4 text-4xl font-bold tracking-tight text-rose-800 sm:text-5xl dark:text-rose-100","children":"Page not found"}],["$","p",null,{"className":"mt-4 text-base text-zinc-600 dark:text-zinc-400","children":"Sorry, we couldn’t find the page you’re looking for."}],["$","p",null,{"className":"mt-4 text-base text-zinc-600 dark:text-zinc-400","children":["You may want to try"," ",["$","a",null,{"href":"https://archive.amimetic.co.uk","className":"font-semibold text-rose-600 hover:text-rose-500","children":"the old version of this website"}]," ","as not everything was included here."]}],["$","$L7",null,{"className":"inline-flex items-center gap-2 justify-center rounded-md py-2 px-3 text-sm outline-offset-2 transition active:transition-none bg-zinc-50 font-medium text-zinc-900 hover:bg-zinc-100 active:bg-zinc-100 active:text-zinc-900/60 dark:bg-zinc-800/50 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-zinc-50 dark:active:bg-zinc-800/50 dark:active:text-zinc-50/70 mt-4","href":"/","children":"Go back home"}]]}]}]}]}]}],"notFoundStyles":[],"styles":null}]}],["$","footer",null,{"className":"mt-32 flex-none","children":["$","div",null,{"className":"sm:px-8","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"border-t border-zinc-100 pb-16 pt-10 dark:border-zinc-700/40","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"flex flex-col items-center justify-between gap-6 sm:flex-row","children":[["$","div",null,{"className":"flex flex-wrap justify-center gap-x-6 gap-y-1 text-sm font-medium text-zinc-800 dark:text-zinc-200","children":[["$","$L7",null,{"href":"/about","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"About"}],["$","$L7",null,{"href":"/blog","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"Writing"}],["$","$L7",null,{"href":"/projects","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"Projects"}]]}],["$","p",null,{"className":"text-sm text-zinc-400 dark:text-zinc-500","children":["© ",2024," James Porter"]}]]}]}]}]}]}]}]}]]}]]}]}]}]}],null],null],[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/3dda7107ffc2265a.css","precedence":"next","crossOrigin":"$undefined"}]],"$L8"]]]] 8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Raymarching with Swift and Metal for Shadertoy-like Graphics - James Porter"}],["$","meta","3",{"name":"description","content":"Projects and thoughts from James Porter"}]] 1:null