Merged feature-graph into dev

This commit is contained in:
vinivendra 2016-02-11 23:32:46 -05:00
commit db76528513
6 changed files with 128 additions and 23 deletions

View File

@ -12,6 +12,7 @@
2426868D1C63B72A00D62456 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2426868B1C63B72A00D62456 /* Main.storyboard */; };
2426868F1C63B72A00D62456 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2426868E1C63B72A00D62456 /* Assets.xcassets */; };
242686921C63B72A00D62456 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 242686901C63B72A00D62456 /* LaunchScreen.storyboard */; };
249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249CF84B1C6D113C008B0C78 /* Matrix.swift */; };
24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */; };
24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */; };
24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */; };
@ -57,6 +58,7 @@
2426868E1C63B72A00D62456 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
242686911C63B72A00D62456 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
242686931C63B72A00D62456 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
249CF84B1C6D113C008B0C78 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKit.swift; sourceTree = "<group>"; };
24E1E7E11C67D37F00ECF1C4 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
@ -135,6 +137,7 @@
24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */,
24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
249CF84B1C6D113C008B0C78 /* Matrix.swift */,
24E1E7EF1C67D74300ECF1C4 /* shaders.metal */,
2426868B1C63B72A00D62456 /* Main.storyboard */,
2426868E1C63B72A00D62456 /* Assets.xcassets */,
@ -295,6 +298,7 @@
24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */,
24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */,
24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */,
249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */,
24FFA8791C6BA038005ACD60 /* Cycle.swift in Sources */,
24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */,
24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */,

72
PixelImage/Matrix.swift Normal file
View File

@ -0,0 +1,72 @@
import UIKit
class Graph<T> {
var adjacencyMatrix: Matrix
var vertices: [T]
var size: Int {
get {
return vertices.count
}
}
init(vertices: [T]) {
let size = vertices.count
self.vertices = vertices
self.adjacencyMatrix = Matrix(size: size)
}
func addEdge(i: Int, _ j: Int) {
adjacencyMatrix.set(i, j)
adjacencyMatrix.set(j, i)
}
func removeEdge(i: Int, _ j: Int) {
adjacencyMatrix.reset(i, j)
adjacencyMatrix.reset(j, i)
}
}
struct Matrix: CustomStringConvertible {
var buffer: [Float]
let size: Int
init(size: Int) {
buffer = [Float](count: size * size, repeatedValue: 0.0)
self.size = size
}
func get(i: Int, j: Int) -> Float {
return buffer[index(i, j)]
}
mutating func set(i: Int, _ j: Int, value: Float = 1.0) {
buffer[index(i, j)] = value
}
mutating func reset(i: Int, _ j: Int) {
buffer[index(i, j)] = 0.0
}
private func index(i: Int, _ j: Int) -> Int {
return j * size + i
}
var description: String {
get {
var result = ""
for (index, value) in buffer.enumerate() {
result = result + "\(value)"
if index % size == size - 1 {
result = result + "\n"
} else {
result = result + " "
}
}
return result
}
}
}

View File

@ -2,5 +2,13 @@
import Metal
protocol MetaballDataSource {
var metaballs: [Metaball] { get }
var metaballGraph: Graph<Metaball>! { get }
}
extension MetaballDataSource {
var metaballs: [Metaball]! {
get {
return metaballGraph.vertices
}
}
}

View File

