Search code examples
metalmtkview

How to render multiple triangleStrips using Metal?


Now I have already known how to render multiple triangles in Metal:

let vertexBuffer = device.makeBuffer(vertices_triangles)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: vertices_triangles.count)
renderEncoder.endEncoding()
commandBuffer.present(view.currentDrawable!)
commandBuffer.commit()

Here, vertices_triangles is an Array of element Vertex. The adjacent three vertices shows a triangle to render.

However, I don't really know how to render multiple triangleStrips in Metal.

let vertexBuffer = device.makeBuffer(vertices_triangleStrips)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: vertices_triangleStrips.count)

If I put adjacent vertices in vertices_triangleStrips and set renderEncoder.drawPrimitives.type to .triangleStrip, I will get one triangleStrip. But how can I render multiple triangleStrips? I tried using for loop to make multiple vertexBuffers and use renderEncoder.drawPrimitives to draw each triangleStrip. It seems that it's not a good idea to do this for performance reasons.


Solution

  • Referring to documentation of drawIndexedPrimitives(type:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:baseVertex:baseInstance:) in Metal:

    Primitive restart functionality is enabled with the largest unsigned integer index value, relative to indexType (0xFFFF for MTLIndexTypeUInt16 or 0xFFFFFFFF for MTLIndexTypeUInt32). This feature finishes drawing the current primitive at the specified index and starts drawing a new one with the next index.

    You could render multiple triangleStrips by defining an indexBuffer seperated by 0xFFFF or 0xFFFFFFFF.

    eg. rendering triangleStrips at vertex [0,1,2,3] [4,5,6,7] [8,9,10] [11,12,13,14,15,16]

    let indexBytes: [UInt32] = [0, 1, 2, 3, 0xFFFFFFFF, 4, 5, 6, 7, 0xFFFFFFFF, 8, 9, 10, 0xFFFFFFFF, 11, 12, 13, 14, 15, 16, 0xFFFFFFFF]
    
    let vertexBuffer = device.makeBuffer(bytes: vertices_triangleStrips,
                                         length: vertices_triangleStrips.count * MemoryLayout<MetalPosition2>.stride,
                                         options: [])!
    let indexBuffer = device.makeBuffer(bytes: indexBytes,
                                        length: indexBytes.count * MemoryLayout<UInt32>.stride,
                                        options: [])!
    
    renderEncoder.setVertexBuffer(vertexBuffer,
                                  offset: 0,
                                  index: 0)
    renderEncoder.drawIndexedPrimitives(type: .triangleStrip,
                                        indexCount: indexBytes.count,
                                        indexType: .uint32,
                                        indexBuffer: indexBuffer,
                                        indexBufferOffset: 0) // only one instance