金属计算着色器:将 alpha 设置为零不会产生完全透明
metal compute shader: setting alpha to zero does not yield complete transparency
我正在尝试修改这个人的代码:
https://github.com/FlexMonkey/MetalVideoCapture
从 iphone / ipad 摄像头获取视频并使用一些 Metal GPU 计算内核对其进行实时过滤。
我想更改 Metal 代码以执行一些简单的色度键控,我们将视频中的特定颜色设为透明(即该颜色的 alpha = 0)。
问题是金属计算内核生成的视频输出永远不会达到完全透明,即使您在金属计算内核的末尾强制 alpha 为零:
outTexture.write(float4(float3(rgb), 0.0), gid);
生成的视频只有部分透明。
注意我在设置
layer.opaque = 假
对于正在完成渲染的 MTKView。
有谁知道为什么会这样?
这是 alpha = 0 且 UIView 为红色背景的结果:
所以 Columbo 的回答对我有用,这里是我的色键过滤器的代码:
kernel void ChromaKey(texture2d<float, access::read> yTexture [[texture(0)]],
texture2d<float, access::read> cbcrTexture [[texture(1)]],
texture2d<float, access::write> outTexture [[texture(2)]],
uint2 gid [[thread_position_in_grid]])
{
float2 green = float2(54.0/255.0, 34.0/255.0);
float threshold = 0.05;
float3 colorOffset = float3(-(16.0/255.0), -0.5, -0.5);
float3x3 colorMatrix = float3x3(
float3(1.164, 1.164, 1.164),
float3(0.000, -0.392, 2.017),
float3(1.596, -0.813, 0.000)
);
uint2 cbcrCoordinates = uint2(gid.x / 2, gid.y / 2);
float y = yTexture.read(gid).r;
float2 cbcr = cbcrTexture.read(cbcrCoordinates).rg;
float alpha = smoothstep(threshold, threshold + 0.5, distance(cbcr, green));
float3 ycbcr = float3(y, cbcr);
float4 rgba = alpha * float4(colorMatrix * (ycbcr + colorOffset), 1.0);
outTexture.write(rgba, gid);
}
我的猜测是您的图层使用的是预乘 alpha (mentioned here)。如果是这样,那么您有两个简单的解决方案:
- 将层从预乘 alpha 合成更改为使用非预乘 alpha 合成。
- 更改计算内核以执行 alpha 预乘。
要执行 #2,您需要更改如下内容:
float alpha = <something_or_other>;
float3 rgb = colorMatrix * (ycbcr + colorOffset);
outTexture.write(float4(float3(rgb), alpha), gid);
像这样:
float alpha = <something_or_other>;
float3 rgb = (colorMatrix * (ycbcr + colorOffset)) * alpha;
outTexture.write(float4(float3(rgb), alpha), gid);
我正在尝试修改这个人的代码:
https://github.com/FlexMonkey/MetalVideoCapture
从 iphone / ipad 摄像头获取视频并使用一些 Metal GPU 计算内核对其进行实时过滤。
我想更改 Metal 代码以执行一些简单的色度键控,我们将视频中的特定颜色设为透明(即该颜色的 alpha = 0)。
问题是金属计算内核生成的视频输出永远不会达到完全透明,即使您在金属计算内核的末尾强制 alpha 为零:
outTexture.write(float4(float3(rgb), 0.0), gid);
生成的视频只有部分透明。
注意我在设置 layer.opaque = 假 对于正在完成渲染的 MTKView。
有谁知道为什么会这样?
这是 alpha = 0 且 UIView 为红色背景的结果:
所以 Columbo 的回答对我有用,这里是我的色键过滤器的代码:
kernel void ChromaKey(texture2d<float, access::read> yTexture [[texture(0)]],
texture2d<float, access::read> cbcrTexture [[texture(1)]],
texture2d<float, access::write> outTexture [[texture(2)]],
uint2 gid [[thread_position_in_grid]])
{
float2 green = float2(54.0/255.0, 34.0/255.0);
float threshold = 0.05;
float3 colorOffset = float3(-(16.0/255.0), -0.5, -0.5);
float3x3 colorMatrix = float3x3(
float3(1.164, 1.164, 1.164),
float3(0.000, -0.392, 2.017),
float3(1.596, -0.813, 0.000)
);
uint2 cbcrCoordinates = uint2(gid.x / 2, gid.y / 2);
float y = yTexture.read(gid).r;
float2 cbcr = cbcrTexture.read(cbcrCoordinates).rg;
float alpha = smoothstep(threshold, threshold + 0.5, distance(cbcr, green));
float3 ycbcr = float3(y, cbcr);
float4 rgba = alpha * float4(colorMatrix * (ycbcr + colorOffset), 1.0);
outTexture.write(rgba, gid);
}
我的猜测是您的图层使用的是预乘 alpha (mentioned here)。如果是这样,那么您有两个简单的解决方案:
- 将层从预乘 alpha 合成更改为使用非预乘 alpha 合成。
- 更改计算内核以执行 alpha 预乘。
要执行 #2,您需要更改如下内容:
float alpha = <something_or_other>;
float3 rgb = colorMatrix * (ycbcr + colorOffset);
outTexture.write(float4(float3(rgb), alpha), gid);
像这样:
float alpha = <something_or_other>;
float3 rgb = (colorMatrix * (ycbcr + colorOffset)) * alpha;
outTexture.write(float4(float3(rgb), alpha), gid);