【问题标题】:Resulting MTLTexture lighter than CGImage生成的 MTLTexture 比 CGImage 轻
【发布时间】:2020-10-10 04:51:02
【问题描述】:

我有内核函数,它必须将从 pixelBuffer(ARFrame.capturedImage) 创建的 Y 和 CbCr 纹理转换为 RGB 纹理,如苹果指南 https://developer.apple.com/documentation/arkit/displaying_an_ar_experience_with_metal 但我克服了明亮的纹理

kernel void renderTexture(texture2d<float, access::sample> capturedImageTextureY [[ texture(0) ]],
                          texture2d<float, access::sample> capturedImageTextureCbCr [[ texture(1) ]],
                      
                          texture2d<float, access::read_write> outTextue [[texture(2)]],
                      
                      
                          uint2 size [[threads_per_grid]],
                          uint2 pid [[thread_position_in_grid]]){


constexpr sampler colorSampler(mip_filter::linear,
                               mag_filter::linear,
                               min_filter::linear);


const float4x4 ycbcrToRGBTransform = float4x4(
    float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f),
    float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f),
    float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f),
    float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f)
);

float2 texCoord;
texCoord.x = float(pid.x) / size.x;
texCoord.y = float(pid.y) / size.y;

// Sample Y and CbCr textures to get the YCbCr color at the given texture coordinate
float4 ycbcr = float4(capturedImageTextureY.sample(colorSampler,    texCoord).r,
                      capturedImageTextureCbCr.sample(colorSampler, texCoord).rg, 1.0);

float4 color = ycbcrToRGBTransform * ycbcr;

outTextue.write(color, pid);

}

我使用以下代码创建 CGImage:

var cgImage: CGImage?
VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &cgImage)

     

cgImage 有正常的闪电

当我尝试使用 MTKTextureLoader 从 cgImage 创建纹理时,我也遇到了光照纹理

如何在 cgImage 中获得具有普通光的 MTLTexture

cgImage:(预期结果)

内核函数:

使用此代码创建纹理:

let descriptor = MTLTextureDescriptor()
descriptor.width = Int(Self.maxTextureSize.width)
descriptor.height = Int(Self.maxTextureSize.height)
descriptor.usage = [.shaderWrite, .shaderRead]
    
let texture = MTLCreateSystemDefaultDevice()?.makeTexture(descriptor: descriptor)

并使用内核函数写入像素。

已经尝试过MTLTextureDescriptor的不同pixelFormats

纹理加载器:

let textureLoader = MTKTextureLoader(device: MTLCreateSystemDefaultDevice()!)
let texturee = try! textureLoader.newTexture(cgImage: cgImage!, options: [.SRGB : (false as NSNumber)])

已经尝试过不同的 MTKTextureLoader.Options

GitHub 项目演示问题: PixelBufferToMTLTexture

【问题讨论】:

  • 通过这些示例很难理解问题所在,尝试将最小项目上传到 GitHub。
  • 你的 iPhone 型号是什么?
  • iPad Pro 第 4 代 12.9,Iphone XS
  • 场景套件似乎为您的纹理添加了额外的伽马校正
  • 您可以通过在着色器中添加伽马校正方程来解决此问题。

标签: swift textures metal metalkit


【解决方案1】:

当我尝试使用 MTKTextureLoader 从 cgImage 创建纹理时,我得到 过亮的纹理

这是因为金属对你的纹理应用了伽马校正。

MTKTextureLoader 有一个 SRGB 键,用于指定纹理数据是否存储为 sRGB 图像数据。

如果该值为 false,则将图像数据视为线性像素数据。 如果该值为 true,则将图像数据视为 sRGB 像素数据。如果 未指定此键且正在加载的图像已 经过伽玛校正,图像数据使用指定的 sRGB 信息。

let path = Bundle.main.path(forResource: "yourTexture", ofType: "png")!
let data = NSData(contentsOfFile: path) as! Data
let texture = try! textureLoader.newTexture(with: data, options: [MTKTextureLoaderOptionSRGB : (false as NSNumber)])

您也可以通过在着色器中添加gamma correcting equation 来解决此问题。

  • 与 sRGB 线性,反之亦然:

rgb = mix(rgb.0.0774, pow(rgb*0.9479 + 0.05213, 2.4), step(0.04045, rgb))

rgb = mix(rgb12.92, pow(rgb*0.4167) * 1.055 - 0.055, step(0.00313, rgb))

【讨论】:

  • 感谢您的回答,但 MTKTextureLoader.Option.SRGB 选项仅在我创建纹理表单路径/名称时对我有效,但当我从 cgImage 创建它时它没有
  • 当我使用这种转换时,会得到一点其他颜色,但太接近了。但是,当我使用答案中提供的代码时,我会得到 1:1 的颜色。
【解决方案2】:

问题已解决,感谢 0xBFE1A8,通过添加伽马校正

通过替换

outTextue.write(color, pid);

与:

outTextue.write(float4(pow(color.rgb, float3(2,2,2)), color.a), pid);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 2018-06-11
    • 2020-12-05
    • 2020-07-03
    • 1970-01-01
    相关资源
    最近更新 更多