swift 调整MTKView的大小在重绘之前缩放旧内容

kiz8lqtg  于 2023-04-28  发布在  Swift
关注(0)|答案(3)|浏览(175)

我使用MTKView来绘制金属内容。其配置如下:

mtkView = MTKView(frame: self.view.frame, device: device)
mtkView.colorPixelFormat = .bgra8Unorm
mtkView.delegate = self
mtkView.sampleCount = 4
mtkView.isPaused = true
mtkView.enableSetNeedsDisplay = true

setFrameSize被覆盖以触发重新显示。
每当视图调整大小时,它都会在重绘所有内容之前缩放其旧内容。这给人一种颤抖的感觉。
我尝试将MTKView层的contentGravity属性设置为不可调整大小的值,但这完全打乱了内容的比例和位置。看来MTKView不想让我摆弄这个参数。
如何确保在调整大小的过程中始终正确地重绘内容?

tjrkku2a

tjrkku2a1#

在我使用Metal和MTKView时,我尝试了presentsWithTransactionwaitUntilScheduled的各种组合,但都没有成功。在实时调整大小的过程中,我仍然偶尔会在正确渲染的内容帧之间看到拉伸内容的帧。
最后,我完全放弃了MTKView,并创建了我自己的NSView子类,它使用了CAMetalLayer和resize,现在看起来很好(没有使用任何presentsWithTransactionwaitUntilScheduled)。一个关键点是,我需要设置层的autoresizingMask,以便在调整窗口大小时每帧调用displayLayer方法。
下面是头文件:

#import <Cocoa/Cocoa.h>
    
@interface MyMTLView : NSView<CALayerDelegate>    
@end

下面是实现:

#import <QuartzCore/CAMetalLayer.h>
#import <Metal/Metal.h>

@implementation MyMTLView

- (id)initWithFrame:(NSRect)frame
{
    if (!(self = [super initWithFrame:frame])) {
        return self;
    }

    // We want to be backed by a CAMetalLayer.
    self.wantsLayer = YES;

    // We want to redraw the layer during live window resize.
    self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;

    // Not strictly necessary, but in case something goes wrong with live window
    // resize, this layer placement makes it more obvious what's going wrong.
    self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;

    return self;
}

- (CALayer*)makeBackingLayer
{
    CAMetalLayer* metalLayer = [CAMetalLayer layer];
    metalLayer.device = MTLCreateSystemDefaultDevice();
    metalLayer.delegate = self;

    // *Both* of these properties are crucial to getting displayLayer to be
    // called during live window resize.
    metalLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
    metalLayer.needsDisplayOnBoundsChange = YES;

    return metalLayer;
}

- (CAMetalLayer*)metalLayer
{
    return (CAMetalLayer*)self.layer;
}

- (void)setFrameSize:(NSSize)newSize
{
    [super setFrameSize:newSize];

    self.metalLayer.drawableSize = newSize;
}

- (void)displayLayer:(CALayer*)layer
{
    // Do drawing with Metal.
}

@end

作为参考,我在MTKView的drawRect方法中完成了所有的Metal绘图。

rryofs0p

rryofs0p2#

我有同样的问题与毛刺的看法调整大小。你甚至可以在苹果开发者网站的HelloTriangle示例中重现它。然而,效果被最小化,因为三角形画在屏幕中间附近,并且它是最靠近窗口边缘的内容,相对于拖动的角落,这是最糟糕的影响。关于使用presentsWithTransactionwaitUntilScheduled的开发人员说明对我也不起作用。
我的解决方案是在window.contentView.layer下面添加一个Metal层,并使该层足够大,几乎不需要调整大小。这样做的原因是,与window.contentView.layer不同,它会根据视图自动调整自身的大小(反过来保持窗口大小),您可以显式控制子层的大小。这消除了 Flink 。

bpzcxfmw

bpzcxfmw3#

这帮助了我-https://github.com/trishume/MetalTest
他使用MetalLayer并仔细设置各种属性。一切都是相当顺利,即使两个并排在同步滚动视图与4500万像素图像。
链接到我的原始问题How do I position an image correctly in MTKView?

相关问题