【问题标题】:Metal API View has no Render Pass DescriptorMetal API 视图没有渲染通道描述符
【发布时间】:2020-04-20 06:55:38
【问题描述】:

我目前正在尝试在不使用 Xcode 中的 IB 的情况下构建一个金属应用程序(纯粹以编程方式,没有情节提要),并且在使用 MTKView Delegate 进行渲染时遇到了一些问题。

我创建了以下 3 个类

应用代理:

import Cocoa
import MetalKit

class AppDelegate: NSObject, NSApplicationDelegate
{
    var newWindow: NSWindow?
    var controller: ViewController?

    func applicationDidFinishLaunching(_ notification: Notification) {
        newWindow = NSWindow(contentRect: NSMakeRect(10, 10, 300, 300), styleMask: [.miniaturizable, .closable, .resizable, .titled], backing: .buffered, defer: false)

        controller = ViewController()
        let content = newWindow!.contentView! as NSView
        let view = controller!.view
        content.addSubview(view)
        newWindow!.makeKeyAndOrderFront(nil)
    }

}

视图控制器:

import Cocoa
import MetalKit

class ViewController: NSViewController {

    var renderer: Renderer?

    override func loadView() {
        view = MTKView.init()
    }

    override func viewDidLoad() {
        guard let metalView = view as? MTKView else {
            fatalError("Cant Get Metal View")
        }

        super.viewDidLoad()

        renderer = Renderer(metalView: metalView)
    }
}

渲染器.swift:

import MetalKit

class Renderer: NSObject {

  static var device: MTLDevice!
  static var commandQueue: MTLCommandQueue!
  var mesh: MTKMesh!
  var vertexBuffer: MTLBuffer!
  var pipelineState: MTLRenderPipelineState!

  init(metalView: MTKView) {

    guard
      let device = MTLCreateSystemDefaultDevice(),
      let commandQueue = device.makeCommandQueue() else {
        fatalError("GPU not available")
    }

    Renderer.device = device
    Renderer.commandQueue = commandQueue
    metalView.device = device

    let mdlMesh = Primative.makeCube(device: device, size: 1)

    do {
      mesh = try MTKMesh(mesh: mdlMesh, device: device)
    } catch let error {
      print(error.localizedDescription)
    }
    vertexBuffer = mesh.vertexBuffers[0].buffer

    let library = device.makeDefaultLibrary()
    let vertexFunction = library?.makeFunction(name: "vertex_main")
    let fragmentFunction = library?.makeFunction(name: "fragment_main")

    let pipelineDescriptor = MTLRenderPipelineDescriptor()
    pipelineDescriptor.vertexFunction = vertexFunction
    pipelineDescriptor.fragmentFunction = fragmentFunction
    pipelineDescriptor.vertexDescriptor =
      MTKMetalVertexDescriptorFromModelIO(mdlMesh.vertexDescriptor)
    pipelineDescriptor.colorAttachments[0].pixelFormat = metalView.colorPixelFormat
    do {
      pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
    } catch let error {
      fatalError(error.localizedDescription)
    }

    super.init()
    metalView.clearColor = MTLClearColor(red: 1.0, green: 1.0,
                                         blue: 0.8, alpha: 1.0)
    metalView.delegate = self
  }
}

extension Renderer: MTKViewDelegate {
  func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {

  }

  func draw(in view: MTKView) {
    // Creating Render Pass Descriptor
        if let descriptor = view.currentRenderPassDescriptor
        {
            print("Drawing")
        }
        else {
            print("Not Drawing")
        }
    }
}

这三个类可以很好地渲染窗口,并且输出

Not Drawing

表明该值始终为空,但它每帧都在做某事。

我尝试过的事情

  • 创建我自己的渲染通道描述符:这导致了一个 sig 错误。
  • 查看过视图,肯定是被识别为MTKView

我知道如果我使用基于文件中情节提要的项目,这将有效,但我希望了解如何在没有它的情况下进行操作。

任何帮助将不胜感激

【问题讨论】:

  • 你见过this吗?
  • @trojanfoe 我有,并且已经超载了加载视图和 viewDidLoad,除非我误解了这篇文章?
  • 我想你是。关键是在不涉及 NIB 时不会调用 viewDidLoad。我不知道 Swift 但你甚至调用基类 (NSViewController) viewDidLoad 吗?我会坚持故事板并继续你的生活。
  • @trojanfoe loadView()viewDidLoad()let view = controller!.view 调用。
  • @Willeke 基类方法是否也被调用?

标签: swift cocoa metal


【解决方案1】:

来自MTKView.currentRenderPassDescriptor的文档:

如果未设置视图的 device 属性,或者如果 currentDrawablenil

您需要为MTKView 提供一个金属设备才能使用。 IB 可能默认给它MTLCreateSystemDefaultDevice(),但是当您以编程方式创建视图时,您需要手动完成:

override func loadView() {
    view = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
}

【讨论】:

  • 我已经在渲染器类中设置了默认设备?然后我也在渲染器类中设置了视图设备
  • 啊,真的。您是否检查过view.devicedraw(in view: MTKView) 中是否可用?
  • 是的,我很确定它在那里。当我签入draw(in view: MTKView) 时它不是零
【解决方案2】:

视图的宽度和高度为0。在applicationDidFinishLaunching中将视图添加到窗口之前设置框架大小。

controller = ViewController()
let content = newWindow!.contentView! as NSView
let view = controller!.view
view.frame = content.bounds
content.addSubview(view)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    相关资源
    最近更新 更多