Convert OpenGL shader to Metal (Swift) to be used in CIFilter

前端 未结 1 477
清歌不尽
清歌不尽 2021-01-22 11:12

I\'m quite new to OpenGL/Metal and I\'m trying to understand some fundamental concepts.
Within our app, we are using CIFilter to filte

相关标签:
1条回答
  • 2021-01-22 11:56

    I gave it a try. Here's the kernel code:

    #include <metal_stdlib>
    using namespace metal;
    #include <CoreImage/CoreImage.h>
    
    extern "C" { namespace coreimage {
    
        float4 vhs(sampler_h src, float time, float amount) {
            const float magnitude = sin(time) * 0.1 * amount;
    
            float2 greenCoord = src.coord(); // this is alreay in relative coords; no need to devide by image size
    
            const float split = 1.0 - fract(time / 2.0);
            const float scanOffset = 0.01;
            float2 redCoord = float2(greenCoord.x + magnitude, greenCoord.y);
            float2 blueCoord = float2(greenCoord.x, greenCoord.y + magnitude);
            if (greenCoord.y > split) {
                greenCoord.x += scanOffset;
                redCoord.x += scanOffset;
                blueCoord.x += scanOffset;
            }
    
            float r = src.sample(redCoord).r;
            float g = src.sample(greenCoord).g;
            float b = src.sample(blueCoord).b;
    
            return float4(r, g, b, 1.0);
        }
    
    }}
    

    And here some slight adjustments to outputImage in your filter:

    override var outputImage: CIImage? {
        guard let inputImage = self.inputImage else { return nil }
    
        // could be filter parameters
        let inputTime: NSNumber = 60
        let inputAmount: NSNumber = 0.3
    
        // You need to tell the kernel the region of interest of the input image,
        // i.e. what region of input pixels you need to read for a given output region.
        // Since you sample pixels to the right and below the center pixel, you need
        // to extend the ROI accordingly.
        let magnitude = CGFloat(sin(inputTime.floatValue) * 0.1 * inputAmount.floatValue)
        let inputExtent = inputImage.extent
    
        let roiCallback: CIKernelROICallback = { _, rect -> CGRect in
            return CGRect(x: rect.minX, y: rect.minY,
                          width: rect.width + (magnitude + 0.01) * inputExtent.width, // scanOffset
                          height: rect.height + magnitude * inputExtent.height)
        }
    
        return self.kernel.apply(extent: inputExtent,
                                 roiCallback: roiCallback,
                                 arguments: [inputImage, inputTime, inputAmount])
    }
    
    0 讨论(0)
提交回复
热议问题