我一直在转换自己的个人OGLES 2.0框架,以利用新的iOS 5框架GLKit
添加的功能。
在取悦结果之后,我现在希望实现here所述的基于颜色的拣选机制。为此,您必须访问后台缓冲区以检索触摸的像素RGBA值,然后将其用作顶点/基元/显示对象的唯一标识符。当然,这需要对所有顶点/基元/显示对象进行临时唯一着色。
我有两个问题,我非常感谢你们的帮助:
我可以访问
GLKViewController
,GLKView
,CAEAGLLayer
(GLKView
)和EAGLContext
。我也可以访问所有OGLES 2.0 缓冲相关命令。如何组合这些以识别颜色 我正在点击屏幕上的EAGLContext中的一个像素?- 醇>
鉴于我正在使用顶点缓冲区对象进行渲染,是否有一种巧妙的方法来覆盖提供给我的顶点着色器的颜色 首先不涉及修改缓冲顶点(颜色) 属性,其次不涉及添加IF 声明到顶点着色器?
我认为(2)的答案是“不”,但出于性能和非艰苦的代码改造的原因,我认为与更有经验的人核实是明智的。
任何建议都会感激不尽。谢谢你的时间
更新
我现在知道如何使用glReadPixels从活动帧缓冲区读取像素数据。所以我想我只需要对后台缓冲区进行特殊的“独特颜色”渲染,短暂切换到它并读取像素,然后切换回来。这将不可避免地产生视觉闪烁,但我想这是最简单的方法;肯定比从屏幕快照创建CGImageContextRef
并分析这种方式更快(也更明智)。
但是,关于后台缓冲区的任何提示都会非常感激。
答案 0 :(得分:12)
好吧,我已尽可能简明扼要地研究如何做到这一点。下面我将解释如何实现这一点并列出所需的所有代码:)
为了允许触摸交互选择像素,首先向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...
设置手势识别器的目标操作;你可以在使用特定的-(IBAction)onTapGesture:(UIGestureRecognizer*)recognizer {
const CGPoint loc = [recognizer locationInView:[self view]];
[self pickAtX:loc.x Y:loc.y];
}
创建它时执行此操作,但是我使用Storyboard(也称为“Xcode 4.2中的新界面生成器”)创建了它并以这种方式连接它。
无论如何,这是我的轻拍手势识别器的目标动作:
GLKViewController
我在-(void)pickAtX:(GLuint)x Y:(GLuint)y {
GLKView *glkView = (GLKView*)[self view];
UIImage *snapshot = [glkView snapshot];
[snapshot pickPixelAtX:x Y:y];
}
子类中定义了一个我在其中定义的pick方法:
snapshot
这利用了一个方便的新方法GLKView
,Apple在UIImage
中包含了EAGLContext
来从基础snapshot
生成glReadPixels
。
需要注意的是EXC_BAD_ACCESS
API文档中的注释,其中声明:
应该在您的应用程序明确调用时调用此方法 需要视图的内容;永远不要试图直接阅读 使用OpenGL ES函数的底层帧缓冲区的内容。
这让我得到了一个线索,为什么我之前尝试调用pickAtX:Y:
尝试访问像素数据时尝试生成pickPixelAtX:Y:
,以及指示我将其发送到正确的路径。
你会注意到我刚才定义的UIImage
方法,我在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
的方法:
void *
这是实施;这是所需的最终代码清单。代码来自this question,并根据收到的答案进行了修改:
R:24 G:46 B:244 A:255
我最初尝试在Apple API文档中找到的一些相关代码,标题为:“从CGImage上下文中获取像素数据”,这需要2个方法定义而不是1,但需要更多代码,并且数据类型为{ {1}}我无法实现正确的解释。
就是这样!将此代码添加到项目中,然后在点击像素时,它将以以下形式输出:
UIColor
当然,您应该编写一些方法来提取这些RGBA int值(将在0 - 255范围内)并根据需要使用它们。一种方法是从上面的方法返回UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
,实例化如下:
{{1}}