Reputation: 10896
I can successfully load a custom ShaderGraphMaterial
material loaded from a .usda
file created with Reality Composer
var shotTrailMaterial : ShaderGraphMaterial? = nil
do {
...
let materialData = try Data(contentsOf: materialURL)
shotTrailMaterial = try await ShaderGraphMaterial(named:"/Root/Material",
from: materialData)
} catch { ... }
for which I can set the "fractionOpaque"
custom property to a floating point value
try shotTrailMaterial.setParameter(name: "fractionOpaque", value: .float(0.9))
The above works well for the entities I create with this material. Now I would like to animate the material based on this parameter but the following fails:
let anim = FromToByAnimation<Float>(name: "foo",
from: 0.0,
to: 1.0,
duration: 3.0,
bindTarget: .parameter("fractionOpaque"))
if let animResource = try? AnimationResource.generate(with: anim) {
entity.playAnimation(animResource, transitionDuration: 3.0, startsPaused: false)
}
I get the error
Cannot find a BindPoint for any bind path: "KeyValue.keyValueStore[fractionOpaque]"
Clearly my key path is wrong for the bindTarget:
parameter. I want to set the "fractionOpaque"
property on material 0, but I am not sure what the correct path for this is? This is a Vision OS app.
Upvotes: 3
Views: 659
Reputation: 58553
Quite possible that someone will find another way to animate the MaterialX parameters (loaded from Reality Composer Pro) in visionOS RealityKit app, but this one is the only way I have found so far.
import SwiftUI
import RealityKit
import RealityKitContent
struct ContentView: View {
@State var amount: CGFloat = 0.0
@State var timer: Timer? = nil
var body: some View {
RealityView { content in
if var material = try? await ShaderGraphMaterial(named: "/Root/MetallicGoldPULeather",
from: "Scene.usda",
in: realityKitContentBundle) {
try! material.setParameter(name: "Basecolor_Tint",
value: .color(.red))
let sphere = ModelEntity(mesh: .generateSphere(radius: 0.4),
materials: [material])
content.add(sphere)
}
} update: { content in
if let entity = content.entities.first as? ModelEntity,
var material = entity.model?.materials.first as? ShaderGraphMaterial {
Task {
self.timer = Timer.scheduledTimer(withTimeInterval: 0.02,
repeats: true) { _ in
Task { @MainActor in
if amount <= 1.0 {
self.amount += 0.01
try! material.setParameter(name: "Basecolor_Tint",
value: .color(.init(red: 1,
green: amount,
blue: amount,
alpha: 1)))
print(amount)
entity.model?.materials = [material]
}
}
}
self.timer?.fire()
// destroying
try await Task.sleep(nanoseconds: 3_000_000_000)
self.timer?.invalidate()
self.timer = nil
print("Timer is:", (self.timer?.isValid) as Any)
}
}
}
}
}
I load MaterialX from an RCP's cone scene and assign that material to a sphere primitive.
Upvotes: 4