I'm trying to create heat maps for a variety of functions of two variables. My first implementation didn't use Metal and was far too slow so now I'm looking into doing it with Metal.
I managed to get a very simple example running but I can't figure out how to pass different functions to the fragment shader. Here's the example:
in ContentView.swift:
struct ContentView: View {
var body: some View {
Rectangle()
.aspectRatio(contentMode: .fit)
.visualEffect { content, gp in
let width = Shader.Argument.float(gp.size.width)
let height = Shader.Argument.float(gp.size.height)
return content.colorEffect(
ShaderLibrary.heatMap(width, height)
)
}
}
}
in Shader.metal:
#include <metal_stdlib>
using namespace metal;
constant float twoPi = 6.283185005187988;
// input in [0,1], output in [0,1]
float f(float x) { return (sin(twoPi * x) + 1) / 2; }
// inputs in [0,1], output in [0,1]
float g(float x, float y) { return f(x) * f(y); }
[[ stitchable ]] half4 heatMap(float2 pos, half4 color, float width, float height) {
float u = pos.x / width;
float v = pos.y / height;
float c = g(u, v);
return half4(c/2, 1-c, c, 1);
}
As it is, it works great and is blazing fast...
...but the function I'm heat-mapping is hardcoded in the metal file. I'd like to be able to write different functions in Swift and pass them to the shader from within SwiftUI (ie, from the ContentView, by querying a model to get the function).
I tried something like this in the metal file:
// (u, v) in [0,1] x [0,1]
// w = f(u, v) in [0,1]
[[ stitchable ]] half4 heatMap(
float2 pos, half4 color,
float width, float height,
float (*f) (float u, float v),
half4 (*c) (float w)
) {
float u = pos.x / width;
float v = pos.y / height;
float w = f(u, v);
return c(w);
}
but I couldn't get Swift and C++ to work together to make sense of the function pointers and and now I'm stuck. Any help is greatly appreciated.
Many thanks!
Post
Replies
Boosts
Views
Activity
Say you have the following view:import SwiftUI
struct BindingViewExample_1 : View {
@State var value = false
private var text: String {
"Toggle is " + (value ? "'on'" : "'off'")
}
var body: some View {
HStack {
Toggle(isOn: $value) {
Text(text)
}
}
.padding([.leading, .trailing], 80)
}
}
#if DEBUG
struct BindingViewExample_1_Previews : PreviewProvider {
static var previews: some View {
BindingViewExample_1(value: true)
}
}
#endifThis previews fine and you can interact with the control in the preview and see the changes immediately.But what if it took a *binding* as input? Consider this alternate version of the same view:import SwiftUI
struct BindingViewExample_2 : View {
@Binding var value: Bool
private var text: String {
"Toggle is " + (value ? "'on'" : "'off'")
}
var body: some View {
HStack {
Toggle(isOn: $value) {
Text(text)
}
}
.padding([.leading, .trailing], 80)
}
}
#if DEBUG
struct BindingViewExample_2_Previews : PreviewProvider {
@State static var value = false
static var previews: some View {
BindingViewExample_2(value: $value)
}
}
#endifThe only differences are in line 5 for the View itself, and in the preview code for both views. This compiles without errors but the preview no longer works. XCode just refuses to even create a preview.If you keep the View as is but change the preview code to this, instead,#if DEBUG
struct BindingViewExample_2_Previews : PreviewProvider {
static var previews: some View {
BindingViewExample_2(value: .constant(true))
}
}
#endifXcode now builds and displays a preview but interacting with it doesn't update the view. That's not surprising, given the `.constant(true)` binding, but that's the only way I managed to make the preview display when the View takes a binding and that's not very useful (since I can't interact with it).So... what's the right way to write preview code for a View that takes bindings as inputs?
Hello,
I'd like to perform some math on a fairly large number of CGPoint instances stored in an array so I thought I'd look into using Accelerate and start by conforming CGPoint to AccelerateBuffer, followed by extending Array to conform as well.
My problem is that I don't understand what to do with the requirement
public func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<CGFloat>) throws -> R) rethrows -> R
How am I supposed to implement this? Are there any code examples somewhere that I can look into?
Many thanks.