[all] It works!
This commit is contained in:
parent
dfa603012f
commit
8dcd0910f1
4 changed files with 73 additions and 66 deletions
|
@ -86,11 +86,11 @@ class Renderer: NSObject, MTKViewDelegate {
|
|||
Vertex(position: Point(x: 1, y: 1), textureCoordinate: Point(x: 1, y: 1))
|
||||
]
|
||||
|
||||
do {
|
||||
try field.updateBuffers()
|
||||
} catch let e {
|
||||
NSLog("Error updating buffers: \(e)")
|
||||
}
|
||||
// do {
|
||||
// try field.updateBuffers()
|
||||
// } catch let e {
|
||||
// NSLog("Error updating buffers: \(e)")
|
||||
// }
|
||||
|
||||
let buffer = commandQueue.makeCommandBuffer()
|
||||
buffer.label = "Render"
|
||||
|
|
|
@ -24,12 +24,8 @@ typedef struct {
|
|||
float2 textureCoordinate;
|
||||
} RasterizerData;
|
||||
|
||||
typedef struct {
|
||||
int2 size;
|
||||
int numberOfBalls;
|
||||
} Parameters;
|
||||
|
||||
typedef half3 Ball;
|
||||
typedef int3 Parameters;
|
||||
typedef float3 Ball;
|
||||
|
||||
vertex RasterizerData
|
||||
passthroughVertexShader(uint vid [[vertex_id]],
|
||||
|
@ -42,20 +38,21 @@ passthroughVertexShader(uint vid [[vertex_id]],
|
|||
return out;
|
||||
}
|
||||
|
||||
float sampleAtPoint(float2, constant Ball*, uint);
|
||||
float sampleAtPoint(float2, constant Ball*, int);
|
||||
|
||||
fragment float4
|
||||
sampleToColorShader(RasterizerData in [[stage_in]],
|
||||
constant Parameters& parameters [[buffer(0)]],
|
||||
constant Ball* balls [[buffer(1)]])
|
||||
{
|
||||
const float sample = sampleAtPoint(in.textureCoordinate, balls, parameters.numberOfBalls);
|
||||
const uint numberOfBalls = parameters.z;
|
||||
const float sample = sampleAtPoint(in.position.xy, balls, numberOfBalls);
|
||||
|
||||
float4 out;
|
||||
if (sample > 1.0) {
|
||||
out = float4(0.0, 1.0, 0.0, 0.0);
|
||||
out = float4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
out = float4(0.0, 0.0, 0.0, 0.0);
|
||||
out = float4(0.2, 0.2, 0.2, 1.0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -63,11 +60,11 @@ sampleToColorShader(RasterizerData in [[stage_in]],
|
|||
float
|
||||
sampleAtPoint(float2 point,
|
||||
constant Ball* balls,
|
||||
uint count)
|
||||
int count)
|
||||
{
|
||||
float sample = 0.0;
|
||||
for (uint i = 0; i < count; i++) {
|
||||
constant Ball& ball = balls[i];
|
||||
for (int i = 0; i < count; i++) {
|
||||
Ball ball = balls[i];
|
||||
float r2 = ball.z * ball.z; // Radius stored in z coordinate.
|
||||
float xDiff = point.x - ball.x;
|
||||
float yDiff = point.y - ball.y;
|
||||
|
|
|
@ -26,6 +26,12 @@ public struct Point {
|
|||
}
|
||||
}
|
||||
|
||||
extension Point: CustomStringConvertible {
|
||||
public var description: String {
|
||||
return "(\(x), \(y))"
|
||||
}
|
||||
}
|
||||
|
||||
public struct Vector {
|
||||
var dx: Float
|
||||
var dy: Float
|
||||
|
@ -39,3 +45,9 @@ public struct Vector {
|
|||
self.dy = dy
|
||||
}
|
||||
}
|
||||
|
||||
extension Vector: CustomStringConvertible {
|
||||
public var description: String {
|
||||
return "(\(dx), \(dy))"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,17 +46,10 @@ public class Field {
|
|||
balls = balls.filter { bounds.contains($0.bounds) }
|
||||
|
||||
// Update Metal state as needed.
|
||||
// updateThreadgroupSizes(withFieldSize: size)
|
||||
// parametersBuffer = nil
|
||||
// sampleTexture = nil
|
||||
populateParametersBuffer()
|
||||
if numberOfBallsBeforeFilter != balls.count {
|
||||
ballBuffer = nil
|
||||
}
|
||||
do {
|
||||
try updateBuffers()
|
||||
} catch let e {
|
||||
NSLog("Error updating size: \(e)")
|
||||
return
|
||||
populateBallBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +98,10 @@ public class Field {
|
|||
let ball = Ball(radius: radius, position: position, velocity: Vector())
|
||||
balls.append(ball)
|
||||
NSLog("Added ball \(ball); fieldSize=\(size)")
|
||||
|
||||
populateParametersBuffer()
|
||||
ballBuffer = nil
|
||||
populateBallBuffer()
|
||||
}
|
||||
|
||||
// MARK: - Metal Configuration
|
||||
|
@ -120,23 +117,55 @@ public class Field {
|
|||
// private var threadgroupSize = MTLSize(width: 16, height: 16, depth: 1)
|
||||
|
||||
/// Create the Metal buffer containing basic parameters of the simulation.
|
||||
private func makeParametersBufferIfNeeded(withDevice device: MTLDevice) -> MTLBuffer? {
|
||||
private func populateParametersBuffer() {
|
||||
if parametersBuffer == nil {
|
||||
parametersBuffer = device.makeBuffer(length: MemoryLayout<Int>.stride * 3, options: [])
|
||||
guard let device = self.device else { return }
|
||||
let length = 16 // A Parameters struct in shader-land is an int3, which takes 16 bytes.
|
||||
parametersBuffer = device.makeBuffer(length: length, options: [])
|
||||
NSLog("Making parameters buffer, length:\(length)")
|
||||
}
|
||||
|
||||
if let parameters = parametersBuffer {
|
||||
var ptr = parameters.contents()
|
||||
var width = UInt32(size.width)
|
||||
parameters.addDebugMarker("Width", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
|
||||
ptr = write(value: &width, to: ptr)
|
||||
var height = UInt32(size.height)
|
||||
parameters.addDebugMarker("Height", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
|
||||
ptr = write(value: &height, to: ptr)
|
||||
var numberOfBalls = UInt32(self.balls.count)
|
||||
parameters.addDebugMarker("Number Of Balls", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
|
||||
ptr = write(value: &numberOfBalls, to: ptr)
|
||||
NSLog("Populated parameters: w:\(width), h:\(height), n:\(numberOfBalls)")
|
||||
}
|
||||
return parametersBuffer
|
||||
}
|
||||
|
||||
/// Create a Metal buffer containing the current set of metaballs.
|
||||
/// @param device The Metal device to use to create the buffer.
|
||||
/// @return A new buffer containing metaball data.
|
||||
private func makeBallBufferIfNeeded(withDevice device: MTLDevice) -> MTLBuffer? {
|
||||
private func populateBallBuffer() {
|
||||
if ballBuffer == nil && balls.count > 0 {
|
||||
let sizeOfBall = MemoryLayout<Float>.stride * 3 // A Ball in shader-land is a float3.
|
||||
guard let device = self.device else { return }
|
||||
let sizeOfBall = 16 // A Ball in shader-land is a float3, which takes 16 bytes.
|
||||
let length = balls.count * sizeOfBall
|
||||
NSLog("Making ball buffer, length:\(length)")
|
||||
ballBuffer = device.makeBuffer(length: length, options: [])
|
||||
}
|
||||
return ballBuffer
|
||||
|
||||
if let ballBuffer = ballBuffer {
|
||||
var ptr = ballBuffer.contents()
|
||||
var idx = 0
|
||||
for var ball in self.balls {
|
||||
ballBuffer.addDebugMarker("Ball \(idx)", range: NSRange(location: ballBuffer.contents().distance(to: ptr), length: 16))
|
||||
ptr = write(value: &ball.position.x, to: ptr)
|
||||
ptr = write(value: &ball.position.y, to: ptr)
|
||||
var r = ball.radius
|
||||
ptr = write(value: &r, to: ptr)
|
||||
ptr = ptr.advanced(by: 4) // Skip 4 bytes to maintain alignment.
|
||||
NSLog("Populated ball: x:\(ball.position.x), y:\(ball.position.y), r:\(r)")
|
||||
idx += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Metal texture to hold sample values created by the sampling compute shader.
|
||||
|
@ -162,37 +191,6 @@ public class Field {
|
|||
// threadgroupCount = MTLSize(width: width + threadgroupSize.width - 1, height: height + threadgroupSize.height - 1, depth: 1)
|
||||
// }
|
||||
|
||||
/// Copy metaballs data into the parameters buffer.
|
||||
public func updateBuffers() throws {
|
||||
guard let device = self.device else {
|
||||
throw MetaballsError.metalError("Missing Metal device for update")
|
||||
}
|
||||
|
||||
guard let parameters = makeParametersBufferIfNeeded(withDevice: device),
|
||||
let balls = makeBallBufferIfNeeded(withDevice: device)
|
||||
else {
|
||||
throw MetaballsError.metalError("Couldn't create buffers")
|
||||
}
|
||||
|
||||
var ptr = parameters.contents()
|
||||
|
||||
var width = Int(size.width)
|
||||
ptr = write(value: &width, to: ptr)
|
||||
var height = Int(size.height)
|
||||
ptr = write(value: &height, to: ptr)
|
||||
|
||||
var numberOfBalls = self.balls.count
|
||||
ptr = write(value: &numberOfBalls, to: ptr)
|
||||
|
||||
ptr = balls.contents()
|
||||
for var ball in self.balls {
|
||||
ptr = write(value: &ball.position.x, to: ptr)
|
||||
ptr = write(value: &ball.position.y, to: ptr)
|
||||
var r = ball.radius
|
||||
ptr = write(value: &r, to: ptr)
|
||||
}
|
||||
}
|
||||
|
||||
private func write<T>(value: inout T, to ptr: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
|
||||
let sizeOfType = MemoryLayout<T>.stride
|
||||
ptr.copyBytes(from: &value, count: sizeOfType)
|
||||
|
@ -206,8 +204,8 @@ public class Field {
|
|||
NSLog("Setting up Metal")
|
||||
self.device = device
|
||||
// sampleComputeState = try computePipelineStateForSamplingKernel(withDevice: device)
|
||||
parametersBuffer = makeParametersBufferIfNeeded(withDevice: device)
|
||||
ballBuffer = makeBallBufferIfNeeded(withDevice: device)
|
||||
populateParametersBuffer()
|
||||
populateBallBuffer()
|
||||
}
|
||||
|
||||
// public func computePipelineStateForSamplingKernel(withDevice device: MTLDevice) throws -> MTLComputePipelineState? {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue