MetalPetal 1.25.2

MetalPetal 1.25.2

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布上次发布2023年2月

YuAo维护。



MetalPetal 1.25.2

  • YuAo

MetalPetal

Swift
Platforms Version
Apple Silicon Mac Catalyst Simulator
CocoaPods Swift PM

基于Metal的图像处理框架。

设计概述

MetalPetal是基于Metal设计的图像处理框架,旨在提供易于使用的编程接口,以实现静态图像和视频的实时处理。

本章涵盖了MetalPetal的关键概念,并有助于您更好地理解其设计、实现、性能影响和最佳实践。

目标

MetalPetal 设计时考虑了以下目标:

  • 易用的 API

    提供便利的 API 并避免常见错误。

  • 性能

    高效地使用 CPU、GPU 和内存。

  • 可扩展性

    易于创建自定义过滤器,以及插件你的自定义图像处理单元。

  • Swift 优化

    为 Swift 程序员提供流畅的使用体验。

核心组件

MetalPetal 的某些核心概念与苹果公司的 Core Image 框架中的概念非常相似。

MTIContext

为渲染 MTIImage 提供评估上下文。它也存储了大量的缓存以及状态信息,因此尽可能在可能的情况下重用上下文会更高效。

MTIImage

MTIImage 对象是待处理或生成的图像的表示。它不直接表示图像位图数据,而是包含生成图像(或更确切地说,MTLTexture)所需的所有信息。它由两部分组成,生成纹理的配方(MTIImagePromise)以及其他信息,例如 كيفية تطبيق المخزنة مما يساعد في تحسين أداء التطبيق (cachePolicy),以及如何手动生成从方式检查描述约束如何对纹理采样(samplerDescriptor)。

MTIFilter

MTIFilter代表图像处理效果及控制该效果的任何参数。它生成一个输出MTIImage对象。要使用滤波器,你需要创建滤波器对象,设置其输入图像和参数,然后访问其输出图像。通常,滤波器类拥有一个静态内核(MTIKernel),当你访问其outputImage属性时,它将与输入图像和参数一起请求内核以生成输出MTIImage

MTIKernel

MTIKernel代表图像处理例程。MTIKernel负责为滤波器创建相应的渲染或计算管线状态,以及为MTIImage构建MTIImagePromise

优化

MetalPetal在底层为您进行了大量的优化。

它会自动缓存函数、内核状态、采样器状态等。

它利用Metal的特性,如可编程混合、无内存渲染目标、资源堆和Metal性能着色器,使渲染更快、更高效。在macOS上,MetalPetal还可以利用Apple硅的TBDR架构。

在渲染之前,MetalPetal可以查看您的图像渲染图,并计算出完成渲染所需的中间纹理的最小数量,从而节省内存、能量和时间。

