-1

我编写了以下测试内核来了解 Metal Core Image Shaders 中的采样。我想要实现的是以下。inputImage 边界(范围)之外的任何像素都应该是黑色的,其他像素应该像往常一样是 inputImage 的像素。但是我没有看到所需的输出,所以我对采样器在着色器中的工作方式的理解有问题。获取inputImage的世界坐标没有简单的方法,只有destination支持世界坐标。这是我的代码。

extern "C" float4 testKernel(coreimage::sampler inputImage, coreimage::destination dest)
 {
  float2 inputCoordinate = inputImage.coord();
  float4 color = inputImage.sample(inputCoordinate);
  float2 inputOrigin = inputImage.origin();
  float2 inputSize = inputImage.size();
  float2 destCoord = dest.coord();

   if (inputCoordinate.x * inputSize.x < destCoord.x || inputCoordinate.y * inputSize.y > destCoord.y) {
       return float4(0.0, 0.0, 0.0, 1.0);
   }


   return color;
}

这是过滤器的 Swift 代码:

 class CIMetalTestRenderer: CIFilter {
    var inputImage:CIImage?

    static var kernel:CIKernel = { () -> CIKernel in

    let bundle = Bundle.main
    let url = bundle.url(forResource: "Kernels", withExtension: "ci.metallib")!
    let data = try! Data(contentsOf: url)
    return try! CIKernel(functionName: "testKernel", fromMetalLibraryData: data)
    
  }()

override var outputImage: CIImage? {
    guard let inputImage = inputImage else {
        return nil
    }
    
    let dod = inputImage.extent.insetBy(dx: -10, dy: -10)
    return CIMetalTestRenderer.kernel.apply(extent: dod, roiCallback: { index, rect in
        return rect
    }, arguments: [inputImage])
 }
}

更新:这是我的 ViewController 的完整代码。我只是在情节提要中有 UIImageView (也可以在 viewDidLoad 中创建):

class ViewController: UIViewController {

@IBOutlet weak var imageView:UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
   
    generateSolidImage()
}

private func generateSolidImage() {
    let renderSize = imageView.bounds.size
    
    let solidSize = CGSize(width: renderSize.width * 0.5, height: renderSize.height * 0.5)
    
    var solidImage = CIImage(color: CIColor(red: 0.3, green: 0.6, blue: 0.754, alpha: 1))
    
    var cropRect = CGRect.zero
    cropRect.size = solidSize
    solidImage = solidImage.cropped(to: cropRect)
    solidImage = solidImage.transformed(by: CGAffineTransform.init(translationX: -10, y: -10))
    
    
    let metalRenderer = CIMetalTestRenderer()
    metalRenderer.inputImage = solidImage
    
    var outputImage = metalRenderer.outputImage
    
    outputImage = outputImage?.transformed(by: CGAffineTransform.init(translationX: 20, y: 20))
    let cyanImage = CIImage(color: CIColor.cyan).cropped(to: CGRect(x: 0, y: 0, width: renderSize.width, height: renderSize.height))
    
    outputImage = outputImage?.composited(over: cyanImage)
    
    let ciContext = CIContext()
    
    let cgImage = ciContext.createCGImage(outputImage!, from: outputImage!.extent)
    
    imageView.image = UIImage(cgImage: cgImage!)
    
}

}

这是输出(分别通过注释和取消注释黑色像素线)。

在此处输入图像描述

在此处输入图像描述

4

1 回答 1

1

我认为问题在于比较,dest.coord()因为这也会根据当前正在处理的像素而变化。

如果您只想检查您当前是否在 的范围之外进行采样inputImage,您可以简单地执行以下操作:

if (inputCoordinate.x < 0.0 || inputCoordinate.x > 1.0 ||
    inputCoordinate.y < 0.0 || inputCoordinate.y > 1.0) {
    return float4(0.0, 0.0, 0.0, 1.0);
}

但是,有一种更简单的方法可以实现“clamp-to-black”效果:

let clapedToBlack = solidImage.composited(over: CIImage.black)
于 2022-02-06T10:33:43.273 回答