Metal MTLBuffer大批量顶点处理

在我们之前的案例Metal 使用渲染管道渲染基本图元一节中,我们使用setVertexBytes:length:atIndex:函数来将我们的顶点数据传递到顶点换冲过去中,但是这个函数有一个限制,那就是它只能传递4KB以下的数据,超过4KB的数据需要使用MTLBuffer对象配合setVertexBuffer:offset:atIndex:来进行传递。下面是苹果官方的释义。

Using this method is equivalent to creating a new MTLBuffer object from the specified data and then binding it to the vertex shader, with the setVertexBuffer:offset:atIndex: method. However, this method avoids the overhead of creating a buffer to store your data; instead, Metal manages the data.

Use this method for single-use data smaller than 4 KB. Create a MTLBuffer object if your data exceeds 4 KB in length or persists for multiple uses.

MTLBuffer

一个我们自定义的数据存储资源对象。

MTLBuffer创建

MTLBuffer对象可以使用MTLDevice来进行创建,我们可以使用MTLDevice以下几个方法来创建MTLBuffer。

  • newBufferWithLength:options:使用新的存储空间创建一个MTLBuffer对象。
  • newBufferWithBytes:length:options:通过将现有内存中的数据复制到新的内存空间中,来创建一个MTLBuffer对象。
  • newBufferWithBytesNoCopy:length:options:deallocator:创建一个MTLBuffer对象,该对象重用现有的内存分配,并且不分配任何新的内存。

Metal框架并不知道MTLBuffer的内容,只知道它的大小,自定义的数据格式,一定要确保应用程序和着色器知道如何读写,例如,您可以在着色器中创建一个结构,定义要存储在缓冲区中的数据以及其内存布局。

_vertexBuffer = [_device newBufferWithBytes:vertexData.bytes length:vertexData.length options:(MTLResourceStorageModeShared)];

其中vertexData是我们的顶点数据,这是我们自定义的顶点。

顶点的传递

接下来我们要将顶点传递到我们的顶点着色器中。

[renderEncoder setVertexBuffer:_vertexBuffer
                        offset:0
                       atIndex:CCVertexInputIndexVertices];

顶点的使用

在我们的顶点函数中我们这样使用传递过来的顶点数据。

vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
             constant CCVertex *vertices [[buffer(CCVertexInputIndexVertices)]],
             constant vector_uint2 *viewportSizePointer [[buffer(CCVertexInputIndexViewportSize)]])
{
    /*
     处理顶点数据:
     1) 执行坐标系转换,将生成的顶点剪辑空间写入到返回值中.
     2) 将顶点颜色值传递给返回值
     */
    //定义out
    RasterizerData out;
    //初始化输出剪辑空间位置
    out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0);
    // 索引到我们的数组位置以获得当前顶点
    // 我们的位置是在像素维度中指定的.
    float2 pixelSpacePosition = vertices[vertexID].position.xy;
    //将vierportSizePointer 从verctor_uint2 转换为vector_float2 类型
    vector_float2 viewportSize = vector_float2(*viewportSizePointer);
    //每个顶点着色器的输出位置在剪辑空间中(也称为归一化设备坐标空间,NDC),剪辑空间中的(-1,-1)表示视口的左下角,而(1,1)表示视口的右上角.
    //计算和写入 XY值到我们的剪辑空间的位置.为了从像素空间中的位置转换到剪辑空间的位置,我们将像素坐标除以视口的大小的一半.
    out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);
    //把我们输入的颜色直接赋值给输出颜色. 这个值将于构成三角形的顶点的其他颜色值插值,从而为我们片段着色器中的每个片段生成颜色值.
    out.color = vertices[vertexID].color;
    //完成! 将结构体传递到管道中下一个阶段:
    return out;
}

你可能感兴趣的:(Metal MTLBuffer大批量顶点处理)