为什么用粗糙的边缘而不是平滑的边缘渲染三角形?金属、Swift、Xcode [英] Why is the triangle being rendered with rough edges and not smooth edges? Metal, Swift, Xcode
问题描述
我正在使用此代码来呈现Hello Triangle"三角形.但是,在我的 iPhone 上,三角形的边缘非常粗糙,而不是像示例中那样平滑的边缘.
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
}
}
我曾尝试用不同的方法多次渲染三角形(有时使用界面构建器中的 MetalKit 视图,有时手动创建视图)...但每次,三角形都带有粗糙的边缘.
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.
推荐答案
这里的主要问题是图层的可绘制尺寸远小于屏幕的分辨率.您可以通过以下步骤使它们匹配:
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:
当您的 Metal 视图移动到新的超级视图时,更新其 contentsScale
属性以匹配托管显示的属性:
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)
}
当您检测到图层与计算出的首选大小不匹配时,更新它的 drawableSize
:
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
}
...
}
顺便说一下,现在真的没有充分的理由不使用 MTKView
来达到这个目的.它为您抽象了所有这些细节,并且更易于使用.
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.
这篇关于为什么用粗糙的边缘而不是平滑的边缘渲染三角形?金属、Swift、Xcode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!