如何解决在 SwiftUI 中使用 MetalView?如何在其中放置要显示的内容?
我一直坚持使用 SwiftUI 和 Metal,以至于快要放弃了。
我从 https://developer.apple.com/forums/thread/119112?answerId=654964022#654964022 得到这个例子:
import MetalKit
struct MetalView: NSViewRepresentable {
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: NSViewRepresentableContext<MetalView>) -> MTKView {
let mtkView = MTKView()
mtkView.delegate = context.coordinator
mtkView.preferredFramesPerSecond = 60
mtkView.enableSetNeedsDisplay = true
if let metalDevice = MTLCreateSystemDefaultDevice() {
mtkView.device = metalDevice
}
mtkView.framebufferOnly = false
mtkView.clearColor = MTLClearColor(red: 0,green: 0,blue: 0,alpha: 0)
mtkView.drawableSize = mtkView.frame.size
mtkView.enableSetNeedsDisplay = true
return mtkView
}
func updateNSView(_ nsView: MTKView,context: NSViewRepresentableContext<MetalView>) {
}
class Coordinator : NSObject,MTKViewDelegate {
var parent: MetalView
var metalDevice: MTLDevice!
var metalCommandQueue: MTLCommandQueue!
init(_ parent: MetalView) {
self.parent = parent
if let metalDevice = MTLCreateSystemDefaultDevice() {
self.metalDevice = metalDevice
}
self.metalCommandQueue = metalDevice.makeCommandQueue()!
super.init()
}
func mtkView(_ view: MTKView,drawableSizeWillChange size: CGSize) {
}
func draw(in view: MTKView) {
guard let drawable = view.currentDrawable else {
return
}
let commandBuffer = metalCommandQueue.makeCommandBuffer()
let rpd = view.currentRenderPassDescriptor
rpd?.colorAttachments[0].clearColor = MTLClearColorMake(0,1,1)
rpd?.colorAttachments[0].loadAction = .clear
rpd?.colorAttachments[0].storeAction = .store
let re = commandBuffer?.makeRenderCommandEncoder(descriptor: rpd!)
re?.endEncoding()
commandBuffer?.present(drawable)
commandBuffer?.commit()
}
}
}
...但我无法理解如何使用这个 MetalView(),当我从 SwiftUI 视图调用它时,它似乎确实有效,以显示数据。我想用它来显示一个 CIImage,它将被 CIFilters 过滤和操作...
有人能指出我如何告诉这个视图如何显示某些东西的正确方向吗?我想我需要它来显示纹理的内容,但尝试了无数个小时,结果从头开始无数次......
这就是我现在运行图像过滤器的方式,但它会导致滑块非常慢,这就是我决定尝试了解 Metal 的原因……但这真的很耗时,而且。由于缺乏文档而令人沮丧...
func ciExposure (inputImage: CIImage,inputEV: Double) -> CIImage {
let filter = CIFilter(name: "CIExposureAdjust")!
filter.setValue(inputImage,forKey: kCIInputImageKey)
filter.setValue(inputEV,forKey: kCIInputEVKey)
return filter.outputImage!
}
我想我需要把那个 filter.outputImage 以某种方式传递给 MetalView?
真的非常感谢任何帮助...
解决方法
我有一个小的 Core Image + SwiftUI 示例项目 on Github,这对您来说可能是一个很好的起点。它还没有涵盖很多,但它已经演示了如何显示过滤后的相机帧。
特别检查视图的 draw
function。它用于将 CIImage
渲染到 MTKView
中(您可以在委托的 draw
函数中执行相同操作)。
好的,这对我有用:
func draw(in view: MTKView) {
guard let drawable = view.currentDrawable else {
return
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let commandBuffer = metalCommandQueue.makeCommandBuffer()
let rpd = view.currentRenderPassDescriptor
rpd?.colorAttachments[0].clearColor = MTLClearColorMake(0,1,1)
rpd?.colorAttachments[0].loadAction = .clear
rpd?.colorAttachments[0].storeAction = .store
let re = commandBuffer?.makeRenderCommandEncoder(descriptor: rpd!)
re?.endEncoding()
context.render((AppState.shared.rawImage ?? AppState.shared.rawImageOriginal)!,to: drawable.texture,commandBuffer: commandBuffer,bounds: AppState.shared.rawImageOriginal!.extent,colorSpace: colorSpace)
commandBuffer?.present(drawable)
commandBuffer?.commit()
}
AppState.shared.rawImage 是我从过滤函数中得到的 CIImage 纹理。
上下文是在其他地方制作的,但应该是:
context = CIContext(mtlDevice: metalDevice)
接下来是添加 Frank Schlegel 提供的代码的居中部分。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。