仅当调整窗口大小时,图层支持的 OpenGLView 才会重绘

2024-03-04

我有一个带有类型主视图的窗口NSView和一个子视图,它是NSOpenGLView谁的名字是CustomOpenGLView。 的子类NSOpenGLView是通过一个获得Custom View在 Interface Builder 中并将其类设置为CustomOpenGLView。 这是根据Apple示例代码制作的图层支持的 OpenGLView http://developer.apple.com/library/mac/#samplecode/LayerBackedOpenGLView/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004386.

该应用程序每隔 0.05 秒向 OpenGLContext 绘制一些内容。 具有核心动画层disabled我能够在视图中看到移动的对象,这是视图不断重绘的结果。一切都完美无缺。

我现在想要在上面有一个半透明的视图CustomOpenGLView容纳控制按钮,如播放/停止/ecc..

为此,我添加了一个子视图CustomOpenGLView我已经启用了核心动画层CustomOpenGLView。控制按钮放置在这个新的子视图中。

这样带有控制按钮的视图就可以正确地出现在CustomOpenGLView但现在视图不会重绘。仅当我调整包含所有这些视图的窗口大小时,它才会绘制。

结果是我没有看到任何“动画”...我只看到一个静态图像,它代表绘图循环开始时绘制的第一帧。 如果我调整窗口大小,openGLContext 会重新绘制,直到我停止调整窗口大小。之后,我再次看到一张静止图像,其中最后一次绘制是在调整大小期间发生的。

此外,当绘图循环开始时,只有第一个“帧”出现在屏幕上,如果我调整窗口大小,比如说 5 秒后,我会在视图中准确地看到在开始后 5 秒应该绘制的内容。绘图循环。 看来我需要设置[glView setNeedsDisplay:TRUE]。我这样做了,但什么都没有改变。

错误在哪里?为什么添加核心动画层会破坏重绘?这是否意味着我没有得到什么?


当你有一个正常的NSOpenGLView,你可以简单地通过 OpenGL 绘制一些东西,然后调用-flushBuffer of the NSOpenGLContext使渲染出现在屏幕上。如果你的上下文不是双缓冲的,如果你渲染到一个窗口,这是不必要的,因为在 MacOS X 中所有窗口都已经是双缓冲的,调用glFlush()也足够了(仅对于真正的全屏 OpenGL 渲染,您需要双缓冲以避免伪影)。然后,OpenGL 将直接渲染到视图的像素存储中(实际上是窗口的后备存储),或者在双缓冲的情况下,它将渲染到后缓冲区,然后与前缓冲区交换;因此,新内容立即在屏幕上可见(实际上不是在下一次屏幕刷新之前,但这样的刷新每秒至少发生 50-60 次)。

如果NSOpenGLView是层支持的。你打电话时-flushBuffer or glFlush(),渲染实际上确实像之前一样发生了,图像直接渲染到视图的像素存储中,但是,这个像素存储不再是窗口的后备存储,它是“后备层” ”的观点。因此,您的 OpenGL 图像已更新,您只是看不到它发生,因为“绘制到图层中”和“在屏幕上显示图层”是两个完全不同的事情!要使新图层内容可见,您必须调用setNeedsDisplay:YES在你的层支持上NSOpenGLView.

为什么当你打电话时它对你不起作用setNeedsDisplay:YES?首先,确保在主线程上执行此调用。您可以在您喜欢的任何线程上执行此调用,它肯定会将视图标记为脏,但只有在主线程上执行此调用时,它还会为其安排重绘调用(如果没有该调用,它会被标记为脏,但它在重绘其任何其他父/子视图之前不会重绘)。另一个问题可能是drawRect:方法。当您将视图标记为脏并重新绘制时,将调用此方法,并且此方法“绘制”的任何内容都会覆盖图层中当前的任何内容。只要您的视图不是基于图层的,那么在何处渲染 OpenGL 内容并不重要,但对于基于图层的视图,这实际上是您应该执行所有绘图的方法。

尝试以下操作: 创建一个NSTimer在你的主线程上,每 20 毫秒触发一次并调用一个方法,该方法调用setNeedsDisplay:YES在你的层支持上NSOpenGLView。将所有 OpenGL 渲染代码移至drawRect:你的层支持的方法NSOpenGLView。那应该效果很好。如果您需要比NSTimer, try a CVDisplayLink(CV = 核心视频)。 ACVDisplayLink就像一个计时器,但每次屏幕重新绘制时它都会触发。

Update

分层 NSOpenGLView 有点过时了,从 10.6 开始,它们不再需要了。当您将其分层时,NSOpenGLView 在内部会创建一个 NSOpenGLLayer,因此您也可以自己直接使用这样的层并“构建”您自己的 NSOpenGLView:

  1. 创建您自己的子类NSOpenGLLayer,我们称之为MyOpenGLLayer
  2. 创建您自己的子类NSView,我们称之为MyGLView
  3. 覆盖- (CALayer *)makeBackingLayer返回一个自动释放的实例MyOpenGLLayer
  4. Set wantsLayer:YES for MyGLView

您现在拥有自己的图层支持视图,并且它是由 NSOpenGLLayer 子类支持的图层。因为它是层支持,向其中添加子视图(例如按钮、文本字段等)是绝对可以的。

对于您的背衬层,您基本上有两种选择。

Option 1
正确且官方支持的方法是将渲染保持在主线程上。因此,您必须执行以下操作:

  • 覆盖canDrawInContext:...回来YES/NO,取决于您是否可以/想要绘制下一帧。
  • 覆盖drawInContext:...执行实际的 OpenGL 渲染。
  • 使层异步(setAsynchronous:YES)
  • 确保图层在调整大小时“更新”(setNeedsDisplayOnBoundsChange:YES),否则当调整图层大小时,OpenGL 背衬表面不会调整大小(并且每次图层重绘时,渲染的 OpenGL 上下文都必须拉伸/收缩)

苹果将​​创建一个CVDisplayLink对你来说,这需要canDrawInContext:...每次触发时在主线程上并且如果此方法返回YES,它调用drawInContext:...。这就是你应该这样做的方式。

如果您的渲染成本太高而无法在主线程上进行,您可以执行以下技巧:覆盖openGLContextForPixelFormat:...创建与您之前创建的另一个上下文(上下文 A)共享的上下文(上下文 B)。在上下文 A 中创建一个帧缓冲区(您可以在创建上下文 B 之前或之后执行此操作,这并不重要);如果需要的话附加深度和/或模板渲染缓冲区(您选择的位深度),但是不是颜色渲染缓冲区,而是附加“纹理”(纹理 X)作为颜色附件(glFramebufferTexture())。现在,在渲染到该帧缓冲区时,所有颜色渲染输出都会写入该纹理。在您选择的任何线程上使用上下文 A 执行对此帧缓冲区的所有渲染!渲染完成后,进行canDrawInContext:... return YES and in drawInContext:...就画个简单的quad它填充整个活动帧缓冲区(Apple 已经为您设置了它以及视口以完全填充它)并且使用纹理 X 进行纹理化。这是可能的,因为共享上下文还共享所有对象(例如纹理、帧缓冲区、 ETC。)。所以你的drawInContext:...方法永远不会比绘制一个简单的、简单的纹理四边形更重要,仅此而已。所有其他(可能昂贵的渲染)都发生在后台线程上的该纹理上,并且不会阻塞主线程。

Option 2
另一个选项不受 Apple 官方支持,可能适合您,也可能不适合您:

  • 不要覆盖canDrawInContext:...,默认实现总是返回YES这就是你想要的。
  • 覆盖drawInContext:...执行实际的 OpenGL 渲染,全部。
  • 不要使该层异步。
  • 不设置needsDisplayOnBoundsChange.

每当你想重绘该层时,调用display直接地 (NOT setNeedsDisplay!确实如此,苹果说你不应该调用它,但“不应该”不是“不能”)并且调用后display, call [CATransaction flush]。即使从后台线程调用,这也会起作用!你的drawInContext:...方法是从调用的同一线程调用的display它可以是任何线程。呼唤display直接将确保您的 OpenGL 渲染代码执行,但新渲染的内容仍然仅在图层的后备存储中可见,要将其带到屏幕上,您必须强制系统执行图层合成并[CATransaction flush]就会这么做。 CATransaction 类只有类方法(您永远不会创建它的实例),它是隐式线程安全的,并且可以随时从任何线程使用(无论何时何地需要,它都会自行执行锁定)。

