我一直在转换我自己的个人 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/