我一直在转换我自己的个人 OGLES 2.0 框架,以利用新的 iOS 5 框架 GLKit 添加的功能。

在获得令人满意的结果后,我现在希望实现 here 描述的基于颜色的挑选机制。为此,您必须访问后台缓冲区以检索触摸像素 RGBA 值,然后将其用作顶点/图元/显示对象的唯一标识符。当然,这需要对所有顶点/基本体/显示对象进行临时唯一着色。

我有两个问题,我将非常感谢您的帮助:



我假设 (2) 的答案是“否”,但出于性能和非艰巨的代码修改的原因,我认为与更有经验的人核对是明智的。

任何建议将不胜感激。感谢您的时间

更新

好吧,我现在知道如何使用 glReadPixels 从事件帧缓冲区读取像素数据。所以我想我只需要对后台缓冲区进行特殊的“独特颜色”渲染,短暂切换到它并读取像素,然后切换回来。这将不可避免地产生视觉闪烁,但我想这是最简单的方法;肯定比从屏幕快照创建 CGImageContextRef 并以这种方式分析更快(也更明智)。

尽管如此,关于后台缓冲区的任何提示都将不胜感激。

最佳答案

好吧,我已经尽可能简洁地确定了如何做到这一点。下面我将解释如何实现这一点并列出所需的所有代码:)

为了允许触摸交互来选择像素,首先将 UITapGestureRecognizer 添加到您的 GLKViewController 子类(假设您想要点击选择像素),在该类中使用以下目标方法。您必须将 GLKViewController 子类设为 UIGestureRecognizerDelegate :

@interface GLViewController : GLKViewController <GLKViewDelegate, UIGestureRecognizerDelegate>

实例化手势识别器后,将其添加到 view 属性(在 GLKViewController 中实际上是一个 GLKView ):
// Inside GLKViewController subclass init/awakeFromNib:
[[self view] addGestureRecognizer:[self tapRecognizer]];
[[self tapRecognizer] setDelegate:self];

为您的手势识别器设置目标操作;您可以在使用特定的 init... 创建它时执行此操作,但是我使用 Storyboard(又名“Xcode 4.2 中的新界面构建器”)创建了我的并以这种方式连接。

无论如何,这是我的点击手势识别器的目标操作:
-(IBAction)onTapGesture:(UIGestureRecognizer*)recognizer {
    const CGPoint loc = [recognizer locationInView:[self view]];
    [self pickAtX:loc.x Y:loc.y];
}

其中调用的 pick 方法是我在 GLKViewController 子类中定义的方法:
-(void)pickAtX:(GLuint)x Y:(GLuint)y {
    GLKView *glkView = (GLKView*)[self view];
    UIImage *snapshot = [glkView snapshot];
    [snapshot pickPixelAtX:x Y:y];
}

这利用了 Apple 善意包含在 snapshot 中的一个方便的新方法 GLKView 从底层 UIImage 生成 EAGLContext

需要注意的是 snapshot API 文档中的一条注释,其中指出:



这给了我一个线索,说明为什么我之前尝试调用 glReadPixels 以尝试访问像素数据会生成 EXC_BAD_ACCESS ,而指示器却让我走上了正确的道路。

您会注意到,在我刚才定义的 pickAtX:Y: 方法中,我在 pickPixelAtX:Y: 上调用了 UIImage 。这是我在自定义类别中添加到 UIImage 的方法:
@interface UIImage (NDBExtensions)
-(void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y;
@end

这是实现;这是所需的最终代码 list 。代码来自 this question 并根据那里收到的答案进行了修改:
@implementation UIImage (NDBExtensions)

- (void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y {

    CGImageRef cgImage = [self CGImage];
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);

    if ((x < width) && (y < height))
    {
        CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
        CFDataRef bitmapData = CGDataProviderCopyData(provider);
        const UInt8* data = CFDataGetBytePtr(bitmapData);
        size_t offset = ((width * y) + x) * 4;
        UInt8 b = data[offset+0];
        UInt8 g = data[offset+1];
        UInt8 r = data[offset+2];
        UInt8 a = data[offset+3];
        CFRelease(bitmapData);
        NSLog(@"R:%i G:%i B:%i A:%i",r,g,b,a);
    }
}

@end

我最初尝试了在 Apple API 文档中找到的一些相关代码,标题为:“从 CGImage 上下文中获取像素数据”,它需要 2 个方法定义而不是这个 1,但是需要更多的代码,并且有 void * 类型的数据我无法执行正确的解释。

就是这样!将此代码添加到您的项目中,然后点击像素后,它将以以下形式输出:
R:24 G:46 B:244 A:255

当然,您应该编写一些方法来提取那些 RGBA int 值(范围为 0 - 255)并根据需要使用它们。一种方法是从上述方法返回一个 UIColor,实例化如下:
UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];

关于colors - iOS 5 + GLKView : How to access pixel RGB data for colour-based vertex picking?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7861316/

10-12 06:00