如果可以连接多个“食谱”,则还可以重新组织图像渲染图,以消除冗余渲染阶段。(MTIContext.isRenderGraphOptimizationEnabled

并发考虑

MTIImage对象是不可变的,这意味着它们可以在线程之间安全共享。

然而,MTIFilter对象是可变的,因此不能在线程之间安全共享。

MTIContext包含许多状态和缓存。有一个线程安全的机制用于MTIContext对象,使得在多个线程之间共享MTIContext对象是安全的。

比Core Image的优势

  • 完全可定制的顶点和片段函数。

  • 支持MRT(多个渲染目标)。

  • 通常性能更优。(需要详细的基准数据)

内建过滤器

  • 颜色矩阵

  • 颜色查找

    使用颜色查找表重新映射图像中的颜色。

  • 不透明度

  • 曝光度

  • 饱和度

  • 亮度

  • 对比度

  • 颜色反转

  • 亮度

    调整图像的饱和度,同时保持肤色适中。

  • RGB色调曲线

  • 混合模式

    • 正常
    • 相乘
    • 叠加
    • 屏幕
    • 硬光
    • 柔光
    • 变暗
    • 变亮
    • 色彩减淡
    • 添加(线性减淡)
    • 色彩加深
    • 线性加深
    • 浅色
    • 深色
    • 亮色
    • 线性光
    • 点光
    • 硬混合
    • 差值
    • 排除
    • 减去
    • 除法
    • 色调
    • 饱和度
    • 颜色
    • 亮度
    • 颜色查找512x512
    • 自定义混合模式
  • 与蒙版混合

  • 变换

  • 裁剪

  • 像素化

  • 多层合成

  • MPS 卷积

  • MPS 高斯模糊

  • MPS 定义

  • MPS 索贝尔

  • MPS 未 sharpened 面具

  • MPS盒式模糊

  • 高斯皮肤平滑

  • CLAHE(对比度受限自适应直方图均衡化)

  • 镜头模糊(六边形虚化模糊)

  • 表面模糊

  • 膨胀畸变

  • 颜色键混合

  • 色彩半色调

  • 网点

  • 圆角(圆形/连续曲线)

  • 所有核心图像过滤器

示例代码

创建一个 MTIImage

您可以从几乎所有图像数据源创建一个 MTIImage 对象,包括

  • 引用要加载的图像文件的 URL
  • 金属纹理
  • CoreVideo 图像或像素缓冲区(CVImageBufferRefCVPixelBufferRef
  • 内存中的图像位图数据
  • 来自给定纹理或图像资源的纹理数据
  • Core Image CIImage 对象
  • MDLTexture 对象
  • SceneKit 和 SpriteKit 场景
let imageFromCGImage = MTIImage(cgImage: cgImage, isOpaque: true)

let imageFromCIImage = MTIImage(ciImage: ciImage)

let imageFromCoreVideoPixelBuffer = MTIImage(cvPixelBuffer: pixelBuffer, alphaType: .alphaIsOne)

let imageFromContentsOfURL = MTIImage(contentsOf: url)

// unpremultiply alpha if needed
let unpremultipliedAlphaImage = image.unpremultiplyingAlpha()

应用过滤器

let inputImage = ...

let filter = MTISaturationFilter()
filter.saturation = 0
filter.inputImage = inputImage

let outputImage = filter.outputImage

渲染 MTIImage

let options = MTIContextOptions()

guard let device = MTLCreateSystemDefaultDevice(), let context = try? MTIContext(device: device, options: options) else {
    return
}

let image: MTIImage = ...

do {
    try context.render(image, to: pixelBuffer) 
    
    //context.makeCIImage(from: image)
    
    //context.makeCGImage(from: image)
} catch {
    print(error)
}

显示 MTIImage

let imageView = MTIImageView(frame: self.view.bounds)

// You can optionally assign a `MTIContext` to the image view. If no context is assigned and `automaticallyCreatesContext` is set to `true` (the default value), a `MTIContext` is created automatically when the image view renders its content.
imageView.context = ...

imageView.image = image

如果您想将GPU命令编码过程从主线程移出,可以使用MTIThreadSafeImageView。您可以在任何线程中将MTIImage分配给MTIThreadSafeImageView

连接过滤器(Swift)

MetalPetal提供了用于连接过滤器的类型安全的Swift API。您可以在FilterGraph.makeImage函数中使用=>运算符连接过滤器并获取输出图像。

以下是一些示例:

let image = try? FilterGraph.makeImage { output in
    inputImage => saturationFilter => exposureFilter => output
}
let image = try? FilterGraph.makeImage { output in
    inputImage => saturationFilter => exposureFilter => contrastFilter => blendFilter.inputPorts.inputImage
    exposureFilter => blendFilter.inputPorts.inputBackgroundImage
    blendFilter => output
}
  • 您可以直接使用=>连接一元过滤器(MTIUnaryFilter)。

  • 对于具有多个输入的过滤器,您需要连接到它的一个inputPorts

  • =>运算符仅在FilterGraph.makeImage方法中使用。

  • 只能将一个过滤器的输出连接到output

处理视频文件

处理AVPlayer

let context = try MTIContext(device: device)
let asset = AVAsset(url: videoURL)
let composition = MTIVideoComposition(asset: asset, context: context, queue: DispatchQueue.main, filter: { request in
    return FilterGraph.makeImage { output in
        request.anySourceImage! => filterA => filterB => output
    }!
}

let playerItem = AVPlayerItem(asset: asset)
playerItem.videoComposition = composition.makeAVVideoComposition()
player.replaceCurrentItem(with: playerItem)
player.play()

导出视频

VideoIO是需要使用以下示例的。

import VideoIO

var configuration = AssetExportSession.Configuration(fileType: .mp4, videoSettings: .h264(videoSize: composition.renderSize), audioSettings: .aac(channels: 2, sampleRate: 44100, bitRate: 128 * 1000))
configuration.videoComposition = composition.makeAVVideoComposition()
self.exporter = try! AssetExportSession(asset: asset, outputURL: outputURL, configuration: configuration)
exporter.export(progress: { progress in
    
}, completion: { error in
    
})

使用VideoIO处理实时视频

本示例需要VideoIO

import VideoIO

// Setup Image View
let imageView = MTIImageView(frame: self.view.bounds)
...

// Setup Camera
let camera = Camera(captureSessionPreset: .hd1920x1080, configurator: .portraitFrontMirroredVideoOutput)
try camera.enableVideoDataOutput(on: DispatchQueue.main, delegate: self)
camera.videoDataOutput?.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]

...

// AVCaptureVideoDataOutputSampleBufferDelegate

let filter = MTIColorInvertFilter()

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
        return
    }
    let inputImage = MTIImage(cvPixelBuffer: pixelBuffer, alphaType: .alphaIsOne)
    filter.inputImage = inputImage
    self.imageView.image = filter.outputImage
}

