Metal学习(四) - 分屏播放

在看了《如何优雅地实现一个分屏滤镜》后,就想用Metal学习着也实现一次,博主是使用GLSL去实现。Metal着色器的实现其实跟GLSL里面的实现一样,没什么差别。

一、静态分屏

静态分屏:每一个屏幕的图像都一样

先上实现效果图:
IMG_0069.PNG

主要是片元着色器里面的代码:

fragment float4 fragmentShader(RasterizerData inVertex [[stage_in]], //stage_in表示这个数据来自光栅化
                               texture2d textureY [[texture(0)]], // texture 表明是纹理数据
                               texture2d textureUV [[texture(1)]], // texture 表明是纹理数据
                               constant XTConvertMatrix *convertMarix [[buffer(0)]] // buffer表示名缓存数据
                               ) {
    
    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 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数。
    
    //取样器
    constexpr sampler textureSampler (mag_filter::linear,
                                      min_filter::linear
                                      );
    /// 获取yuv数据
    float3 yuv = float3(textureY.sample(textureSampler, position).r,
                        (textureUV.sample(textureSampler, position).rg));

    /// yuv转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);
}

二、动态分屏

动态分屏指的是,每个屏的图像都不一样,每间隔一段时间,会主动捕获一个新的图像。

先上效果图:


IMG_0068.PNG

上代码:

fragment float4 fragmentShader2(RasterizerData inVertex [[stage_in]], //stage_in表示这个数据来自光栅化
                                texture2d texture0Y [[texture(0)]], // texture 表明是纹理数据
                                texture2d texture0UV [[texture(1)]], // texture 表明是纹理数据
                                texture2d texture1Y [[texture(2)]], // texture 表明是纹理数据
                                texture2d texture1UV [[texture(3)]], // texture 表明是纹理数据
                                texture2d texture2Y [[texture(4)]], // texture 表明是纹理数据
                                texture2d texture2UV [[texture(5)]], // texture 表明是纹理数据
                                texture2d texture3Y [[texture(6)]], // texture 表明是纹理数据
                                texture2d texture3UV [[texture(7)]], // texture 表明是纹理数据
                                texture2d texture4Y [[texture(8)]], // texture 表明是纹理数据
                                texture2d texture4UV [[texture(9)]], // texture 表明是纹理数据
                                constant XTConvertMatrix *convertMarix [[buffer(0)]], // buffer表示名缓存数据
                                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 textureY;
    texture2d 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);
}

在实现动态分屏的时候遇到一个问题:
我全局记录分屏的数据,过了特定时间后,前面的纹理数据会变化。比方就是说当过了4s,我会记录textureBuffer1,并且全局记录,然后继续往下跑,textureBuffer1的数据有发生变化。然后我打印pixelBuffer地址会重复,发现pixelBuffer重用了,然后我就记录下pixelBuffer,完美解决

具体代码放在Metal-11(分屏)里面。

热爱生活,记录生活!

你可能感兴趣的:(Metal学习(四) - 分屏播放)