@ -1,8 +1,6 @@
import Metal
import UIKit
var i = 0
class MetalMetaballRenderer {
typealias TargetView = UIImageView
@ -54,8 +52,6 @@ class MetalMetaballRenderer {
let timeout = dispatch_time(DISPATCH_TIME_NOW, 1000000000)
dispatch_semaphore_wait(semaphore, timeout)
print("Update \(i++)!")
state = .Ending
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)) { () -> Void in
@ -108,6 +104,8 @@ class MetalMetaballRenderer {
commandEncoder.setTexture(computeContext.texture, atIndex: 0)
let metaballInfoBuffer = metaballBuffer()
commandEncoder.setBuffer(metaballInfoBuffer, offset: 0, atIndex: 0)
let edgesBuffer = metaballEdgesBuffer()
commandEncoder.setBuffer(edgesBuffer, offset: 0, atIndex: 1)
commandEncoder.dispatchThreadgroups(threadGroups,
threadsPerThreadgroup: threadGroupCounts)
commandEncoder.endEncoding()
@ -163,6 +161,14 @@ class MetalMetaballRenderer {
return image
}
func metaballEdgesBuffer() -> MTLBuffer {
let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
let buffer = context.device.newBufferWithBytes(floats, length: floats.count * sizeof(Float), options: .StorageModeShared)
return buffer
}
func metaballBuffer() -> MTLBuffer {
// Create Float array for buffer
// Exclude metaballs far from the view's bounds

View File

@ -9,9 +9,7 @@ class ViewController: UIViewController, MetaballDataSource {
let width = 350
let height = 600
var metaballs = [CGPoint(x: 70, y: 70), CGPoint(x: 270, y: 470), CGPoint(x: 270, y: 70), CGPoint(x: 70, y: 470)].map {
Metaball(position: $0)
}
var metaballGraph: Graph<Metaball>!
var previousLocation: CGPoint!
var selectedMetaball: Metaball?
@ -22,6 +20,17 @@ class ViewController: UIViewController, MetaballDataSource {
let recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
view.addGestureRecognizer(recognizer)
let metaballs = [CGPoint(x: 70, y: 70), CGPoint(x: 270, y: 70), CGPoint(x: 270, y: 470), CGPoint(x: 70, y: 470)].map {
Metaball(position: $0)
}
metaballGraph = Graph(vertices: metaballs)
metaballGraph.addEdge(0, 1)
metaballGraph.addEdge(0, 3)
metaballGraph.addEdge(1, 2)
metaballGraph.addEdge(2, 3)
metaballGraph.removeEdge(2, 3)
print(metaballGraph.adjacencyMatrix)
let border = 20
let metaballViewFrame = CGRect(x: border/2, y: border/2, width: width, height: height)
renderer = MetalMetaballRenderer(dataSource: self, frame: metaballViewFrame)

View File

@ -5,40 +5,46 @@ using namespace metal;
kernel void
drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]],
constant float *metaballBuffer [[buffer(0)]],
constant float *edgesBuffer[[buffer(1)]],
constant float *metaballBuffer[[buffer(0)]],
uint2 gid[[thread_position_in_grid]]) {
char numberOfMetaballs = metaballBuffer[0];
char metaballArraySize = numberOfMetaballs * 2 + 1;
uint numberOfMetaballs = metaballBuffer[0];
uint metaballArraySize = numberOfMetaballs * 2 + 1;
float sum = 0;
for (char i = 1; i < metaballArraySize; i += 2) {
for (char j = i + 2; j < metaballArraySize; j += 2) {
float2 metaball1 = float2(metaballBuffer[i],
metaballBuffer[i + 1]);
uint i, j, x, y;
float2 metaball2 = float2(metaballBuffer[j],
metaballBuffer[j + 1]);
for (i = 1, x = 0; i < metaballArraySize; i += 2, x += 1) {
for (j = i + 2, y = x + 1; j < metaballArraySize; j += 2, y += 1) {
float2 metaball1 = float2(metaballBuffer[i], metaballBuffer[i + 1]);
float2 metaball2 = float2(metaballBuffer[j], metaballBuffer[j + 1]);
float2 metaball1Vector
= float2(metaball1.x - gid.x, metaball1.y - gid.y);
float2 metaball2Vector
= float2(metaball2.x - gid.x, metaball2.y - gid.y);
float value1 = 2048 / (dot(metaball1Vector, metaball1Vector) + 1);
float value2 = 2048 / (dot(metaball2Vector, metaball2Vector) + 1);
float v = value1 + value2;
float weightedValue = 0.5 * v;
char edgeIndex = y * numberOfMetaballs + x;
float edgeWeight = edgesBuffer[edgeIndex];
float2 direction1 = normalize(metaball1Vector);
float2 direction2 = normalize(metaball2Vector);
float cosine = dot(direction1, direction2);
float value1 = 2048 / (dot(metaball1Vector, metaball1Vector) + 1);
float value2 = 2048 / (dot(metaball2Vector, metaball2Vector) + 1);
float v = value1 + value2;
float link = pow(((1 - cosine) * 0.5), 100);
float weightedLink = 0.6 * link;
float weightedValue = 0.5 * v;
float weightedLink = 0.6 * link * edgeWeight;
sum += mix(0.0, 1.0, step(0.5, weightedValue + weightedLink));
}