Why is the triangle being rendered with rough edges and not smooth edges? Metal, Swift, Xcode

爱⌒轻易说出口 提交于 2021-01-29 12:19:53

问题


I am using this code to render the "Hello Triangle" triangle. On my iPhone, though, the triangle has very rough edges, not smooth edges, like in the example.

import UIKit
import Metal
import MetalKit
import simd

class MBEMetalView: UIView {

     // // // // // MAIN // // // // //
     var metalDevice: MTLDevice! = nil
     var metalLayer: CAMetalLayer! = nil
     var commandQueue: MTLCommandQueue! = nil
     var vertexBuffer: MTLBuffer! = nil
     var pipelineState: MTLRenderPipelineState! = nil
     var displayLink: CADisplayLink! = nil

     override class var layerClass : AnyClass {
          return CAMetalLayer.self
     }
//     override func didMoveToWindow() {
//          self.redraw()
//     }
     override func didMoveToSuperview() {
          super.didMoveToSuperview()
          if self.superview != nil {
               self.displayLink = CADisplayLink(target: self, selector: #selector(displayLinkFired))
               self.displayLink.add(to: RunLoop.main, forMode: .common)
          } else {
               self.displayLink.invalidate()
          }
     }
     @objc func displayLinkFired() {
          self.redraw()
     }





     // // // // // INIT // // // // //
     required init?(coder aDecoder: NSCoder) {
          super.init(coder: aDecoder)
          self.prepareDeviceLayerAndQueue()
          self.makeBuffers()
          self.makePipeline()
     }

     func prepareDeviceLayerAndQueue() {
          metalLayer = (self.layer as! CAMetalLayer)
          metalDevice = MTLCreateSystemDefaultDevice()
          metalLayer.device = metalDevice
          metalLayer.pixelFormat = .bgra8Unorm
          commandQueue = metalDevice.makeCommandQueue()
     }

     func makeBuffers() {
          var vertices: [MBEVertex] = [
               MBEVertex(position: vector_float4(0, 0.5, 0, 1) , color: vector_float4(1, 0, 0, 1)),
               MBEVertex(position: vector_float4(-0.5, -0.5, 0, 1)  , color: vector_float4(0, 1, 0, 1)),
               MBEVertex(position: vector_float4(0.5, -0.5, 0, 1)  , color: vector_float4(0, 0, 1, 1))
          ]
          self.vertexBuffer = metalDevice.makeBuffer(bytes: &vertices, length: 56, options: .storageModeShared)
     }

     func makePipeline() {
          guard let library = metalDevice.makeDefaultLibrary() else { print("COULD NOT CREATE LIBRARY") ; return }
          guard let vertexFunction = library.makeFunction(name: "vertex_main") else { print("COULD NOT CREATE A VERTEX FUNCTION") ; return }
          guard let fragmentFunction = library.makeFunction(name: "fragment_main") else { print("COULD NOT CREATE LIBRARY") ; return }

          let pipelineDescriptor = MTLRenderPipelineDescriptor()
          pipelineDescriptor.vertexFunction = vertexFunction
          pipelineDescriptor.fragmentFunction = fragmentFunction
          pipelineDescriptor.colorAttachments[0].pixelFormat = metalLayer.pixelFormat

          pipelineState = try? metalDevice.makeRenderPipelineState(descriptor: pipelineDescriptor)
          if pipelineState == nil { print("COULD NOT CREATE PIPELINE STATE") ; return }

     }





     // // // // // FUNCTIONS // // // // //
     func redraw() {
          guard let drawable = metalLayer.nextDrawable() else { print("COULD NOT CREATE A DRAWABLE") ; return }
          let texture = drawable.texture
          let renderPassDescriptor = MTLRenderPassDescriptor()
          renderPassDescriptor.colorAttachments[0].texture = texture
          renderPassDescriptor.colorAttachments[0].loadAction = .clear
          renderPassDescriptor.colorAttachments[0].storeAction = .store
          renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1)

          guard let commandBuffer = commandQueue.makeCommandBuffer() else { print("COULD NOT CREATE A COMMAND BUFFER") ; return }
          guard let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { print("COULD NOT CREATE AN ENCODER") ; return }

          commandEncoder.setRenderPipelineState(pipelineState)
          commandEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
          commandEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3)

          commandEncoder.endEncoding()
          commandBuffer.present(drawable)
          commandBuffer.commit()
     }





     // // // // // TYPES // // // // //
     struct MBEVertex {
          var position: vector_float4
          var color: vector_float4
     }

}

I have tried to render the triangle a few different times with different methods (sometimes use a MetalKit view from interface builder, sometimes create the view manually)... each time, though, the triangle comes out with rough edges.


回答1:


The main issue here is that the drawable size of your layer is much smaller than the resolution of your screen. You can get them to match by taking the following steps:

When your Metal view moves to a new superview, update its contentsScale property to match that of the hosting display:

layer.contentsScale = self.window?.screen.scale ?? 1.0

Add a property to your view subclass that computes the ideal drawable size based on the bounds of the view and its scale:

var preferredDrawableSize: CGSize {
    return CGSize(width: bounds.size.width * layer.contentsScale,
                  height: bounds.size.height * layer.contentsScale)
}

Update the drawableSize of your layer when you detect that it doesn't match the computed preferred size:

 func redraw() {
      if metalLayer.drawableSize != preferredDrawableSize {
          metalLayer.drawableSize = preferredDrawableSize
      }
    ...
 }

By the way, these days there's really no good reason not to use MTKView for this purpose. It abstracts all of these details for you and is much nicer to work with.



来源:https://stackoverflow.com/questions/57613416/why-is-the-triangle-being-rendered-with-rough-edges-and-not-smooth-edges-metal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!