ios - Metal 仅绘制 View 的一部分并查询图层

标签 ios swift metal

我正在遵循基本 Metal 教程的设置,并尝试渲染统一颜色的空白屏幕。

出于某种原因,我遇到了这个问题:Metal 仅绘制到屏幕的一部分。

我设置了一个单一 View 应用程序,并将 MainStoryboard 的 View 附加到我正在创建的类中。我将其背景颜色设置为绿色。

这是类(class)

class MBEMetalView: UIView {

    var device:MTLDevice?
    var MTLLayer:CAMetalLayer?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        device = MTLCreateSystemDefaultDevice()

        //The book said to cast the layer to a CAMetalLayer 
        //but that causes a crash in the redraw method because
        //failed assertion `No rendertargets set in RenderPassDescriptor.'
        //So we do this.. which might be wasteful?
        MTLLayer = CAMetalLayer()
        MTLLayer?.device = device
        MTLLayer?.pixelFormat = MTLPixelFormat.bgra8Unorm
        MTLLayer?.framebufferOnly = true
        MTLLayer?.frame = frame
        layer.addSublayer(MTLLayer!)
    }

    override func didMoveToWindow() {
        redraw()
    }

    func redraw() {
        var drawable = MTLLayer?.nextDrawable()
        var texture = drawable?.texture

        var passDescriptor = MTLRenderPassDescriptor()
        passDescriptor.colorAttachments[0].texture = texture
        passDescriptor.colorAttachments[0].loadAction = MTLLoadAction.clear
        passDescriptor.colorAttachments[0].storeAction = MTLStoreAction.store
        passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 1, 0, 1)


        var commandQueue = device?.makeCommandQueue()
        var commandBuffer = commandQueue?.makeCommandBuffer()
        var commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: passDescriptor)
        commandEncoder?.endEncoding()

        if let drawOn = drawable {
            commandBuffer?.present(drawOn)
            commandBuffer?.commit()
        }
    }

}

该类应该将整个屏幕渲染为绿色,但事实并非如此,它只填充了一部分,如 iPhone 6s plus 的图片所示(红色是 View 的背景,而不是 Metal 正在绘制的内容)。 enter image description here

这个结果让我想起了几个问题:

  1. 为什么 Metal 只渲染到屏幕的一部分
  2. 我接下来的教程是在 Objective-C 中完成的,他们能够将继承的 UIView 层转换为 CAMetal 层 而不是创建一个新层(这允许他们删除 .addSublayer 行)。然而,当我尝试这个时,我遇到了崩溃 在评论中显示?这是为什么?
  3. 传入的帧将如何受到 iPhone X 等具有安全区域的设备的影响?我需要画一些额外的东西吗 安全区之外?哪里可以查到保险箱的尺寸 以编程方式从我的 View 框架中获取区域(如果新设备 已发布)

最佳答案

您可以在 init(coder) 中设置 CAMetalLayer 的框架,并且永远不会更改它。但在 init(coder) 中,最终帧大小尚不清楚(它只是使用您此时在 Interface Builder 中设置的任何大小,但尚未使用设备大小)。在didMoveToWindow()中,还将Metal层的框架设置为其最终大小。 (或者也许在 layoutSubviews() 中。)

关于ios - Metal 仅绘制 View 的一部分并查询图层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47902056/

相关文章:

ios - 无法从 CVMetalTextureGetTexture 函数获取有效的 MTLTexture

ios - 有什么方法可以通过 NFC 传输字符串吗?

ios - NSURLSessionDataTask 和线程

ios - 从字典创建 Swift 对象

ios - Firebase/Crashlytics 在提交崩溃报告时遇到问题

swift - 具有多个命令编码器的无内存纹理

ios - 为什么在 SceneKit 着色器修改器中使用 glsl 或定义函数只会产生错误?

ios - Firebase 实时数据库连接刷新

ios - 我如何 "go to"来自 XCode Storyboard的引用 socket 代码?

ios - 节点未在 Swift 2 和 SpriteKit 中加载纹理