在看了《如何優(yōu)雅地實現(xiàn)一個分屏濾鏡》后,就想用Metal學(xué)習(xí)著也實現(xiàn)一次,博主是使用GLSL去實現(xiàn)。Metal著色器的實現(xiàn)其實跟GLSL里面的實現(xiàn)一樣,沒什么差別。
一、靜態(tài)分屏
靜態(tài)分屏:每一個屏幕的圖像都一樣
先上實現(xiàn)效果圖:IMG_0069.PNG
主要是片元著色器里面的代碼:
fragment float4 fragmentShader(RasterizerData inVertex [[stage_in]], //stage_in表示這個數(shù)據(jù)來自光柵化
texture2d<float> textureY [[texture(0)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> textureUV [[texture(1)]], // texture 表明是紋理數(shù)據(jù)
constant XTConvertMatrix *convertMarix [[buffer(0)]] // buffer表示名緩存數(shù)據(jù)
) {
float row = 2; /// 多少行
float column = 3; /// 多少列
float rowCount = max(row, 1.0); // 確保至少有一行
float columnCount = max(column, 1.0); // 確保至少有一列
float ratio = rowCount / columnCount;
float2 originSize = float2(1.0, 1.0);
float2 newSize = originSize;
if (ratio > 1.0) {
newSize.y = 1.0 / ratio;
} else {
newSize.x = ratio;
}
float2 offset = (originSize - newSize) / 2.0; /// 畫面的偏移距離
float2 position = offset + fmod(inVertex.texCoords * min(rowCount, columnCount), newSize); // (5)
/// C 庫函數(shù) double fmod(double x, double y) 返回 x 除以 y 的余數(shù)。
//取樣器
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear
);
/// 獲取yuv數(shù)據(jù)
float3 yuv = float3(textureY.sample(textureSampler, position).r,
(textureUV.sample(textureSampler, position).rg));
/// yuv轉(zhuǎn)rgb
float3 rgb = convertMarix[0].matrix * (yuv + convertMarix[0].offset);
/// 確保超出不被顯示 用黑色
if (position.x > 1.0) {
return float4(0,0,0,1);
}
if (position.y > 1.0) {
return float4(0,0,0,1);
}
return float4(rgb, 1.0);
}
二、動態(tài)分屏
動態(tài)分屏指的是,每個屏的圖像都不一樣,每間隔一段時間,會主動捕獲一個新的圖像。
先上效果圖:
IMG_0068.PNG
上代碼:
fragment float4 fragmentShader2(RasterizerData inVertex [[stage_in]], //stage_in表示這個數(shù)據(jù)來自光柵化
texture2d<float> texture0Y [[texture(0)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture0UV [[texture(1)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture1Y [[texture(2)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture1UV [[texture(3)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture2Y [[texture(4)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture2UV [[texture(5)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture3Y [[texture(6)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture3UV [[texture(7)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture4Y [[texture(8)]], // texture 表明是紋理數(shù)據(jù)
texture2d<float> texture4UV [[texture(9)]], // texture 表明是紋理數(shù)據(jù)
constant XTConvertMatrix *convertMarix [[buffer(0)]], // buffer表示名緩存數(shù)據(jù)
constant XTUniform *uniform [[buffer(1)]]
) {
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear
);
float2 newSize = float2(1.0, 1.0);;
float2 position = modf(inVertex.texCoords * 2, newSize);
texture2d<float> textureY;
texture2d<float> textureUV;
if (inVertex.texCoords.x <= 0.5 && inVertex.texCoords.y <= 0.5) { //左上
if (uniform[0].textureCount > 0) {
textureY = texture1Y;
textureUV = texture1UV;
}else {
textureY = texture0Y;
textureUV = texture0UV;
}
}else if (inVertex.texCoords.x > 0.5 && inVertex.texCoords.y <= 0.5) { //右上
if (uniform[0].textureCount > 1) {
textureY = texture2Y;
textureUV = texture2UV;
}else {
textureY = texture0Y;
textureUV = texture0UV;
}
}else if (inVertex.texCoords.x <= 0.5 && inVertex.texCoords.y > 0.5) { //左下
if (uniform[0].textureCount > 2) {
textureY = texture3Y;
textureUV = texture3UV;
}else {
textureY = texture0Y;
textureUV = texture0UV;
}
}else { // 右下
if (uniform[0].textureCount > 3) {
textureY = texture4Y;
textureUV = texture4UV;
}else {
textureY = texture0Y;
textureUV = texture0UV;
}
}
float3 yuv = float3(textureY.sample(textureSampler, position).r,
(textureUV.sample(textureSampler, position).rg));
float3 rgb = convertMarix[0].matrix * (yuv + convertMarix[0].offset);
if (position.x > 1.0) {
return float4(0,0,0,1);
}
if (position.y > 1.0) {
return float4(0,0,0,1);
}
return float4(rgb, 1.0);
}
在實現(xiàn)動態(tài)分屏的時候遇到一個問題:
我全局記錄分屏的數(shù)據(jù),過了特定時間后,前面的紋理數(shù)據(jù)會變化。比方就是說當過了4s,我會記錄textureBuffer1,并且全局記錄,然后繼續(xù)往下跑,textureBuffer1的數(shù)據(jù)有發(fā)生變化。然后我打印pixelBuffer地址會重復(fù),發(fā)現(xiàn)pixelBuffer重用了,然后我就記錄下pixelBuffer,完美解決
具體代碼放在Metal-11(分屏)里面。
熱愛生活,記錄生活!