OpenGL 2.0 – 如何交换颜色select的缓冲区

我试图在iOS上重现颜色采摘,遵循这里描述的技术: http : //www.lighthouse3d.com/opengl/picking/index.php3?openglway2 ,使用OpenGL ES 2.0。

当用户触摸屏幕时,我需要绘制与屏幕上显示的缓冲区不同的缓冲区,这似乎是由glRenderMode(GL_SELECT)完成的; 我怎么能做到这一点与OpenGL ES 2.0?

我应该如下所述创建一个支持缓冲区吗? https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW6

感谢您的任何建议,

是的,你可以这样做。 这是我如何在iOS中进行颜色select,它的工作真的很棒。 另外,我已经使用apportable将我的代码移植到android,并且颜色select器也在其他设备上工作。

  1. 创建一个临时或临时framebuffer。 我创建一个特定的颜色select框架缓冲区。 这就像创建一个dynamic纹理。 它以相同的方式完成。 我select一个正方形大小适合整个屏幕的缓冲区大小。 你不必这样做,但是我就是这么做的。 或者,你可以做一半的大小和select器样本分辨率可能是足够好的。 你必须为你的应用程序玩。 如果你需要代码让我知道。
  2. 如果需要,可以附加深度缓冲区。 我只有当我select的3d对象需要它。
  3. 每个你想要挑选的项目都需要一个独特的颜色:

    -(vec4) colorVec4FromItemID: (int)itemID { if (itemID<0) { return vec4Make(0.0, 0.0, 0.0, 1.0); } float r = itemID % 255; float g = (itemID / 255) % 255; float b = (itemID / (255 * 255)) % 255; return vec4Make(r/255, g/255, b/255, 1.0); } 
  4. 我跟踪项目之一的两种方式。 要么我有我的对象在一个结构数组和我传递给上述方法的itemID是该数组的索引号。 或者我保持一个colorPickerID和++每当我抓住一个颜色。 无论哪种方式,我将颜色存储在结构数组中的vec4 pickerColor中。 我避免了颜色拾取的objective-c ns-stuff,并使用ac数组结构。 在我的游戏中,我也将我的inputID乘以30来给出颜色之间的空间 – 但这可能不是必需的。

  5. 使用纯色着色器渲染。 所以我需要时将场景中的可选对象重新添加到颜色select器帧缓冲区/纹理(不是每个帧)。 我已经尽可能地融合了自己的优势。 你不想插入颜色。 我使用这样的着色器:

      void main(void) { gl_FragColor = u_baseColor; } 
  6. 这也意味着我保持着色器和支持代码非常兼容。 我可以从纹理着色器转换为纯色着色器,而无需重做一堆代码。 然后你可以重复使用相同的绘制例程。 而当绘制颜色select器通过我也使用完全相同的matrix。 如果你caching它们,你不必重新计算它们。

  7. 当用户触摸时,我设置processColorPicker=TRUE 。 在绘制我的场景之后,在我的drawView循环中检查该bool,然后(如果场景已经改变),我绘制颜色select器并处理它。 显然,不要在每一帧画出select器。

  8. 读取像素:

     -(void)processColorPicker { //if (colorPickerNeedsRedrawn) { [self drawColorPicker]; //} glBindFramebuffer(GL_FRAMEBUFFER, pickerFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureInfo[TEX_PICKER].texture, 0); Byte pixelColor[4] = {0,0,0,0}; glReadPixels(colorPickerTouchPosition.x * backingScale, (backingHeight - (colorPickerTouchPosition.y * backingScale)), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelColor); vec4 pickerColor = vec4Make((float)pixelColor[0]/255, (float)pixelColor[1]/255, (float)pixelColor[2]/255, (float)pixelColor[3]/255); NSLog(@"what is pixelColor at %f,%f = %f %f %f %f", colorPickerTouchPosition.x, colorPickerTouchPosition.y, pickerColor.r,pickerColor.g,pickerColor.b,pickerColor.a); ... 
  9. 解读阅读。 您可以查看颜色是否与存储在结构中的选取器颜色相匹配,或者您可以使用colorVecFromItemID再次检查每个项目编号。

一些提示:如果你只保持读取0,0,0,0 ,它不工作的机会是你的缓冲区设置错误,或者你真的没有绘制到该缓冲区。 你总是可以将纹理绘制到屏幕上,而不是处理颜色。然后你可以看到颜色是否正确绘制。 他们会变得黑暗和微红。

另外,由于您不是从屏幕上读取数据,而是从临时缓冲区读取数据,因此不必担心kEAGLDrawablePropertyRetainedBacking 。 这只是如果你正在从屏幕缓冲区读取像素。 此外,我不确定布拉德·拉尔森的替代glRead将为此工作,因为我相信只能从屏幕上阅读。

如果你想加快速度的话,把颜色select器纹理的大小除以2或4.这个缓冲区在理论上将在/ 2处快4倍,在4处快4倍。 机会是你不需要一个视网膜像素准确的颜色select缓冲区。

确保在绘制到主屏幕缓冲区时,不会开始绘制到选取器缓冲区(或任何dynamic纹理)。 我这样做的方式是不直接跳转到processColorPicker ,而是设置一个布尔,然后在主缓冲区出现后在我的drawView循环中执行。

*更新**

这是我的颜色select器缓冲区代码。 请注意,我将所有纹理的信息保存在一个textureInfo数组中,包括是否已经生成,大小等。

 -(BOOL)createPickerFramebuffer { glGenFramebuffers(1, &pickerFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, pickerFramebuffer); glGenTextures(1, &textureInfo[TEX_PICKER].texture); textureInfo[TEX_PICKER].generated = YES; glBindTexture(GL_TEXTURE_2D, textureInfo[TEX_PICKER].texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); textureInfo[TEX_PICKER].width = backingWidth; textureInfo[TEX_PICKER].height = backingHeight; // bind renderbuffer and create a 16-bit depth buffer // width and height of renderbuffer = width and height of // the texture glGenRenderbuffers(1, &pickerDepthRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, pickerDepthRenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, backingWidth, backingHeight); // bind the framebuffer // specify texture as color attachment glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureInfo[TEX_PICKER].texture, 0); // specify depth_renderbufer as depth attachment - only if you need it glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, pickerDepthRenderbuffer); // test the framebuffer GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) { NSLog(@"***************************failed to make complete picker buffer object %x", status); return NO; } //else { // NSLog(@"*************************** MADE complete picker buffer object %x", status); //} glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); return YES; } 

下面是你如何开始绘制它:

 -(void) startDrawingPickerTexture { // set the framebuffer to the textureFramebuffer glBindFramebuffer(GL_FRAMEBUFFER, pickerFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureInfo[TEX_PICKER].texture, 0); // reset the viewport just in case glViewport(0, 0, backingWidth, backingHeight); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); // and GL_DEPTH_BUFFER_BIT if necessary glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); // And now it's ready and you can start rendering to it.... } 

答案是肯定的

创建一个临时的framebuffer是解决scheme,苹果的文档就好了。