金属是OpenGL混合的替代品

5

我正在尝试理解在Metal中与mix OpenGL函数对应的是什么。这是我想要转换的OpenGL代码:

float udRoundBox( vec2 p, vec2 b, float r )
{
    return length(max(abs(p)-b+r,0.0))-r;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // setup
    float t = 0.2 + 0.2 * sin(mod(iTime, 2.0 * PI) - 0.5 * PI);
    float iRadius = min(iResolution.x, iResolution.y) * (0.05 + t);
    vec2 halfRes = 0.5 * iResolution.xy;

    // compute box
    float b = udRoundBox( fragCoord.xy - halfRes, halfRes, iRadius );

    // colorize (red / black )
    vec3 c = mix( vec3(1.0,0.0,0.0), vec3(0.0,0.0,0.0), smoothstep(0.0,1.0,b) );

    fragColor = vec4( c, 1.0 );
} 

到目前为止,我已经成功转换了其中的一部分:

float udRoundBox( float2 p, float2 b, float r )
{
    return length(max(abs(p)-b+r,0.0))-r;
}

float4 cornerRadius(sampler_h src) {

    float2 greenCoord = src.coord(); // this is alreay in relative coords; no need to devide by image size

    float t = 0.5;
    float iRadius = min(greenCoord.x, greenCoord.y) * (t);
    float2 halfRes = float2(greenCoord.x * 0.5, greenCoord.y * 0.5);

    float b = udRoundBox( float2(greenCoord.x - halfRes.x, greenCoord.y - halfRes.y), halfRes, iRadius );

    float3 c = mix(float3(1.0,0.0,0.0), float3(0.0,0.0,0.0), smoothstep(0.0,1.0,b) );

    return float4(c, 1.0);
}

但是它正在生成绿色屏幕。我正在尝试在视频上实现类似于以下的圆角效果:

enter image description here

2个回答

5
混合函数是线性插值(通常称为Lerp函数)的一种实现。
当您有一个值t,并且想要知道该值在某个范围内的映射时,可以使用线性插值。
例如,如果我有三个值: a = 0 b = 1 和 t = 0.5
我可以调用mix(a,b,t),我的结果将是0.5。这是因为mix函数需要一个开始范围值、一个结束范围值和一个插值因子,所以我得到0.5,即0和1之间的中间值。
查看文档,Metal有一个mix的实现,用于进行线性插值。 enter image description here

谢谢您为我解释了这些基础知识,学习Metal/OpenGL的基本操作还有很长的路要走! - Roi Mulia

3
问题在于,变量名为greenCoord(顺便说一句,这只是你之前提出的问题中的一个好的变量名)是当前像素的相对坐标,与绝对输入分辨率无关。
如果您想要替换iResolution,请改用src.size()
而且看起来您需要以绝对(像素)单位获得输入坐标。您可以通过向内核的输入添加一个destination参数来实现此目的:
float4 cornerRadius(sampler src, destination dest) {
    const float2 destCoord = dest.coord(); // pixel position in the output buffer in absolute coordinates
    const float2 srcSize = src.size();

    const float t = 0.5;
    const float radius = min(srcSize.x, srcSize.y) * t;
    const float2 halfRes = 0.5 * srcSize;

    const float b = udRoundBox(destCoord - halfRes, halfRes, radius);

    const float3 c = mix(float3(1.0,0.0,0.0), float3(0.0,0.0,0.0), smoothstep(0.0,1.0,b) );

    return float4(c, 1.0);
}

嘿,弗兰克!再次感谢你。我想这是一个糟糕的命名,但我不敢冒险哈哈。成功了! :) 我开始更好地理解正在发生的事情,尽管今天花了我半天时间才意识到我需要使用Metal初始化CIContext而不是使用EAGL context来进行渲染。 - Roi Mulia
嘿,弗兰克,我们之前制作的VHS滤镜出现了新的内存消耗问题。似乎当我们使用4K视频时,设备非常吃力,并且会崩溃。问题是我们应用程序产生的最终输出不超过1080p,所以我们做了额外的工作却毫无意义。如果你有空,我希望你能看一下并指导我正确的方向(像往常一样)。这是链接:https://stackoverflow.com/questions/57153640/metal-resize-video-buffer-before-passing-to-custom-kernel-filter。非常感谢你,无话可说! - Roi Mulia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接