Colors iOS 5+GLKView:如何访问基于颜色的顶点拾取的像素RGB数据?

Colors iOS 5+GLKView:如何访问基于颜色的顶点拾取的像素RGB数据?,colors,ios5,opengl-es-2.0,pixel,picking,Colors,Ios5,Opengl Es 2.0,Pixel,Picking,我一直在转换我自己的个人OGLES 2.0框架,以利用新的iOS 5框架GLKit添加的功能 在获得令人满意的结果之后,我现在希望实现所描述的基于颜色的拾取机制。为此,必须访问后缓冲区以检索触摸像素RGBA值,然后将其用作顶点/基本体/显示对象的唯一标识符。当然,这需要所有顶点/基本体/显示对象的临时唯一着色 我有两个问题,非常感谢您的帮助: 我可以访问GLKViewController、GLKView、GLKView的CAEAGLLayer和EAGLContext。我还可以访问所有OGLES2

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

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

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

我可以访问GLKViewController、GLKView、GLKView的CAEAGLLayer和EAGLContext。我还可以访问所有OGLES2.0 与缓冲区相关的命令。我如何结合这些来识别颜色 我在屏幕上点击的EagleContext中的一个像素

鉴于我使用顶点缓冲区对象进行渲染,是否有一种巧妙的方法覆盖提供给顶点着色器的颜色 首先不涉及修改缓冲顶点颜色 属性,其次不涉及添加IF 语句导入顶点着色器

我认为2的答案是否定的,但出于性能和不费力的代码修改的原因,我认为与更有经验的人核实是明智的

如有任何建议,我们将不胜感激。谢谢你抽出时间

更新

现在我知道了如何使用从活动帧缓冲区读取像素数据。所以我想我只需要做特殊的独特颜色渲染到后缓冲区,简单切换到它并读取像素,然后切换回。这将不可避免地产生视觉闪烁,但我想这是最简单的方法;当然,比从屏幕快照创建CGImageContextRef并以这种方式进行分析更快、更合理


不过,任何关于后缓冲区的提示都将不胜感激。

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

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

为手势识别器设置目标动作;您可以在使用特定初始化创建它时执行此操作。。。然而,我在Xcode 4.2中使用Storyboard又名新的接口生成器创建了我的脚本,并以这种方式连接起来

无论如何,以下是我对轻拍手势识别器的目标操作:

-(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];
}
这利用了苹果公司在GLKView中提供的一个方便的新方法快照,从底层的EagleContext生成UIImage

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

当应用程序显式运行时,应调用此方法 需要视图的内容;切勿试图直接阅读 使用OpenGL ES函数的底层帧缓冲区的内容

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

您会注意到,在刚才定义的pickAtX:Y:方法中,我在UIImage上调用了pickPixelAtX:Y:。这是我在自定义类别中添加到UIImage的方法:

@interface UIImage (NDBExtensions)
-(void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y;
@end
以下是实施情况;这是所需的最终代码清单。该准则来自并根据收到的答复进行了修订:

@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
当然,您应该编写一些方法来提取那些将在0-255范围内的RGBA int值,并根据需要使用它们。一种方法是从上述方法返回UIColor,如下所示:

UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];

我已经完成了整个采摘机制,现在它的工作待遇:呼!选择的答案效果很好,除了它似乎还揭示了苹果GLKView快照方法中的一个重大缺陷,在我的例子中,它会导致大内存分配峰值并导致崩溃。。。如果其他人遇到过这个问题,请参阅我关于这个主题的帖子。
@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
R:24 G:46 B:244 A:255
UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];