1.流程图
2.metal纹理加载
- 纹理加载就是把png、jpg等文件使用CGBitmapContextCreate重绘一次,使其转成NSData的过程。
- .metal文件中顶点函数需要传入顶点坐标和纹理坐标,片元函数需要传入纹理。
2.1 纹理加载
- (Byte *)loadImage:(UIImage *)image {
// 1.获取图片的CGImageRef
CGImageRef spriteImage = image.CGImage;
// 2.读取图片的大小
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
//3.计算图片大小.rgba共4个byte
Byte * spriteData = (Byte *) calloc(width * height * 4, sizeof(Byte));
//4.创建画布
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
//5.在CGContextRef上绘图
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
//6.图片翻转过来
CGRect rect = CGRectMake(0, 0, width, height);
CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0, -1.0);
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage);
//7.释放spriteContext
CGContextRelease(spriteContext);
return spriteData;
}
2.2 metal文件
顶点函数:
// 顶点着色器输出和片段着色器输入
//结构体
typedef struct
{
float4 clipSpacePosition [[position]];
float2 textureCoordinate;
} RasterizerData;
//顶点着色函数
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
constant CCVertex *vertexArray [[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 = vertexArray[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.clipSpacePosition.z = 0.0f;
out.clipSpacePosition.w = 1.0f;
//把我们输入的颜色直接赋值给输出颜色. 这个值将于构成三角形的顶点的其他颜色值插值,从而为我们片段着色器中的每个片段生成颜色值.
out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
//完成! 将结构体传递到管道中下一个阶段:
return out;
}
片元函数:
fragment float4 fragmentShader(RasterizerData in [[stage_in]],
texture2d<half> colorTexture [[texture(CCTextureIndexBaseColor)]])
{
constexpr sampler textureSampler(mag_filter::linear,
min_filter::linear);
const half4 colorSampler = colorTexture.sample(textureSampler,in.textureCoordinate);
return float4(colorSampler);
//返回输入的片元颜色
//return in.color;
}