Metal与图形渲染十一:分屏滤镜

零. 前言

分屏滤镜是指在一个有限的区域内,将内容分割为若干个部分,应用在一些剪辑或者连麦展示效果上,做了个小demo,效果如下:

一. 分屏原理

分屏滤镜修改的是片段着色器,对于同一个渲染内容,可以分成若干个模块,对于某个模块来说,需要对原纹理进行采样,采样可以选择保持原比例不裁剪,或者居中裁剪。

但是如果该模块比例发生变化的话,保持比例裁剪就会产生压缩问题,比如上面的二分屏和三分屏。

下面分别给出了将x或y坐标二等分或三等分的方法,

二等分不裁剪:左半边将坐标 * 2,由[0, 0.5]区间变为[0, 1];右半边由[0.5, 1],变为[0, 1]。

二等分裁剪:左右半边均变为[0.25, 0.75]。

三等分不裁剪:和二等分类似,直接 * 3变为[0, 1]。

三等分裁剪:均变为[1 / 3, 2 / 3]。

float splitTwoCoor(float coor, bool centerCrop) {
    float res;
    
    if (centerCrop) {
        if (coor < 0.5) {
            res = coor + 0.25;
        }
        else {
            res = coor - 0.25;
        }
    } else {
        if (coor < 0.5) {
            res = coor * 2.0;
        }
        else {
            res = (coor - 0.5) * 2.0;
        }
    }
    
    return res;
}

float splitThreeCoor(float coor, bool centerCrop) {
    float res;
    
    if (centerCrop) {
        if (coor < 1.0 / 3) {
            res = coor + 1.0 / 3;
        }
        else if (coor > 2.0 / 3) {
            res = coor - 1.0 / 3;
        }
        else {
            res = coor;
        }
    } else {
        if (coor < 1.0 / 3) {
            res = coor * 3.0;
        }
        else if (coor < 2.0 / 3) {
            res = (coor - 1.0 / 3) * 3.0;
        }
        else {
            res = (coor - 2.0 / 3) * 3.0;
        }
    }
    
    return res;
}

二. 各等分的调用

二等分:将y坐标二等分

fragment float4
twoScreenSplitFragment(SingleInputVertexIO input [[ stage_in ]],
                       constant bool ¢erCrop [[ buffer(0) ]],
                       texture2d texture [[ texture(0) ]]) {
    float currentY = input.textureCoordinate.y;

    float sampleY = splitTwoCoor(currentY, centerCrop);

    constexpr sampler s;
    
    float4 color = texture.sample(s, float2(input.textureCoordinate.x, sampleY));

    return color;
}

三等分:将y坐标三等分

fragment float4
threeScreenSplitFragment(SingleInputVertexIO input [[ stage_in ]],
                         constant bool ¢erCrop [[ buffer(0) ]],
                         texture2d texture [[ texture(0) ]]) {
    float currentY = input.textureCoordinate.y;

    float sampleY = splitThreeCoor(currentY, centerCrop);

    constexpr sampler s;
    
    float4 color = texture.sample(s, float2(input.textureCoordinate.x, sampleY));
    
    return color;
}

四等分:将x、y坐标二等分

fragment float4
fourScreenSplitFragment(SingleInputVertexIO input [[ stage_in ]],
                        constant bool ¢erCrop [[ buffer(0) ]],
                        texture2d texture [[ texture(0) ]]) {
    float currentX = input.textureCoordinate.x;
    float currentY = input.textureCoordinate.y;
    
    float sampleX = splitTwoCoor(currentX, centerCrop);
    float sampleY = splitTwoCoor(currentY, centerCrop);
    
    constexpr sampler s;
    
    float4 color = texture.sample(s, float2(sampleX, sampleY));
    
    return color;
}

九等分:将x、y坐标三等分

fragment float4
nineScreenSplitFragment(SingleInputVertexIO input [[ stage_in ]],
                        constant bool ¢erCrop [[ buffer(0) ]],
                        texture2d texture [[ texture(0) ]]) {
    float currentX = input.textureCoordinate.x;
    float currentY = input.textureCoordinate.y;

    float sampleX = splitThreeCoor(currentX, centerCrop);
    float sampleY = splitThreeCoor(currentY, centerCrop);
    
    constexpr sampler s;
    
    float4 color = texture.sample(s, float2(sampleX, sampleY));
    
    return color;
}

三. 总结

本文主要介绍了分屏滤镜的原理,在业务的分屏滤镜中,可能有各种各样的样式要求,比如左半边展示一个大头像,右半边再四等分...这些都是可以通过修改片段着色器来实现的,其原理是在特定的区域按取样公式对整个纹理进行采样,从而达到分屏的效果。

四. 参考文章

OpenGL ES(九)-自定义滤镜(分屏滤镜)

你可能感兴趣的:(Metal与图形渲染十一:分屏滤镜)