在我们之前的案例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;
}