有关预览和录制滤镜实时视频的更多信息,请参阅示例项目中的CameraFilterView.swift

最佳实践

  • 尽可能重用MTIContext

    上下文是重量级对象,因此如果需要创建它,应该尽早创建,并在每次需要渲染图像时重用。

  • 明智地使用MTIImage.cachePolicy

    当您不希望保留图像的渲染结果时,例如当图像是滤镜链中的中间结果时,使用MTIImageCachePolicyTransient,以便可以重用渲染结果的底层纹理。这是最内存高效的选择。然而,当您要求上下文渲染先前渲染的图像时,可能会重新渲染该图像,因为其底层纹理已被重用。

    默认情况下,滤镜的输出图像具有transient策略。

    当您想防止底层纹理被重用时,使用MTIImageCachePolicyPersistent

    默认情况下,从外部源创建的图像具有persistent策略。

  • 了解MTIFilter.outputImage是计算属性。

    每次您要求滤镜提供其输出图像时,滤镜可能会提供一个新的输出图像对象,即使输入与之前的调用相同。因此,尽可能重用输出图像。

    例如,

    //          ╭→ filterB
    // filterA ─┤
    //          ╰→ filterC
    // 
    // filterB and filterC use filterA's output as their input.

    在这种情况下,以下

    let filterOutputImage = filterA.outputImage
    filterB.inputImage = filterOutputImage
    filterC.inputImage = filterOutputImage

    解决方案比

    filterB.inputImage = filterA.outputImage
    filterC.inputImage = filterA.outputImage

构建自定义滤镜

如果您想在.metal文件中包含MTIShaderLib.h,需要将MTIShaderLib.h文件的路径添加到Metal编译器 - 头文件搜索路径MTL_HEADER_SEARCH_PATHS)设置中。

例如,如果您使用CocoaPods,可以将MTL_HEADER_SEARCH_PATHS设置为${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders。如果您使用Swift Package Manager,设置MTL_HEADER_SEARCH_PATHS$(HEADER_SEARCH_PATHS)

着色器函数参数编码

MetalPetal 有一个内置机制来为您编码着色器函数参数。您可以将着色器函数参数作为 name: value 字典传递给 MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:)MTIRenderCommand(kernel:geometry:images:parameters:) 等。

例如,适用于 metal 函数 vibranceAdjust 的参数字典可以是