虽然不推荐这种方法,因为它可能会导致其他视图的重绘问题(因为这些视图也可能在主线程以外的线程上重绘,并且并非所有视图都支持),但它是也不禁止,它不使用私有 API,并且已在 Apple 邮件列表中建议,Apple 中没有任何人反对。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅当调整窗口大小时,图层支持的 OpenGLView 才会重绘 的相关文章

  • 仅当调整窗口大小时,图层支持的 OpenGLView 才会重绘

    我有一个带有类型主视图的窗口NSView和一个子视图 它是NSOpenGLView谁的名字是CustomOpenGLView 的子类NSOpenGLView是通过一个获得Custom View在 Interface Builder 中并将其
  • 使用 CALayer 委托

    我有一个 UIView 其图层将有子图层 我想为每个子图层分配委托 因此委托方法可以告诉图层要绘制什么 我的问题是 作为 CALayer 的代表我应该提供什么 文档说不要使用图层所在的 UIView 因为这是为视图的主 CALayer 保留
  • 白色背景上带有透明标题的 iOS UIButton

    我有一个习惯UIButton具有透明背景和白色标题 我正在寻找一个简单的解决方案来反转它的突出显示 白色背景和透明标题 因为它是在系统上实现的UISegmentedControl 有没有比反转用作快照的 alpha 更简单的解决方案CALa
  • 可拖动的CALayer

    有什么方法可以让用户拖动 CALayer 吗 如果是这样 怎么办 在可可 Mac 中 图层本身无法接收鼠标事件 您必须在包含该层的视图或视图控制器中进行事件处理 If a mouseDragged 事件起源于某个层 请参见 CALayer
  • 来自一维像素阵列的 NSImage?

    我的程序中有一个大型一维动态数组 它表示磁盘上的 FITS 图像 即它保存图像的所有像素值 数组的类型是double 目前 我只关心单色图像 由于 Cocoa 不直接支持 FITS 格式 因此我使用 CFITSIO 库读取图像 这是可行的
  • 在 UIImageView 之上绘图以使图像透明

    我正在开发一个 iPhone 应用程序 其中当用户在图像上移动手指时 我需要通过将其 alpha 级别设置为 0 来使图像的一部分透明 基本上 如果您碰巧知道应用程序商店应用程序 iSteam 用户应该能够在顶部图像上移动手指 这将使背景图
  • 动画 CALayer 隐藏

    我试图隐藏一个CALayer几微秒后我正在使用CABasicAnimation为隐藏设置动画 目前我正在尝试使用 aLayer setHidden YES CABasicAnimation hideAnimation CABasicAnim
  • UIView动画VS核心动画

    我正在尝试制作一个视图的动画 该视图滑入视图并在到达屏幕侧面后弹跳 我正在做的幻灯片的基本示例如下 The view is added with a rect making it off screen UIView beginAnimati
  • 无法捕获视图层内的蒙版

    因此 我使用以下代码将图像蒙版应用到 UIView 层 CALayer maskLayer CALayer layer UIImage maskImage self image image maskLayer contents id mas
  • 在 iOS 上使用可调整大小的图像时避免混合图层

    我试图避免 iOS 上的混合层以提高性能 但是 我注意到我使用的可调整大小的图像backgroundView of my UITableViewCell被标记为混合层 事实上 使用任何可调整大小的图像 即使是没有透明度的 JPEG 都会导致
  • 基于路径的遮罩具有良好的抗锯齿功能

    我想用圆圈掩盖一个正方形 我使用它而不是圆角半径 因为我想稍后对动画进行处理 我可以将其遮盖 但边缘非常粗糙 Target View let targetView UIView frame CGRect x 0 y 0 width 100
  • 是否可以在drawInContext调用之间保留CALayer的内容?

    是否有任何内置功能可以在 drawLayer inContext 调用之间维护 CALayer 的内容 现在 我将图层复制到缓冲区 并在每次调用drawLayer inContext 时从缓冲区重新绘制图像 但我想知道 CALayer 是否
  • 如何使用扩展功能保存分层图像

    我正在使用扩展函数将 uiview 保存为 uiimage 该代码用于保存 uiimage 然而 我想做的是在保存到照片库的图像上保存透明图像 所以我尝试使用扩展函数保存分层图像 现在只有 uiivew 被保存 第二层没有被保存 class
  • 如何在 NSImageView 中实现 NSImage 的连续旋转?

    未来的观众 我已经成功完成了这个旋转动画 并且可以在问题上找到带有描述的代码 NSView 中的 NSImage 旋转不起作用 https stackoverflow com questions 10836131 nsimage rotat
  • SpriteKit SKScene 添加 AVCaptureVideoPreviewLayer CALayer 作为背景不起作用

    我正在尝试将 AVCaptureVideoPreviewLayer CALayer 添加为 SKScene 的背景 我可以将 CALayer 添加到场景中 但无论尝试如何排序 CALayer 始终是最顶层的对象 在 didMoveToVie
  • 基于视图的 NSTableView 在插入带有动画的新行后渲染空白行

    我有一个基于视图的NSTableView我用 NSMutableArray 来支持 我定期出去获取一些数据 并希望将新行插入到顶部的表中 当我在没有指定动画的情况下执行此操作时insertRowsAtIndexes withAnimatio
  • 观察 CALayer 中的动画属性变化

    我有一个CABasicAnimation动画 a 的属性CALayer e g bounds origin 我希望能够观察属性随时间的变化 但还没有真正找到一种 100 有效的方法 我尝试使用 KVO 键值观察 presentationLa
  • 如何将不同层的核心动画一个接一个地链接起来?

    我有一个启用分页的scrollView和N个页面 它们是作为scrollView的子视图的UIView 我正在尝试执行以下操作 用户滚动到第 n 页 此时 之前添加到第 n 页的 7 个 CALayers 即 到页面 scrollView
  • IE10重画/重画问题

    你可以在这里看到这个工作 中断 http new campchampions com parents http new campchampions com parents 该问题仅在 IE10 中出现 用户滚动一小段距离后 导航就会被固定
  • 自定义 CALayer - 无效上下文 0x0

    我正在尝试构建一个使用图层的应用程序 我的应用程序结构是 UIView gt UIScrollView gt UIView gt LayersView Custom UIView gt UIImageView 我想向 LayersView

随机推荐