【问题标题】:Draw a textured rectangle in Metal - Swift在 Metal 中绘制带纹理的矩形 - Swift
【发布时间】:2020-06-23 13:12:09
【问题描述】:

我正在尝试使用 Swift 在 Metal 中绘制一个带纹理的 2D 矩形。所有在线示例,包括以下示例,都使用 Objective-C 或更早版本的 Swift,并且很难移植到 Swift 5:

How to draw a textured rectangle with Metal https://developer.apple.com/documentation/metal/creating_and_sampling_textures

我的目标是在视频的一角画一个简单的水印。我有一个Renderer 类,用于捕获帧,将它们绘制到我的金属视图(这很好),然后想在顶部绘制一个徽标。我不能对相机帧使用相同的方法,因为它们是 YUV 格式,所以使用特殊的着色器。我的水印只是一个普通的旧 PNG 文件。

我能够绘制无纹理的矩形,但尝试应用纹理失败 - 没有错误,什么都没有。屏幕上什么也没有出现。当 Metal 没有返回错误来调试这些类型的问题时,我应该检查哪些关键事项?

这里有一些代码:

func drawRect(renderEncoder: MTLRenderCommandEncoder, x:Double, y:Double, w:Double, h:Double, pipelineState:MTLRenderPipelineState, viewSize: CGSize)
    {
        //new viewport to size of image we want to display
        var viewPort = MTLViewport(originX: x, originY: y, width: w, height: h, znear: 0.0, zfar: 1.0)
        var viewPortSize = simd_float2(x: Float(w), y: Float(h))
        
        var logoQuadVertices:[AAPLVertex] = [
            //Triangle1: top left, top right, bottom left
            AAPLVertex(position: simd_float2(x: 0, y: 0), textureCoordinate: simd_float2(x: 0.0, y: 0.0)),
            AAPLVertex(position: simd_float2(x: 100, y: 0), textureCoordinate: simd_float2(x: 1.0, y: 0.0)),
            AAPLVertex(position: simd_float2(x: 0, y: 100), textureCoordinate: simd_float2(x: 0.0, y: 1.0)),
            //Triangle2: bottom left, bottom right, top right
            AAPLVertex(position: simd_float2(x: 0, y: 100), textureCoordinate: simd_float2(x: 0.0, y: 1.0)),
            AAPLVertex(position: simd_float2(x: 100, y: 100), textureCoordinate: simd_float2(x: 1.0, y: 1.0)),
            AAPLVertex(position: simd_float2(x: 100, y: 0), textureCoordinate: simd_float2(x: 1.0, y: 0.0))
        ]

        //Set the new viewport
        renderEncoder.setViewport(MTLViewport(originX: x, originY: y, width: w, height: h, znear: 0.0, zfar: 1.0))

        //Debug string
        renderEncoder.pushDebugGroup("DrawRect")

        //Set pipeline state
        renderEncoder.setRenderPipelineState(pipelineState)
    
        //Send vertex data of rectangle to shaders
        renderEncoder.setVertexBytes(logoQuadVertices, length: logoQuadVertices.count*MemoryLayout<AAPLVertex>.stride, index: Int(AAPLVertexInputIndexVertices.rawValue))

        //Send vertex bytes of viewport to shaders
        renderEncoder.setVertexBytes(&viewPortSize, length: MemoryLayout<simd_float2>.stride, index: Int(AAPLVertexInputIndexViewportSize.rawValue))

        // Set the texture
        renderEncoder.setFragmentTexture(texture, index: Int(kTextureIndexPNG.rawValue))

        //Sampler state
        if let samplerState = logoSamplerState {
            renderEncoder.setFragmentSamplerState(samplerState, index: 0)
        }
    
        //Draw the textured rectangle
        renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 6)
        
        //Debug
        renderEncoder.popDebugGroup()
    }

