diff --git a/README.md b/README.md index e021d1a..d0aa377 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,23 @@ # Metal Repository to accompany the following blog posts: -- [Introducing the Metal framework](http://mhorga.org/2016/01/04/introducing-the-metal-framework.html) -- [Using MetalKit part 1](http://mhorga.org/2016/01/11/using-metalkit-part-1.html) -- [Using MetalKit part 2](http://mhorga.org/2016/01/18/using-metalkit-part-2.html) -- [Using MetalKit part 3](http://mhorga.org/2016/01/25/using-metalkit-part-3.html) -- [Using MetalKit part 4](http://mhorga.org/2016/02/01/using-metalkit-part-4.html) -- [Using MetalKit part 5](http://mhorga.org/2016/02/08/using-metalkit-part-5.html) -- [Using MetalKit part 6](http://mhorga.org/2016/02/15/using-metalkit-part-6.html) -- [Using MetalKit part 7](http://mhorga.org/2016/02/29/using-metalkit-part-7.html) -- [Using MetalKit part 8](http://mhorga.org/2016/03/07/using-metalkit-part-8.html) -- [Using MetalKit part 9](http://mhorga.org/2016/04/18/using-metalkit-part-9.html) -- [Using MetalKit part 10](http://mhorga.org/2016/05/02/using-metalkit-part-10.html) -- [Using MetalKit part 11](http://mhorga.org/2016/05/10/using-metalkit-part-11.html) -- [Using MetalKit part 12](http://mhorga.org/2016/05/18/using-metalkit-part-12.html) -- [Using MetalKit part 13](http://mhorga.org/2016/05/25/using-metalkit-part-13.html) -- [Using MetalKit part 14](http://mhorga.org/2016/06/01/using-metalkit-part-14.html) -- [Using MetalKit part 15](http://mhorga.org/2016/06/23/using-metalkit-part-15.html) -- [Using MetalKit part 16](http://mhorga.org/2016/07/06/using-metalkit-part-16.html) -- [Using MetalKit part 17](http://mhorga.org/2016/09/24/using-metalkit-part-17.html) -- [Using MetalKit part 18](http://mhorga.org/2016/09/30/using-metalkit-part-2-3-2.html) +- [Introducing the Metal framework](http://metalkit.org/2016/01/04/introducing-the-metal-framework.html) +- [Using MetalKit part 1](http://metalkit.org/2016/01/11/using-metalkit-part-1.html) +- [Using MetalKit part 2](http://metalkit.org/2016/01/18/using-metalkit-part-2.html) +- [Using MetalKit part 3](http://metalkit.org/2016/01/25/using-metalkit-part-3.html) +- [Using MetalKit part 4](http://metalkit.org/2016/02/01/using-metalkit-part-4.html) +- [Using MetalKit part 5](http://metalkit.org/2016/02/08/using-metalkit-part-5.html) +- [Using MetalKit part 6](http://metalkit.org/2016/02/15/using-metalkit-part-6.html) +- [Using MetalKit part 7](http://metalkit.org/2016/02/29/using-metalkit-part-7.html) +- [Using MetalKit part 8](http://metalkit.org/2016/03/07/using-metalkit-part-8.html) +- [Using MetalKit part 9](http://metalkit.org/2016/04/18/using-metalkit-part-9.html) +- [Using MetalKit part 10](http://metalkit.org/2016/05/02/using-metalkit-part-10.html) +- [Using MetalKit part 11](http://metalkit.org/2016/05/10/using-metalkit-part-11.html) +- [Using MetalKit part 12](http://metalkit.org/2016/05/18/using-metalkit-part-12.html) +- [Using MetalKit part 13](http://metalkit.org/2016/05/25/using-metalkit-part-13.html) +- [Using MetalKit part 14](http://metalkit.org/2016/06/01/using-metalkit-part-14.html) +- [Using MetalKit part 15](http://metalkit.org/2016/06/23/using-metalkit-part-15.html) +- [Using MetalKit part 16](http://metalkit.org/2016/07/06/using-metalkit-part-16.html) +- [Using MetalKit part 17](http://metalkit.org/2016/09/24/using-metalkit-part-17.html) +- [Using MetalKit part 18](http://metalkit.org/2016/10/01/using-metalkit-part-2-3-2.html) +- [Raymarching in Metal](http://metalkit.org/2016/12/29/raymarching-in-metal.html) \ No newline at end of file diff --git a/raymarching/raymarching.playground/Contents.swift b/raymarching/raymarching.playground/Contents.swift new file mode 100644 index 0000000..d12f060 --- /dev/null +++ b/raymarching/raymarching.playground/Contents.swift @@ -0,0 +1,9 @@ + +import MetalKit +import PlaygroundSupport + +let frame = NSRect(x: 0, y: 0, width: 300, height: 300) +let delegate = MetalView() +let view = MTKView(frame: frame, device: delegate.device) +view.delegate = delegate +PlaygroundPage.current.liveView = view diff --git a/raymarching/raymarching.playground/Resources/Shaders.metal b/raymarching/raymarching.playground/Resources/Shaders.metal new file mode 100755 index 0000000..e5e2ff3 --- /dev/null +++ b/raymarching/raymarching.playground/Resources/Shaders.metal @@ -0,0 +1,54 @@ + +#include +using namespace metal; + +struct Ray { + float3 origin; + float3 direction; + Ray(float3 o, float3 d) { + origin = o; + direction = d; + } +}; + +struct Sphere { + float3 center; + float radius; + Sphere(float3 c, float r) { + center = c; + radius = r; + } +}; + +float distToSphere(Ray ray, Sphere s) { + return length(ray.origin - s.center) - s.radius; +} + +float distToScene(Ray r) { + Sphere s = Sphere(float3(1.), 0.5); + Ray repeatRay = r; + repeatRay.origin = fmod(r.origin, 2.0); + return distToSphere(repeatRay, s); +} + +kernel void compute(texture2d output [[texture(0)]], + constant float &time [[buffer(0)]], + uint2 gid [[thread_position_in_grid]]) { + int width = output.get_width(); + int height = output.get_height(); + float2 uv = float2(gid) / float2(width, height); + uv = uv * 2.0 - 1.0; + float3 camPos = float3(1000. + sin(time) + 1., 1000. + cos(time) + 1., time); + Ray ray = Ray(camPos, normalize(float3(uv, 1.))); + float3 col = float3(0.); + for (int i=0.; i<100.; i++) { + float dist = distToScene(ray); + if (dist < 0.001) { + col = float3(1.); + break; + } + ray.origin += ray.direction * dist; + } + float3 posRelativeToCamera = ray.origin - camPos; + output.write(float4(col * abs((posRelativeToCamera) / 10.0), 1.), gid); +} diff --git a/raymarching/raymarching.playground/Sources/MetalView.swift b/raymarching/raymarching.playground/Sources/MetalView.swift new file mode 100755 index 0000000..19203f9 --- /dev/null +++ b/raymarching/raymarching.playground/Sources/MetalView.swift @@ -0,0 +1,52 @@ + +import MetalKit + +public class MetalView: NSObject, MTKViewDelegate { + + public var device: MTLDevice! + var queue: MTLCommandQueue! + var cps: MTLComputePipelineState! + var time: Float = 0 + var timeBuffer: MTLBuffer! + + override public init() { + super.init() + registerShaders() + } + + func registerShaders() { + device = MTLCreateSystemDefaultDevice()! + queue = device.makeCommandQueue() + let path = Bundle.main.path(forResource: "Shaders", ofType: "metal") + do { + let input = try String(contentsOfFile: path!, encoding: String.Encoding.utf8) + let library = try device.makeLibrary(source: input, options: nil) + let kernel = library.makeFunction(name: "compute")! + cps = try device.makeComputePipelineState(function: kernel) + } catch let e { + Swift.print("\(e)") + } + timeBuffer = device!.makeBuffer(length: MemoryLayout.size, options: []) + } + + public func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {} + + public func draw(in view: MTKView) { + if let drawable = view.currentDrawable { + let commandBuffer = queue.makeCommandBuffer() + let commandEncoder = commandBuffer.makeComputeCommandEncoder() + commandEncoder.setComputePipelineState(cps) + commandEncoder.setTexture(drawable.texture, at: 0) + commandEncoder.setBuffer(timeBuffer, offset: 0, at: 0) + time += 0.01 + let bufferPointer = timeBuffer.contents() + memcpy(bufferPointer, &time, MemoryLayout.size) + let threadGroupCount = MTLSizeMake(8, 8, 1) + let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1) + commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) + commandEncoder.endEncoding() + commandBuffer.present(drawable) + commandBuffer.commit() + } + } +} diff --git a/raymarching/raymarching.playground/contents.xcplayground b/raymarching/raymarching.playground/contents.xcplayground new file mode 100644 index 0000000..9f9eecc --- /dev/null +++ b/raymarching/raymarching.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/raymarching/raymarching.playground/playground.xcworkspace/contents.xcworkspacedata b/raymarching/raymarching.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..919434a --- /dev/null +++ b/raymarching/raymarching.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/raymarching/raymarching.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate b/raymarching/raymarching.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..94f3cc3 Binary files /dev/null and b/raymarching/raymarching.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/raymarching/raymarching.playground/timeline.xctimeline b/raymarching/raymarching.playground/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/raymarching/raymarching.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + +