【问题标题】:Creating a UIControl that is a MTKView or otherwise uses Metal for rendering创建一个作为 MTKView 或使用 Metal 进行渲染的 UIControl
【发布时间】:2018-07-23 02:59:40
【问题描述】:

我正在尝试做一些使用金属进行渲染的自定义 UIControls。这些将在基于 UIKit 的界面中使用。屏幕上一次会有大约 3 个不同的,所以我认为 MTKView 可能是这里的正确选择。

我想不惜一切代价节省 CPU 和 GPU 的工作量,在没有明确编辑时不要不必要地使用 CPU 或 GPU 能量来更新这些视图。它们没有动画。

我的问题是我希望这些是 UIControls,以便我制作的类可以轻松地从 InterfaceBuilder 中使用,并且可以响应、发送和委托 UIEvents。

Swift 不支持多重继承,我该怎么做呢?我在尝试正确的事情吗?

【问题讨论】:

  • 我还没有这样做,但是您能否继承UIControl 并添加一个或多个MTKViews 或CAMetalLayers,以便在您的视图需要重绘时绘制到其中?您最终可能会出现几帧延迟,但这似乎是可能的并且符合您的标准。
  • 据我了解,UIKit 在现代版本的 iOS 中已经基于 Metal 构建。您想达到哪些用普通技术无法实现的目标?
  • 花式渐变色

标签: xcode uikit metal


【解决方案1】:

您可能会使用UIControl 并知道它是UIView 的子类。因此,您可以在 UIControl 中实现一个布尔属性,该属性存储是否可以使用 Metal,并为其他技术提供后备以在金属不可用的情况下呈现内容。

您需要考虑当您分配多个自定义 UIControls 时,Metal/GPU 将一个一个地渲染它们而不是并行渲染它们,除非您定义一个全局渲染器,该渲染器可以一次渲染所有控件图形,并将其放置为 '基本 UIView 的几乎最前面的层。您将希望通过

来使用透明度
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);

并且还要考虑触摸/事件处理可能会被这样的层干扰。这一切都可以很好地处理。或者你可以在你的基础视图中实现它,然后使用 UIControls 在提到的全局渲染器中设置即 Uniforms

作为起点,您将使用类似的东西

@interface yourUIControl {
    MTKView * mtkview;
    YourMetalRenderer * _yourRenderer;
    BOOL _isMetalDriven;
}
@end

@implementation yourUIControl

-(BOOL)isMetalPerforming:(CGRect)frame {
    mtkview = [[MTKView alloc] init];
    [MTKView setAnimationsEnabled:NO];
    mtkview.preferredFramesPerSecond = 24;
    mtkview.presentsWithTransaction = NO;
    mtkview.contentMode = UIViewContentModeScaleAspectFill;
    mtkview.frame = frame;
    mtkview.device = MTLCreateSystemDefaultDevice();
    if(!mtkview.device) {
        NSLog(@"Metal is not supported on this device");
        return NO;
    } else {
        _yourRenderer = [[YourMetalRenderer alloc] initWithMetalKitView:mtkview];
        if (!_yourRenderer) {
            NSLog(@"Renderer failed initialization");
            return NO;
        } else {
            [_yourRenderer mtkView:mtkview drawableSizeWillChange:mtkview.drawableSize];
            mtkview.delegate = _yourRenderer;
            [self addSubview:mtkview];
            return YES;
        }
    }
}

然后在初始化您的自定义 UIControl 时像这样设置您的 BOOL 属性

-(instancetype)initWithFrame:(CGRect)frame {
    if ( !(self = [super initWithFrame:frame]) ) return nil;
    // ask for the renderer and set BOOL property
    _isMetalDriven = [self isMetalPerforming:frame];
    // handling fallback if i.e. metal is not performing
    if (!_isMetalDriven) {
       // your classic layer technique to create UIControls content here.
       // dont forget when the control is changed in some way, you will forward
       // changes to _yourRenderer (i.e. Uniform properties) OR to classic handling  
    }
    //your other UIControl code
    return self;
}

-(void)layoutSubviews {
    if (!_isMetalDriven) { 
        //classic control layout here..

    } else {
        //metal backed layout here..
        mtkview.frame = self.frame; //i.e.
    }
}

@end

如果需要,您可以将 pause 渲染器设置为“是”和“否”,甚至可以根据 DisplayLink 或 setNeedsDisplay 使用 mtkView 中的适当属性进行渲染过程

您的CAMetalLayer 将存在于mtkview.layer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 2019-03-28
    • 2019-07-13
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    相关资源
    最近更新 更多