// Swift
let amount: Float = 1.0
let vibranceVector = float4(1, 1, 1, 1)
let parameters = ["amount": amount,
                  "vibranceVector": MTIVector(value: vibranceVector),
                  "avoidsSaturatingSkinTones": true,
                  "grayColorTransform": MTIVector(value: float3(0,0,0))]
// vibranceAdjust metal function
fragment float4 vibranceAdjust(...,
                constant float & amount [[ buffer(0) ]],
                constant float4 & vibranceVector [[ buffer(1) ]],
                constant bool & avoidsSaturatingSkinTones [[ buffer(2) ]],
                constant float3 & grayColorTransform [[ buffer(3) ]])
{
    ...
}

下表列出了着色器函数参数类型和参数字典中使用的对应类型。

着色器函数参数类型 Swift Objective-C
float Float float
int Int32 int
uint UInt32 uint
bool Bool bool
simd (float2,float4 float4x4, int4, 等.) simd (使用 MetalPetal/Swift) / MTIVector MTIVector
struct Data / MTIDataBuffer NSData / MTIDataBuffer
其他 (float * struct*, 等.) 不可变 Data / MTIDataBuffer NSData / MTIDataBuffer
其他 (float * struct*, 等.) 可变 MTIDataBuffer MTIDataBuffer

简单单输入/输出过滤器

要构建自定义一元过滤器,您可以继承 MTIUnaryImageRenderingFilter 并在 SubclassingHooks 类别中重写方法。示例:MTIPixellateFilterMTIVibranceFilterMTIUnpremultiplyAlphaFilterMTIPremultiplyAlphaFilter 等。

//Objective-C

@interface MTIPixellateFilter : MTIUnaryImageRenderingFilter

@property (nonatomic) float fractionalWidthOfAPixel;

@end

@implementation MTIPixellateFilter

- (instancetype)init {
    if (self = [super init]) {
        _fractionalWidthOfAPixel = 0.05;
    }
    return self;
}

+ (MTIFunctionDescriptor *)fragmentFunctionDescriptor {
    return [[MTIFunctionDescriptor alloc] initWithName:@"pixellateEffect" libraryURL:[bundle URLForResource:@"default" withExtension:@"metallib"]];
}

- (NSDictionary<NSString *,id> *)parameters {
    return @{@"fractionalWidthOfAPixel": @(self.fractionalWidthOfAPixel)};
}

@end
//Swift

class MTIPixellateFilter: MTIUnaryImageRenderingFilter {
    
    var fractionalWidthOfAPixel: Float = 0.05

    override var parameters: [String : Any] {
        return ["fractionalWidthOfAPixel": fractionalWidthOfAPixel]
    }
    
    override class func fragmentFunctionDescriptor() -> MTIFunctionDescriptor {
        return MTIFunctionDescriptor(name: "pixellateEffect", libraryURL: MTIDefaultLibraryURLForBundle(Bundle.main))
    }
}

完全自定义过滤器

要构建更复杂的过滤器,您只需创建一个内核 (MTIRenderPipelineKernel/MTIComputePipelineKernel/MTIMPSKernel),然后将内核应用于输入图像即可。示例:MTIChromaKeyBlendFilterMTIBlendWithMaskFilterMTIColorLookupFilter 等。

@interface MTIChromaKeyBlendFilter : NSObject <MTIFilter>

@property (nonatomic, strong, nullable) MTIImage *inputImage;

@property (nonatomic, strong, nullable) MTIImage *inputBackgroundImage;

@property (nonatomic) float thresholdSensitivity;

@property (nonatomic) float smoothing;

@property (nonatomic) MTIColor color;

@end

@implementation MTIChromaKeyBlendFilter

@synthesize outputPixelFormat = _outputPixelFormat;

+ (MTIRenderPipelineKernel *)kernel {
    static MTIRenderPipelineKernel *kernel;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        kernel = [[MTIRenderPipelineKernel alloc] initWithVertexFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:MTIFilterPassthroughVertexFunctionName] fragmentFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:@"chromaKeyBlend"]];
    });
    return kernel;
}

- (instancetype)init {
    if (self = [super init]) {
        _thresholdSensitivity = 0.4;
        _smoothing = 0.1;
        _color = MTIColorMake(0.0, 1.0, 0.0, 1.0);
    }
    return self;
}

- (MTIImage *)outputImage {
    if (!self.inputImage || !self.inputBackgroundImage) {
        return nil;
    }
    return [self.class.kernel applyToInputImages:@[self.inputImage, self.inputBackgroundImage]
                                      parameters:@{@"color": [MTIVector vectorWithFloat4:(simd_float4){self.color.red, self.color.green, self.color.blue,self.color.alpha}],
                                    @"thresholdSensitivity": @(self.thresholdSensitivity),
                                               @"smoothing": @(self.smoothing)}
                         outputTextureDimensions:MTITextureDimensionsMake2DFromCGSize(self.inputImage.size)
                               outputPixelFormat:self.outputPixelFormat];
}

@end

单次渲染通道中的多次绘制调用

您可以使用 MTIRenderCommand 在单次渲染通道中发出多次绘制调用。

// Create a draw call with kernelA, geometryA, and imageA.
let renderCommandA = MTIRenderCommand(kernel: self.kernelA, geometry: self.geometryA, images: [imageA], parameters: [:])

// Create a draw call with kernelB, geometryB, and imageB.
let renderCommandB = MTIRenderCommand(kernel: self.kernelB, geometry: self.geometryB, images: [imageB], parameters: [:])

// Create an output descriptor
let outputDescriptor = MTIRenderPassOutputDescriptor(dimensions: MTITextureDimensions(width: outputWidth, height: outputHeight, depth: 1), pixelFormat: .bgra8Unorm, loadAction: .clear, storeAction: .store)

// Get the output images, the output image count is equal to the output descriptor count.
let images = MTIRenderCommand.images(byPerforming: [renderCommandA, renderCommandB], outputDescriptors: [outputDescriptor])

