我编写了以下测试内核来了解 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!)
}
}
这是输出(分别通过注释和取消注释黑色像素线)。