From 720e3b1b64ff1ca4cba9254b8b6845437c79dff7 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 14 Oct 2018 12:51:24 -0700 Subject: [PATCH] Render sampled grid with colors and stuff! --- MetaballsKit/MarchingSquares.metal | 10 +++- MetaballsKit/MarchingSquares.swift | 95 +++++++++--------------------- MetaballsKit/Renderer.swift | 32 +++++----- 3 files changed, 55 insertions(+), 82 deletions(-) diff --git a/MetaballsKit/MarchingSquares.metal b/MetaballsKit/MarchingSquares.metal index 64207bf..d5051ba 100644 --- a/MetaballsKit/MarchingSquares.metal +++ b/MetaballsKit/MarchingSquares.metal @@ -19,6 +19,7 @@ struct RasterizerData { float4 position [[position]]; float4 color; float2 textureCoordinate; + int instance; }; vertex RasterizerData @@ -34,12 +35,17 @@ gridVertexShader(constant Vertex *vertexes [[buffer(0)]], RasterizerData out; out.position = renderParameters.projection * rect.transform * float4(v.position.xy, 0, 1); + out.color = rect.color; out.textureCoordinate = v.textureCoordinate; + out.instance = instid; return out; } fragment float4 -gridFragmentShader(RasterizerData in [[stage_in]]) +gridFragmentShader(RasterizerData in [[stage_in]], + constant float *samples [[buffer(0)]]) { - return in.color; + int instance = in.instance; + float sample = samples[instance]; + return sample > 1.0 ? in.color : float4(0); } diff --git a/MetaballsKit/MarchingSquares.swift b/MetaballsKit/MarchingSquares.swift index 5be37f6..1349d0a 100644 --- a/MetaballsKit/MarchingSquares.swift +++ b/MetaballsKit/MarchingSquares.swift @@ -13,12 +13,13 @@ class MarchingSquares { private var field: Field private var sampleGridSize = Size(16) + private var semaphore: DispatchSemaphore + /// Samples of the field's current state. - private(set) var samples: MTLTexture? + private(set) var samplesBuffer: MTLBuffer? /// Indexes of geometry to render. private(set) var indexes: MTLTexture? - private var lastGridCount: Int = 0 private(set) var gridGeometry: MTLBuffer? private var xSamples: Int { @@ -29,12 +30,15 @@ class MarchingSquares { return Int(field.size.y / sampleGridSize.y) } + private var lastSamplesCount = 0 + var samplesCount: Int { return xSamples * ySamples } init(field: Field) { self.field = field + semaphore = DispatchSemaphore(value: 1) } func setupMetal(withDevice device: MTLDevice) { @@ -54,15 +58,16 @@ class MarchingSquares { } func fieldDidResize() { - guard let gridGeometry = gridGeometry else { + guard let device = gridGeometry?.device else { return } - createGridGeometryBuffer(withDevice: gridGeometry.device) - populateGrid(withDevice: gridGeometry.device) + populateGrid(withDevice: device) + populateSamples(withDevice: device) + lastSamplesCount = samplesCount } func populateGrid(withDevice device: MTLDevice) { - guard lastGridCount != samplesCount else { + guard lastSamplesCount != samplesCount else { return } @@ -77,7 +82,8 @@ class MarchingSquares { for y in 0...stride - - for xSample in 0...stride - - for x in 0.. 1.0 ? 0b1000 : 0) + - (samples[1] > 1.0 ? 0b0100 : 0) + - (samples[2] > 1.0 ? 0b0001 : 0) + - (samples[3] > 1.0 ? 0b0010 : 0) - - let origin = MTLOrigin(x: x, y: y, z: 0) - let size = MTLSize(width: 1, height: 1, depth: 1) - let region = MTLRegion(origin: origin, size: size) - let indexArr = [index] - indexes.replace(region: region, mipmapLevel: 0, withBytes: indexArr, bytesPerRow: bytesPerRow) - } + let samplesLength = MemoryLayout.stride * samplesCount + if let buffer = device.makeBuffer(length: MemoryLayout.stride * samples.count, options: .storageModeShared) { + memcpy(buffer.contents(), samples, samplesLength) + samplesBuffer = buffer + } else { + fatalError("Couldn't create buffer for samples") } } - - private func getSampleBlock(x: Int, y: Int) -> [Float]? { - guard let samples = samples else { - return nil - } - - var block: [Float] = [0, 0, 0, 0] - let bytesPerRow = samples.width * MemoryLayout.stride - let origin = MTLOrigin(x: x, y: y, z: 0) - let size = MTLSize(width: 2, height: 2, depth: 1) - let region = MTLRegion(origin: origin, size: size) - samples.getBytes(&block, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0) - - return block - } } diff --git a/MetaballsKit/Renderer.swift b/MetaballsKit/Renderer.swift index 68312d8..d7a554e 100644 --- a/MetaballsKit/Renderer.swift +++ b/MetaballsKit/Renderer.swift @@ -45,6 +45,7 @@ public class Renderer: NSObject, MTKViewDelegate { delegate.field.setupMetal(withDevice: device) delegate.marchingSquares.setupMetal(withDevice: device) delegate.marchingSquares.populateGrid(withDevice: device) + delegate.marchingSquares.populateSamples(withDevice: device) } } @@ -207,6 +208,9 @@ public class Renderer: NSObject, MTKViewDelegate { buffer.label = "Metaballs Command Buffer" field.update() + if let ms = delegate?.marchingSquares { + ms.populateSamples(withDevice: device) + } if self.pixelGeometry == nil { self.pixelGeometry = self.pixelGeometry(forViewSize: view.drawableSize) @@ -215,24 +219,24 @@ public class Renderer: NSObject, MTKViewDelegate { if let renderPass = view.currentRenderPassDescriptor { // Render the per-pixel metaballs - if let pipeline = pixelPipeline, - let encoder = buffer.makeRenderCommandEncoder(descriptor: renderPass) { - encoder.label = "Pixel Render" - encoder.setRenderPipelineState(pipeline) - encoder.setVertexBytes(pixelGeometry, length: pixelGeometry.count * MemoryLayout.stride, index: 0) - encoder.setVertexBuffer(parametersBuffer, offset: 0, index: 1) - encoder.setFragmentBuffer(field.parametersBuffer, offset: 0, index: 0) - encoder.setFragmentBuffer(field.ballBuffer, offset: 0, index: 1) - encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 6) - encoder.endEncoding() - didEncode = true - } +// if let pipeline = pixelPipeline, +// let encoder = buffer.makeRenderCommandEncoder(descriptor: renderPass) { +// encoder.label = "Pixel Render" +// encoder.setRenderPipelineState(pipeline) +// encoder.setVertexBytes(pixelGeometry, length: pixelGeometry.count * MemoryLayout.stride, index: 0) +// encoder.setVertexBuffer(parametersBuffer, offset: 0, index: 1) +// encoder.setFragmentBuffer(field.parametersBuffer, offset: 0, index: 0) +// encoder.setFragmentBuffer(field.ballBuffer, offset: 0, index: 1) +// encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 6) +// encoder.endEncoding() +// didEncode = true +// } if let marchingSquares = delegate?.marchingSquares { // Render the marching squares version over top of the pixel version. // We need our own render pass descriptor that specifies that we load the results of the previous pass to make this render pass appear on top of the other. let pass = renderPass.copy() as! MTLRenderPassDescriptor - pass.colorAttachments[0].loadAction = .load +// pass.colorAttachments[0].loadAction = .load if let pipeline = marchingSquaresPipeline, let encoder = buffer.makeRenderCommandEncoder(descriptor: pass) { encoder.label = "Marching Squares Grid Render" @@ -240,7 +244,7 @@ public class Renderer: NSObject, MTKViewDelegate { encoder.setVertexBytes(Rect.geometry, length: MemoryLayout.stride * Rect.geometry.count, index: 0) encoder.setVertexBuffer(marchingSquares.gridGeometry, offset: 0, index: 1) encoder.setVertexBuffer(parametersBuffer, offset: 0, index: 2) - encoder.setTriangleFillMode(.lines) + encoder.setFragmentBuffer(marchingSquares.samplesBuffer, offset: 0, index: 0) encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: Rect.geometry.count, instanceCount: marchingSquares.samplesCount) encoder.endEncoding() didEncode = true