您还可以创建多个输出描述符以在单次渲染通道中输出多个图像(MRT,请参见 https://en.wikipedia.org/wiki/Multiple_Render_Targets)。

自定义顶点数据

MTIVertex 无法满足您的需求时,您可以实现 MTIGeometry 协议,向命令编码器提供您的自定义顶点数据。

使用 MTIRenderCommand API 发出绘制调用并传递您的自定义 MTIGeometry

自定义处理模块

在罕见情况下,您可能希望直接访问底层纹理,在一个渲染通道中使用多个 MPS 内核,执行 3D 渲染,或自行编码渲染命令。

MTIImagePromise 协议为 MetalPetal 中的一步提供对底层纹理和渲染上下文的直接访问。

通过实现 MTIImagePromise 协议,您可以创建新的输入源或完全自定义的处理单元。您可能需要导入一个额外的模块才能这样做。

Objective-C

@import MetalPetal.Extension;

Swift

// CocoaPods
import MetalPetal.Extension

// Swift Package Manager
import MetalPetalObjectiveC.Extension

例如,请参阅 MTIComputePipelineKernelMTICLAHELUTRecipeMTIImage 的实现。

Alpha 类型

如果图像使用了 Alpha 通道,则有两种常见的表示方式:未预乘(直接/不相关)Alpha,和预乘(相关)Alpha。

在未预乘 Alpha 中,RGB 分量代表像素的颜色,不考虑其不透明度。

在预乘 Alpha 中,RGB 分量代表像素的颜色,并且通过乘法调整其不透明度。

MetalPetal 会显式处理 Alpha 类型。您负责在创建图像时提供正确的 Alpha 类型。

在 MetalPetal 中有三种子 Alpha 类型。

MTIAlphaType.nonPremultiplied:图像中的 Alpha 值未预乘。

MTIAlphaType.premultiplied:图像中的 Alpha 值已预乘。

MTIAlphaType.alphaIsOne:图像中没有 Alpha 通道,或者图像是不透明的。

通常,CGImageCVPixelBufferCIImage 对象具有预乘 Alpha 通道。如果您的不透明图像,例如来自摄像头输入的 CVPixelBuffer 或从 jpg 文件加载的 CGImage,请强烈推荐使用 MTIAlphaType.alphaIsOne

您可以在 MTIImage 上调用 unpremultiplyingAlpha()premultiplyingAlpha() 来转换图像的 Alpha 类型。

出于性能原因,Alpha 类型验证仅在调试构建中发生。

内置滤镜的Alpha处理

  • MetalPetal中的大多数滤镜均接受未预乘Alpha和对透明图像的支持,并输出未预乘Alpha图像。

  • 具有outputAlphaType属性的滤镜接受所有Alpha类型的输入。您可以使用outputAlphaType来指定输出图像的Alpha类型。

    例如:MTIBlendFilterMTIMultilayerCompositingFilterMTICoreImageUnaryFilterMTIRGBColorSpaceConversionFilter

  • 不实际更改颜色的滤镜采用透明度透传处理规则,即输出图像的Alpha类型与输入图像相同。

    例如:MTITransformFilterMTICropFilterMTIPixellateFilterMTIBulgeDistortionFilter

有关Alpha类型和Alpha合成的更多信息,请参阅Bartosz Ciechanowski的这篇令人惊叹的互动文章:Alpha合成

色彩空间

色彩空间在图像处理中至关重要。没有色彩空间,红、绿、蓝分量的数值就无意义。

在继续了解MetalPetal如何处理色彩空间之前,您可能需要了解色彩空间是什么以及它如何影响颜色值的表示。网上有许多关于色彩空间的解释文章,您可以从中入门,建议阅读色彩空间 - 由Bartosz Ciechanowski撰写

不同的软件和框架处理色彩空间的方式不同。例如,Photoshop具有默认的sRGB IEC61966-2.1工作色彩空间,而Core Image默认使用线性sRGB工作色彩空间。

Metal纹理不存储任何色彩空间信息。MetalPetal中的多数色彩空间处理发生在图像数据输入(MTIImage(...))和输出(MTIContext.render...)时。

输入的色彩空间

为输入指定色彩空间意味着MetalPetal应在创建纹理时将源色彩值转换为指定的色彩空间。

  • 当从 URLCGImage 加载时,您可以使用 MTICGImageLoadingOptions 指定纹理数据使用的颜色空间。如果您在加载图像时不指定任何选项,则使用设备 RGB 颜色空间(MTICGImageLoadingOptions.default)。一个 nil 颜色空间将禁用颜色匹配,这等价于使用输入图像的颜色空间来创建 MTICGImageLoadingOptions。如果指定颜色空间的模式不是 RGB,则使用设备 RGB 颜色空间作为后备。

  • 当从 CIImage 加载时,您可以使用 MTICIImageRenderingOptions 指定纹理数据使用的颜色空间。如果您在加载 CIImage 时不指定任何选项,则使用设备 RGB 颜色空间(MTICIImageRenderingOptions.default)。一个 nil 颜色空间将禁用颜色匹配,颜色值将在 CIContext 的工作颜色空间中加载。

输出颜色空间

指定输出颜色空间时,颜色空间更多像是一个标签,用于与系统通信如何表示输出中的颜色值。实际上并没有执行颜色空间转换。

  • 您可以使用 MTIContext.makeCGImage...MTIContext.startTaskTo... 方法并通过 colorSpace 参数指定输出 CGImage 的颜色空间。

  • 您可以使用 MTICIImageCreationOptions 指定输出 CIImage 的颜色空间。

如果没有指定输出颜色空间,MetalPetal假定输出颜色值位于设备 RGB 颜色空间。

CVPixelBuffer 的颜色空间

由于 MetalPetal 使用 CVMetalTextureCacheIOSurface 直接将 CVPixelBuffer 映射到 Metal 纹理,因此您无法为从 CVPixelBuffer 加载或渲染指定颜色空间。但是,您可以选择是否使用具有 sRGB 像素格式的纹理进行映射。

在 Metal 中,如果像素格式名称具有 _sRGB 后缀,则在读取和写入像素中的颜色值时将应用 sRGB 灰度压缩和解压缩。这意味着具有 _sRGB 像素格式的纹理假定它存储的颜色值是 sRGB 灰度校正的,当在着色器中读取颜色值时,执行 sRGB 到线性 RGB 的转换。当在着色器中写入颜色值时,执行线性 RGB 到 sRGB 的转换。

颜色空间转换

您可以使用MTIRGBColorSpaceConversionFilter来执行色彩空间转换。色彩空间转换函数也包含在MTIShaderLib.h中。

  • metalpetal::sRGBToLinear(sRGB IEC61966-2.1到线性sRGB)
  • metalpetal::linearToSRGB(线性sRGB到sRGB IEC61966-2.1)
  • metalpetal::linearToITUR709(线性sRGB到ITU-R 709)
  • metalpetal::ITUR709ToLinear(ITU-R 709到线性sRGB)

扩展

与SceneKit一起工作

您可以使用MTISCNSceneRendererSCNScene生成MTIImage。您可能需要处理SceneKit渲染器的线性RGB色彩空间,参见问题#76 SceneKit生成的图片比正常颜色暗

与SpriteKit一起工作

您可以使用MTISKSceneRendererSKScene生成MTIImage

与Core Image一起工作

您可以从CIImage创建MTIImage

您可以使用MTIContextMTIImage渲染为CIImage

您可以直接使用CIFilterMTICoreImageKernelMTICoreImageUnaryFilter类一起使用。(仅限Swift)

与JavaScript一起工作

参见MetalPetalJS

使用MetalPetalJS,您可以使用JavaScript创建渲染管线和过滤器,使其能够从“云”中下载您的过滤器/渲染器。

纹理加载器

建议您使用接受 MTICGImageLoadingOptions 的 API 来加载 CGImage 和从 URL 加载的图片,而不是使用接受 MTKTextureLoaderOption 的 API。

当您使用接受 MTKTextureLoaderOption 的 API 时,MetalPetal 默认使用 MTIDefaultTextureLoader 来加载 CGImage、从 URL 加载的图片和命名图片。《MTIDefaultTextureLoader》 在内部使用 MTKTextureLoader,并且在性能上有细微的成本为处理 MTKTextureLoader 的一致性和错误提供了一个解决方案。您还可以通过实现 MTITextureLoader 协议来自定义纹理加载程序。然后,在创建 MTIContext 时,将您的纹理加载程序类分配给 MTIContextOptions.textureLoaderClass

安装

CocoaPods

您可以使用 CocoaPods 来安装最新版本。

use_frameworks!

pod 'MetalPetal'

# Required if you are using Swift.
pod 'MetalPetal/Swift'

# Recommended if you'd like to run MetalPetal on Apple silicon Macs.
pod 'MetalPetal/AppleSilicon'

子库 Swift

提供针对 Objective-C API 的 Swift 特定的补充和修改,以改进它们映射到 Swift。如果您使用 Swift,则高度推荐使用。

子库 AppleSilicon

提供默认的 Metal Shading Language v2.3 编译库,用于在 Apple Silicon Mac 上启用可编程混合支持。

Swift 包管理器

将包依赖添加到您的应用程序

iOS 模拟器支持

MetalPetal 可以在 Xcode 11+ 和 macOS 10.15+ 的模拟器上运行。

MetalPerformanceShaders.framework 在模拟器上不可用,因此依赖于 MetalPerformanceShaders 的过滤器(如 MTIMPSGaussianBlurFilterMTICLAHEFilter)无法工作。

模拟器支持的特性少于实际 Apple GPU,或具有不同的实施限制。请参阅 在模拟器中运行 Metal 应用程序的开发 获取详细信息。

快速查看调试支持

如果您对 MTIImage 执行快速查看,它将显示您构成的图像图以生成该图像。

Quick Look Debug Preview

趣味事实

为什么是 Objective-C?

贡献

感谢您考虑为 MetalPetal 做贡献。请阅读我们的 贡献指南

许可证

MetalPetal遵循MIT许可证。 LICENSE

位于/MetalPetalExamples目录中的文件受其他许可证的约束。LICENSE.md

文档遵循CC-BY-4.0许可。