调整 MTKView 的大小会在重绘之前缩放旧内容
Resizing MTKView scales old content before redraw
我正在使用 MTKView 绘制 Metal 内容。配置如下:
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 不希望我 fiddle 使用该参数。
如何确保在调整大小时始终正确重绘内容?
我在调整视图大小时遇到同样的问题。您甚至可以在 Apple 开发者网站的 HelloTriangle 示例中重现它。然而,效果最小化,因为三角形绘制在屏幕中间附近,并且它是最接近 [=18= 边缘的内容,与拖动的角相对,受到的影响最差。关于使用 presentsWithTransaction
和 waitUntilScheduled
的开发人员注释对我也不起作用。
我的解决方案是在 window.contentView.layer
下面添加一个 Metal 层,并使该层足够大以至于几乎不需要调整大小。这样做的原因是,与 window.contentView.layer
不同,它会根据视图自动调整自身大小(进而保持 window 大小),您可以显式控制子层大小。这消除了闪烁。
在我对 Metal 和 MTKView
的使用中,我尝试了 presentsWithTransaction
和 waitUntilScheduled
的各种组合,但都没有成功。在实时调整大小时,我仍然偶尔会在正确渲染的内容帧之间遇到拉伸内容帧。
最后,我完全放弃了 MTKView
并创建了我自己的 NSView 子类,它使用 CAMetalLayer
并且调整大小现在看起来不错(没有使用任何 presentsWithTransaction
或 waitUntilScheduled
) .一个关键位是我需要设置图层的 autoresizingMask
以在 window 调整大小期间让每个帧调用 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 绘图。
这对我有帮助 - https://github.com/trishume/MetalTest
他使用 MetalLayer 并精心设置了各种属性。即使在具有 45 像素图像的同步滚动视图中两个并排显示,一切都非常流畅。
一个link我原来的问题How do I position an image correctly in MTKView?
我正在使用 MTKView 绘制 Metal 内容。配置如下:
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 不希望我 fiddle 使用该参数。
如何确保在调整大小时始终正确重绘内容?
我在调整视图大小时遇到同样的问题。您甚至可以在 Apple 开发者网站的 HelloTriangle 示例中重现它。然而,效果最小化,因为三角形绘制在屏幕中间附近,并且它是最接近 [=18= 边缘的内容,与拖动的角相对,受到的影响最差。关于使用 presentsWithTransaction
和 waitUntilScheduled
的开发人员注释对我也不起作用。
我的解决方案是在 window.contentView.layer
下面添加一个 Metal 层,并使该层足够大以至于几乎不需要调整大小。这样做的原因是,与 window.contentView.layer
不同,它会根据视图自动调整自身大小(进而保持 window 大小),您可以显式控制子层大小。这消除了闪烁。
在我对 Metal 和 MTKView
的使用中,我尝试了 presentsWithTransaction
和 waitUntilScheduled
的各种组合,但都没有成功。在实时调整大小时,我仍然偶尔会在正确渲染的内容帧之间遇到拉伸内容帧。
最后,我完全放弃了 MTKView
并创建了我自己的 NSView 子类,它使用 CAMetalLayer
并且调整大小现在看起来不错(没有使用任何 presentsWithTransaction
或 waitUntilScheduled
) .一个关键位是我需要设置图层的 autoresizingMask
以在 window 调整大小期间让每个帧调用 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 绘图。
这对我有帮助 - https://github.com/trishume/MetalTest
他使用 MetalLayer 并精心设置了各种属性。即使在具有 45 像素图像的同步滚动视图中两个并排显示,一切都非常流畅。
一个link我原来的问题How do I position an image correctly in MTKView?