【问题标题】:Flipped picture after render in Metal在 Metal 中渲染后翻转图片
【发布时间】:2020-02-11 08:18:40
【问题描述】:

我正在尝试在 MTKView 中渲染动画并遇到一个奇怪的问题。在模拟器中,我看到翻转的图片,但在设备上一切都很好。我也使用相同的方法渲染视频,并且图片在设备和模拟器上具有相同的方向。

这是重现我的问题的最简化示例:

class TestVC: UIViewController {
    var output: MTKView!
    let device: MTLDevice
    let context: CIContext
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let queue: MTLCommandQueue?
    let image: CIImage

    init() {
        let defaultDevice = MTLCreateSystemDefaultDevice()!
        self.device = defaultDevice
        self.context = CIContext(mtlDevice: defaultDevice)
        self.queue = defaultDevice.makeCommandQueue()
        self.image = CIImage(image: UIImage(named: "lena.png")!)!
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        makeOutputView()
    }

    func makeOutputView() {
        let side = min(view.frame.size.width, view.frame.size.height) * 0.9
        let viewFrame = CGRect(x: 0, y: 0, width: side, height: side)
        output = MTKView(frame: viewFrame, device: device)
        view.addSubview(output)
        output.center = view.center
        output.framebufferOnly = false
        output.delegate = self
    }
}

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

    func draw(in view: MTKView) {
        let buffer = queue?.makeCommandBuffer()
        guard let drawable = view.currentDrawable else { return }
        let dpi = UIScreen.main.nativeScale
        let width = view.bounds.width * dpi
        let height = view.bounds.height * dpi
        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        let extent = image.extent
        let xScale = extent.width > 0 ? width  / extent.width  : 1
        let yScale = extent.height > 0 ? height / extent.height : 1
        let scale = max(xScale, yScale)
        let tx = (width - extent.width * scale) / 2
        let ty = (height - extent.height * scale) / 2
        let transform = CGAffineTransform(a: scale, b: 0, c: 0, d: scale, tx: tx, ty: ty)
        let filter = CIFilter(name: "CIAffineTransform",
                              parameters: ["inputImage": image, "inputTransform": transform])!
        let scaledImage = filter.outputImage!
        context.render(scaledImage,
                       to: drawable.texture,
                       commandBuffer: buffer,
                       bounds: rect,
                       colorSpace: colorSpace)
        buffer?.present(drawable)
        buffer?.commit()
    }
}

这就是我所看到的:

【问题讨论】:

  • 这感觉像是一个模拟器错误。我的理解是,当前的 Xcode 11.4 测试版支持 Metal 的 GPU 帧捕获,因此您可以使用它来深入了解问题所在并找到解决方法。
  • @warrenm 这是否意味着我必须翻转照片才能渲染到视频并保持原始方向才能渲染到 MTKView?它对我有用,但我想弄清楚它为什么会发生
  • 您是否正在通过 CoreImage 渲染您的视频帧?或者你有不同的渲染路径?
  • 是的。我将使用 CoreImage 对图像进行更改并在之后进行渲染。

标签: ios swift metal


【解决方案1】:

此问题与使用不同坐标系的 Mac 上的 GPU 的模拟器有关。一个快速的解决方法是在模拟器中运行图像时翻转图像。

var scaledImage = filter.outputImage!
    
#if targetEnvironment(simulator)
    scaledImage = scaledImage.transformed(by: CGAffineTransform(scaleX: 1, y: -1))
        .transformed(by: CGAffineTransform(translationX: 0, y: scaledImage.extent.height))
#endif

context.render(scaledImage,
          to: drawable.texture,
          commandBuffer: buffer,
          bounds: rect,
          colorSpace: colorSpace)
 buffer?.present(drawable)
 buffer?.commit()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    • 2012-02-02
    • 2020-12-21
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多