...
// Pipeline configuration
let logoPipelineStateDescriptor = MTLRenderPipelineDescriptor()
logoPipelineStateDescriptor.label = "MyLogoPipeline"
logoPipelineStateDescriptor.sampleCount = renderDestination.sampleCount
logoPipelineStateDescriptor.vertexFunction = 
defaultLibrary.makeFunction(name: "vertexShader")!
logoPipelineStateDescriptor.fragmentFunction = 
defaultLibrary.makeFunction(name: "samplingShader")
logoPipelineStateDescriptor.vertexDescriptor = logoPlaneVertexDescriptor
logoPipelineStateDescriptor.colorAttachments[0].pixelFormat = 
renderDestination.colorPixelFormat
logoPipelineStateDescriptor.depthAttachmentPixelFormat = 
renderDestination.depthStencilPixelFormat
logoPipelineStateDescriptor.stencilAttachmentPixelFormat = 
renderDestination.depthStencilPixelFormat
do {
    try logoPipelineState = device.makeRenderPipelineState(descriptor: logoPipelineStateDescriptor)
} catch let error {
    print("Failed to created logo pipeline state, error \(error)")
}
...

着色器:

typedef struct
{
    float4 position [[position]];
    float2 textureCoordinate;
} RasterizerData;

// Vertex Function
vertex RasterizerData
vertexShader(uint vertexID [[ vertex_id ]],
         constant AAPLVertex *vertexArray [[ buffer(AAPLVertexInputIndexVertices) ]],
         constant vector_uint2 *viewportSizePointer  [[ buffer(AAPLVertexInputIndexViewportSize) ]])

{
    RasterizerData out;

    float2 pixelSpacePosition = vertexArray[vertexID].position.xy;

    float2 viewportSize = float2(*viewportSizePointer);

    out.position = vector_float4(0.0, 0.0, 0.0, 1.0);
    out.position.xy = pixelSpacePosition / (viewportSize / 2.0);

    out.textureCoordinate = vertexArray[vertexID].textureCoordinate;

    return out;
}

// Fragment function
fragment float4
samplingShader(RasterizerData in [[stage_in]],
           texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])
{
    constexpr sampler textureSampler (mag_filter::linear,
                                  min_filter::linear);

    // Sample the texture to obtain a color
    const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);

    // return the color of the texture
    return float4(colorSample);
}

【问题讨论】:

  • 您对 Xcode 中的图形调试器有兴趣吗?这是一个非常好的工具,可以查看正在发生的事情......
  • @trojanfoe 我没有,谢谢!今晚会试试这个。
  • 还要注意顶点的缠绕顺序(背面被剔除)并使用索引缓冲区,因此您只需要 4 个顶点。
  • 不需要。很高兴您解决了您的问题。
  • @Fattie 对不起,不知道。

标签: ios swift arkit swift5 metal


【解决方案1】:

根据@trojanfoe 的建议,调试器有一些用于调试 GPU 功能的有用工具。要访问它,在运行您的应用程序时,在 XCode 中转到 Debug > Capture GPU Frame。然后,您可以探索层次结构,甚至查看顶点是如何加载的等等。

在我的例子中,顶点是错误的。我将它们提供为像素坐标,而不是 -1.0、1.0 纹理坐标系。当我在调试器中的 verticies 数据看起来不像预期的那样时,这一点很明显。您的问题可能是其他问题,但这是一个很好的起点。

针对我的问题修改了代码:

var logoQuadVertices:[AAPLVertex] = [
        //Triangle1: top left, top right, bottom left
        AAPLVertex(position: simd_float2(x: -1.0, y: -1.0), textureCoordinate: simd_float2(x: 0.0, y: 0.0)),
        AAPLVertex(position: simd_float2(x: 1.0, y: -1.0), textureCoordinate: simd_float2(x: 1.0, y: 0.0)),
        AAPLVertex(position: simd_float2(x: -1.0, y: 1.0), textureCoordinate: simd_float2(x: 0.0, y: 1.0)),
        //Triangle2: bottom left, bottom right, top right
        AAPLVertex(position: simd_float2(x: -1.0, y: 1.0), textureCoordinate: simd_float2(x: 0.0, y: 1.0)),
        AAPLVertex(position: simd_float2(x: 1.0, y: 1.0), textureCoordinate: simd_float2(x: 1.0, y: 1.0)),
        AAPLVertex(position: simd_float2(x: 1.0, y: -1.0), textureCoordinate: simd_float2(x: 1.0, y: 0.0))
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-19
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2012-11-25
    相关资源
    最近更新 更多