【问题标题】:CARenderer never produces outputCARenderer 从不产生输出
【发布时间】:2010-08-07 09:36:43
【问题描述】:

我被困了好几个小时,试图使用 CARenderer 将 Core Animation 层树渲染到 OpenGL 上下文中。 OpenGL 上下文当前由 Interface Builder 中设置的 NSOpenGLView 子类提供,默认设置。

这是我在示例中设置 CALayers 的方式:

l1 = [[CALayer layer] retain];        // l1 is an instance variable
l1.bounds = CGRectMake(0, 0, 100, 100);
l1.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1);
CALayer* l2 = [CALayer layer];
l2.bounds = CGRectMake(0, 0, 20, 20);
l2.backgroundColor = CGColorCreateGenericRGB(1, 0, 0, 1);
l2.position = CGPointMake(50, 50);
[l1 addSublayer:l2];

如果我将这些添加到常规的 NSView 中,它们会显示得很好。

这是来自我的 NSOpenGLView 子类的绘图代码:

- (void) drawRect:(NSRect)dirtyRect
{
    NSRect frame = [self frame];

    // set up context according to CARenderer.h instructions
    glViewport(0, 0, frame.size.width, frame.size.height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, frame.size.width, 0, frame.size.height, -1, 1);

    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    if (l1)
    {
        CARenderer* renderer = [CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil];
        renderer.layer = l1;
        renderer.bounds = NSRectToCGRect(frame);
        [renderer beginFrameAtTime:0.0 timeStamp:NULL];
        [renderer addUpdateRect:renderer.bounds];
        [renderer render];
        [renderer endFrame];
    }

    glFlush();
}

我确认视图在创建图层后重绘,并且视图本身似乎工作正常——我发出的 OpenGL 命令正确显示。 CARenderer 确实活跃了(事实上,如果 l1 在此代码运行时已经附加到另一个上下文,它会尽职尽责地抱怨)。永远没有可见的输出。

我尝试过的其他事情:将 CARenderer 代码包装在 CATransaction 中,在 Interface Builder 中摆弄 NSOpenGLView 设置选项,将整个事件渲染到屏幕外手动创建的 OpenGL 上下文中,并将其保存到图像文件中……所有达到同样的效果:原生 OpenGL 命令显示正常,CARenderer 不显示任何内容。

我怀疑我的 OpenGL 上下文设置方式有问题,或者我什至可能以某种方式在我的视口之外进行渲染......可能是一些非常愚蠢的小细节。不幸的是,网络上 CARenderer 的文档和示例代码都比较稀少,虽然我对 Core Animation 有相当的经验,但我的 OpenGL 知识显然有限。

所以现在,我真的很困惑,完全没有想法,所以非常感谢任何指针!

干杯

【问题讨论】:

    标签: cocoa macos opengl core-animation


    【解决方案1】:

    哇哦。因此,如果有人感兴趣,我同时得到了这个“大部分工作”。以下是相关代码:

    - (void) drawRect:(NSRect)dirtyRect
    {
        NSRect viewBounds = [self bounds];
    
        // set up context according to CARenderer.h instructions
        glViewport(0, 0, viewBounds.size.width, viewBounds.size.height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, viewBounds.size.width, 0, viewBounds.size.height, -1, 1);
    
        glClearColor(0, 0, 0, 0);
        glClear(GL_COLOR_BUFFER_BIT);
    
        [renderer beginFrameAtTime:0.0 timeStamp:NULL];
        [renderer addUpdateRect:renderer.bounds];
        [renderer render];
        [renderer endFrame];
    
        glFlush();
    }
    
    - (void) prepareOpenGL
    {
        renderer = [[CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil] retain];
    
        [CATransaction begin];
        CALayer* l = [CALayer layer];
        l.bounds = CGRectMake(0, 0, 100, 100);
        l.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1);
    
        renderer.layer = l;
        renderer.bounds = l.bounds;
        [CATransaction commit];
    }
    

    注意层/渲染器创建代码周围的CATransaction 块。没有这个,该层要么根本不显示(就像我最初的问题一样),要么只在稍有延迟后才呈现,即,当视图在一段时间后重新绘制时。至于为什么这是必要的,我仍然不确定,如果有人能在这一点上启发我,我会非常高兴。

    显然,这个解决方案可能仍然存在某种错误,但考虑到CARenderer 缺少示例代码,我决定暂时将其留在这里。

    编辑:正如我后来发现的那样,上述解决方案的一个相当不明显的错误是0.0 被传递给beginFrameAtTime 方法调用;相反,这应该是来自CACurrentMediaTime 的值。这将消除对CATransaction 块的需求,并在此过程中纠正一些其他错误。就像任何可能偶然发现此答案的人的提醒一样。

    【讨论】:

    • 感谢您发布此信息。遵循 prepareOpenGL 方法似乎有助于让 CALayer 拥有一个非零表示层而不实际显示(我试图与 CAKeyFrameanimation 一起使用来粗略地计算沿 CGPath 的点)
    猜你喜欢
    • 2012-01-07
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多