Metal學(xué)習(xí)(四) - 分屏播放

在看了《如何優(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(分屏)里面。

熱愛生活,記錄生活!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容