added particles
This commit is contained in:
parent
996ebf1260
commit
3bb25af63a
|
|
@ -29,3 +29,4 @@ Repository to accompany the following blog posts:
|
||||||
- [Introducing Metal 2](http://metalkit.org/2017/06/30/introducing-metal-2.html)
|
- [Introducing Metal 2](http://metalkit.org/2017/06/30/introducing-metal-2.html)
|
||||||
- [Using ARKit with Metal](http://metalkit.org/2017/07/29/using-arkit-with-metal.html)
|
- [Using ARKit with Metal](http://metalkit.org/2017/07/29/using-arkit-with-metal.html)
|
||||||
- [Using ARKit with Metal part 2](http://metalkit.org/2017/08/31/using-arkit-with-metal-part-2.html)
|
- [Using ARKit with Metal part 2](http://metalkit.org/2017/08/31/using-arkit-with-metal-part-2.html)
|
||||||
|
- [Working with Particles in Metal](http://metalkit.org/2017/09/30/working-with-particles-in-metal.html)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
import MetalKit
|
||||||
|
import PlaygroundSupport
|
||||||
|
|
||||||
|
let frame = NSRect(x: 0, y: 0, width: 400, height: 400)
|
||||||
|
let delegate = MetalView()
|
||||||
|
let view = MTKView(frame: frame, device: delegate.device)
|
||||||
|
view.delegate = delegate
|
||||||
|
PlaygroundPage.current.liveView = view
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct Particle {
|
||||||
|
float2 center;
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
float distanceToParticle(float2 point, Particle p) {
|
||||||
|
return length(point - p.center) - p.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void compute(texture2d<float, access::write> 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);
|
||||||
|
float2 center = float2(0.5, time);
|
||||||
|
float radius = 0.05;
|
||||||
|
float stop = 1 - radius;
|
||||||
|
if (time >= stop) { center.y = stop; }
|
||||||
|
else center.y = time;
|
||||||
|
Particle p = Particle{center, radius};
|
||||||
|
float distance = distanceToParticle(uv, p);
|
||||||
|
float4 color = float4(1, 0.7, 0, 1);
|
||||||
|
if (distance > 0) { color = float4(0.2, 0.5, 0.7, 1); }
|
||||||
|
output.write(float4(color), gid);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
import MetalKit
|
||||||
|
|
||||||
|
public class MetalView: NSObject, MTKViewDelegate {
|
||||||
|
|
||||||
|
public var device: MTLDevice! = nil
|
||||||
|
var queue: MTLCommandQueue! = nil
|
||||||
|
var cps: MTLComputePipelineState! = nil
|
||||||
|
var timerBuffer: MTLBuffer! = nil
|
||||||
|
var timer: Float = 0
|
||||||
|
|
||||||
|
override public init() {
|
||||||
|
super.init()
|
||||||
|
device = MTLCreateSystemDefaultDevice()
|
||||||
|
queue = device.makeCommandQueue()
|
||||||
|
registerShaders()
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerShaders() {
|
||||||
|
guard let path = Bundle.main.path(forResource: "Shaders", ofType: "metal") else { return }
|
||||||
|
do {
|
||||||
|
let input = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
|
||||||
|
let library = try device.makeLibrary(source: input, options: nil)
|
||||||
|
guard let kernel = library.makeFunction(name: "compute") else { return }
|
||||||
|
cps = try device.makeComputePipelineState(function: kernel)
|
||||||
|
} catch let e {
|
||||||
|
Swift.print("\(e)")
|
||||||
|
}
|
||||||
|
timerBuffer = device.makeBuffer(length: MemoryLayout<Float>.size, options: [])
|
||||||
|
}
|
||||||
|
|
||||||
|
func update() {
|
||||||
|
timer += 0.01
|
||||||
|
let bufferPointer = timerBuffer.contents()
|
||||||
|
memcpy(bufferPointer, &timer, MemoryLayout<Float>.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, index: 0)
|
||||||
|
commandEncoder.setBuffer(timerBuffer, offset: 0, index: 0)
|
||||||
|
update()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
|
||||||
|
<timeline fileName='timeline.xctimeline'/>
|
||||||
|
</playground>
|
||||||
7
particles/particle.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
particles/particle.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Timeline
|
||||||
|
version = "3.0">
|
||||||
|
<TimelineItems>
|
||||||
|
</TimelineItems>
|
||||||
|
</Timeline>
|
||||||
Loading…
Reference in New Issue