I know that CustomMaterial in RealityKit can update texture by use DrawableQueue, but in new VisionOS, CustomMaterial doesn't work anymore. How i can do the same thing,does ShaderGraphMaterial can do?I can't find example about how to do that. Looking forward your repley, thank you!
Hello,
Yes, you can update input texture resources of a ShaderGraphMaterial using a DrawableQueue, below is a self-contained snippet that demonstrates this.
Important: The particulars of when/where/how you request and render to the nextDrawable depend on the exact use-case in your app. This snippet uses a Timer and CIContext for convenience of demonstration only, it is not intended to demonstrate a best practice for the functionality that it demonstrates.
import SwiftUI
import RealityKit
import RealityKitContent
import Combine
struct ContentView: View {
let drawableQueue = try! TextureResource.DrawableQueue(.init(pixelFormat: .bgra8Unorm, width: 256, height: 256, usage: [.renderTarget, .shaderRead, .shaderWrite], mipmapsMode: .none))
let context = CIContext()
@State private var cancellables = Set<AnyCancellable>()
var body: some View {
RealityView { content in
do {
var dynamicMaterial = try await ShaderGraphMaterial(named: "/Root/DynamicMaterial", from: "Scene.usda", in: realityKitContentBundle)
let color = CIImage(color: .red).cropped(to: CGRect(origin: .zero, size: .init(width: 256, height: 256)))
let image = context.createCGImage(color, from: color.extent)!
let resource = try await TextureResource.generate(from: image, options: .init(semantic: .color))
resource.replace(withDrawables: drawableQueue)
try dynamicMaterial.setParameter(name: "DiffuseColorImageInput", value: .textureResource(resource))
let box = Entity()
box.name = "box"
box.components.set(ModelComponent(mesh: .generateBox(size: 0.1), materials: [dynamicMaterial]))
content.add(box)
} catch {
fatalError(error.localizedDescription)
}
}.task {
Timer.publish(every: 0.5, on: .main, in: .common).autoconnect().sink { output in
let t = output.timeIntervalSince1970
let red = abs(sin(t))
let color = CIImage(color: .init(red: red, green: 0, blue: 0)).cropped(to: CGRect(origin: .zero, size: .init(width: 256, height: 256)))
do {
let nextDrawable = try drawableQueue.nextDrawable()
context.render(color, to: nextDrawable.texture, commandBuffer: nil, bounds: color.extent, colorSpace: CGColorSpace(name: CGColorSpace.displayP3)!)
nextDrawable.present()
} catch {
print(error.localizedDescription)
}
}.store(in: &cancellables)
}
}
}
And here is a screenshot of the Shader Graph in Reality Composer Pro: