You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查看系统CIFilter默认实现及自定义MSL过渡滤镜问题排查

自定义CIFilter过渡滤镜开发问题排查

更新:根据@FrankSchlegel的回复,核心问题结论:无法查看系统原生CIFilter的内部实现逻辑。

我想知道是否可以查看部分默认CIFilter的实现,比如CIDissolveTransition、CISwipeTransition这类过渡滤镜?我需要开发自定义过渡滤镜,想尽可能参考一些Metal Shading Language的实现示例,但目前网上只能找到普通Metal管线的过渡滤镜实现,找不到基于MSL的相关示例。


更新1:淡入淡出滤镜代码移植问题

以下是我想要移植到MSL的淡入淡出滤镜示例代码:

#include <metal_stdlib>
using namespace metal;
#include "../../Vender/Render/Base/OperationShaderTypes.h"

struct TwoInputVertexIO
{
    float4 position [[position]];
    float2 textureCoordinate [[user(texturecoord)]];
    float2 textureCoordinate2 [[user(texturecoord2)]];
};
    
typedef struct
{
    float tweenFactor;
} FadeTransitionUniform;
    
fragment half4 fadeTransition(TwoInputVertexIO fragmentInput [[stage_in]],
                              texture2d<half> inputTexture [[texture(0)]],
                              texture2d<half> inputTexture2 [[texture(1)]],
                              constant FadeTransitionUniform& uniform [[ buffer(1) ]])
{
    
    constexpr sampler quadSampler;
    half4 textureColor = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);
    half4 textureColor2 = inputTexture2.sample(quadSampler, fragmentInput.textureCoordinate2);
    
    return half4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * half(uniform.tweenFactor)), textureColor.a);
}

以下是我移植失败的代码版本:

float4 fadeTransition(sampler fromTexture, sampler toTexture, float time) {
    
    float2 uv = fromTexture.coord();
    float4 textureColor = fromTexture.sample(uv);
    float4 textureColor2 = toTexture.sample(uv);
    
    return float4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * float(time)), textureColor.a);
    
}

目前这段代码没有任何效果,我猜测是没有添加constexpr sampler quadSampler对应的等效逻辑导致的。


更新2:CIKernel相关代码

以下是我初始化CIKernel的代码:

import CoreImage

class TestTransitionFilter: CIFilter {

    private let kernel: CIKernel
    @objc dynamic var inputImage: CIImage?
    @objc dynamic var inputImage2: CIImage?
    @objc dynamic var inputTime: CGFloat = 0
    
    override init() {
        let url = Bundle.main.url(forResource: "default", withExtension: "metallib")!
        let data = try! Data(contentsOf: url)
        kernel = try! CIKernel(functionName: "fadeTransition", fromMetalLibraryData: data)
        super.init()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func outputImage() -> CIImage? {
        
        guard let inputImage = inputImage else {return nil}
        guard let inputImage2 = inputImage2 else {return nil}
        
        return kernel.apply(extent: inputImage.extent, roiCallback: {
            (index, rect) in
            return rect.insetBy(dx: -1, dy: -1)
        }, arguments: [inputImage, inputImage2, inputTime])
    }
    
}

以下是我调用该滤镜的代码:

public class TestTransition: NoneTransition {
    
    override public func renderImage(foregroundImage: CIImage, backgroundImage: CIImage, forTweenFactor tween: Float64, renderSize: CGSize) -> CIImage {
        
    
        // 这段代码可正常运行
        /*
        if let crossDissolveFilter = CIFilter(name: "CIFlashTransition") {
            crossDissolveFilter.setValue(backgroundImage, forKey: "inputImage")
            crossDissolveFilter.setValue(CIVector(x: backgroundImage.extent.width / 2.0, y: backgroundImage.extent.height / 2.0), forKey: "inputCenter")
            crossDissolveFilter.setValue(foregroundImage, forKey: "inputTargetImage")
            crossDissolveFilter.setValue(tween, forKey: "inputTime")
            if let outputImage = crossDissolveFilter.outputImage {
                return outputImage
            }
        }*/
        
        
        // 这段代码无效果
        let filter = TestTransitionFilter()
        filter.inputImage = backgroundImage
        filter.inputImage2 = foregroundImage
        filter.inputTime = CGFloat(tween)
        
        if let outputImage = filter.outputImage {
            return outputImage
        }
        
        return super.renderImage(foregroundImage: foregroundImage, backgroundImage: backgroundImage, forTweenFactor: tween, renderSize: renderSize)
    }
}

最终排查结果

最终更新:经过两天排查找到了问题的根本原因:调用CIKernel的位置写的是filter.outputImage,而不是filter.outputImage()。


内容的提问来源于stack exchange,提问作者SmartTree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 15:09:03