iOS:金属、CoreImage和GL着色器

iOS:金属、CoreImage和GL着色器,ios,opengl,shader,metal,core-image,Ios,Opengl,Shader,Metal,Core Image,我想将我正在使用的相机从GL(GPUImage)切换到金属 我试图找出我使用的金属着色器可能有什么问题,以便将查找过滤器应用于MTLtexture,但我有一些带状问题,如蓝色线条,尤其是在显示暗渐变时 这些蓝带问题在应用金属着色器时出现,而不是在使用CoreImage时出现。 图像的其余部分很好。 以下是使用查找图像生成高对比度的示例: (两个示例的源图像完全相同) 正如你们所见,金属似乎不如CoreImage精确,并产生了这些奇怪的蓝带 我想知道这是否是一个正常的问题,因为这两个着色器都是B

我想将我正在使用的相机从GL(GPUImage)切换到金属

我试图找出我使用的金属着色器可能有什么问题,以便将查找过滤器应用于MTLtexture,但我有一些带状问题,如蓝色线条,尤其是在显示暗渐变时

这些蓝带问题在应用金属着色器时出现,而不是在使用CoreImage时出现。 图像的其余部分很好。 以下是使用查找图像生成高对比度的示例:

(两个示例的源图像完全相同)

正如你们所见,金属似乎不如CoreImage精确,并产生了这些奇怪的蓝带

我想知道这是否是一个正常的问题,因为这两个着色器都是Brad Larson工作的改编

金属着色器:

kernel void LookupFilterKernel(texture2d<float, access::read> sourceTexture [[texture(0)]],
                        texture2d<float, access::write> outTexture [[texture(1)]],
                        texture2d<float, access::read> lutTexture [[texture(2)]],
                        uint2 gid [[thread_position_in_grid]]){

 float4 color = sourceTexture.read(gid);

 float blueColor = color.b * 63.0;

 float2 quad1;
 quad1.y = floor(floor(blueColor) / 8.0);
 quad1.x = floor(blueColor) - (quad1.y * 8.0);

 float2 quad2;
 quad2.y = floor(ceil(blueColor) / 8.0);
 quad2.x = ceil(blueColor) - (quad2.y * 8.0);

 float2 texPos1;
 texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);
 texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);

 float2 texPos2;
 texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);
 texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);

 float4 newColor1 = lutTexture.read(uint2(texPos1.x * 512 , texPos2.y * 512));
 float4 newColor2 = lutTexture.read(uint2(texPos2.x * 512, texPos2.y * 512 ));

 float4 newColor = mix(newColor1, newColor2, fract(blueColor));


 float4 finalColor = mix(color, float4(newColor.rgb, color.w), 1.0);

 outTexture.write(finalColor, gid);
}
源纹理是从相机的captureOutput功能接收的MTLTexture im

如果你知道我为什么会有这个问题,或者你需要更多的代码/解释,请告诉我

非常感谢

编辑1:

在Frank的回答之后,我试图解决这些问题。因此,我线性化了LUT纹理和源纹理,更新着色器:

static float linearTosRGB(float c) {
return powr(c, 1./2.2);
}

static float srgbToLinear(float c) {
if (c <= 0.04045)
    return c / 12.92;
else
    return powr((c + 0.055) / 1.055, 2.4);
}

kernel void LookupFilterKernel(texture2d<float, access::read> sourceTexture [[texture(0)]],
                        texture2d<float, access::write> outTexture [[texture(1)]],
                        texture2d<float, access::read> lutTexture [[texture(2)]],
                        uint2 gid [[thread_position_in_grid]]){

float4 color = sourceTexture.read(gid);
color.r = srgbToLinear(color.r);
color.g = srgbToLinear(color.g);
color.b = srgbToLinear(color.b);

float blueColor = color.b * 63.0;

float2 quad1;
quad1.y = floor(floor(blueColor) / 8.0);
quad1.x = floor(blueColor) - (quad1.y * 8.0);

float2 quad2;
quad2.y = floor(ceil(blueColor) / 8.0);
quad2.x = ceil(blueColor) - (quad2.y * 8.0);

float2 texPos1;
texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);
texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);

float2 texPos2;
texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);
texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);

float4 newColor1 = lutTexture.read(uint2(texPos1.x * 512 , texPos2.y * 512));
float4 newColor2 = lutTexture.read(uint2(texPos2.x * 512, texPos2.y * 512 ));
float4 newColor = mix(newColor1, newColor2, fract(blueColor));

float4 finalColor = mix(color, float4(newColor.rgb, color.w), 1.0);
finalColor.r = linearTosRGB(finalColor.r);
finalColor.g = linearTosRGB(finalColor.g);
finalColor.b = linearTosRGB(finalColor.b);

outTexture.write(finalColor, gid);
}
float4 newColor = mix(newColor1, newColor2, fract(blueColor));
致:

蓝色条纹消失了。我假设quad1的计算不正确,产生了这些带。
所以我的问题是:为什么这只发生在金属着色器上,而不发生在CoreImage或GPUImage的着色器上?

非常有趣。。。我现在能想象的唯一不同是核心图像应用了自动颜色管理(如果没有配置其他)。这意味着它将把输入图像转换成线性光sRGB颜色空间,也就是LUT。你需要明确地告诉它不要那样做。这就是为什么我觉得很奇怪,CI版本实际上是正确的…@FrankSchlegel谢谢你的回答。我编辑了这个问题,试图调整金属着色器以使用线性颜色空间。不幸的是,结果仍然是错误的。您如何创建
MTLTexture
s以及以何种格式创建?默认情况下,核心图像使用16位半浮点数类型的纹理。也许您的金属实现使用了不同的精度?我使用的MTLTextureDescriptor如下:MTLTextureDescriptor*texDesc=[MTLTextureDescriptor Texture2dDescriptor with PixelFormat:MTLPixelFormatBGRA8Unorm宽度:宽度高度:高度mipmapped:NO];您认为这是由于MTLPixelFormatBGRA8Unorm标志吗?那么,它肯定是8位的。也许可以尝试使用
MTLPixelFormatRGBA16Float
格式?
kernel void sRGBToLinearKernel(texture2d<float, access::read> sourceTexture [[texture(0)]],
                           texture2d<float, access::write> outTexture [[texture(1)]],
                           uint2 gid [[thread_position_in_grid]]){
float4 color = sourceTexture.read(gid);
color.r = srgbToLinear(color.r);
color.g = srgbToLinear(color.g);
color.b = srgbToLinear(color.b);
outTexture.write(color, gid);
}
float4 newColor = mix(newColor1, newColor2, fract(blueColor));
float4 newColor = mix(newColor1, newColor2, 1.0);