它是关于使用拾色来挑选3D对象。我将网格(更新:驻留在静态头文件中,在同一项目中很好地显示在屏幕上(绘制到一个新的屏幕外帧缓冲区,然后使用 glReadPixel 来识别用户是否触摸了它。
按照Erik M.Buck的"Learning OpenGLES for iOS"一书中的项目opengles_ch10_1代码,我编写了以下代码,该代码始终打印为所选择(通过点击(像素的颜色0,0,0。
我的代码是:
- (IBAction) tapGesture:(id)sender
{
if ([(UITapGestureRecognizer *)sender state] == UIGestureRecognizerStateEnded) {
CGPoint tapLocation = [(UITapGestureRecognizer *)sender locationInView:self.view];
int tt = [self findMeshByPoint:tapLocation];
//NSLog( @"tap value: %i", tt );
}
}
- (NSUInteger)findMeshByPoint:(CGPoint)point
{
//In openGL the y axis starts from the bottom of the screen
point.y = self.view.bounds.size.height - point.y;
GLKView *glView = (GLKView *)self.view;
NSAssert([glView isKindOfClass:[GLKView class]],
@"View controller's view is not a GLKView");
// Make the view's context current
[EAGLContext setCurrentContext:glView.context];
glBindVertexArrayOES(0);
// self.effect.constantColor = GLKVector4Make( 1.0f, //This should be meshId/255.0f
if(0 == _glVertexAttributeBufferID)
{
GLuint glName;
glGenBuffers(1, // STEP 1
&glName);
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
glName);
glBufferData( // STEP 3
GL_ARRAY_BUFFER, // Initialize buffer contents
sizeof(parparit51OBJVertices), parparit51OBJVertices,
GL_STATIC_DRAW); // Hint: cache in GPU memory
_glVertexAttributeBufferID = glName;
}
else
{
glBindBuffer(GL_ARRAY_BUFFER,
_glVertexAttributeBufferID);
}
//glEnableVertexAttribArray(TETerrainPositionAttrib);
glEnableVertexAttribArray( GLKVertexAttribPosition );
if(0 == _program)
{
[self loadShadersWithName:@"UtilityPickTerrainShader"];
[self buildFBO];
NSAssert(0 != _program,
@"prepareOpenGL failed to load shaders");
}
glUseProgram(_program);
// Pre-calculate the mvpMatrix
GLKMatrix4 modelViewProjectionMatrix2 =
GLKMatrix4Multiply(
self.effect.transform.projectionMatrix,
self.effect.transform.modelviewMatrix);
// Standard matrices
glUniformMatrix4fv(uniforms[UtilityPickTerrainMVPMatrix], 1, 0,
modelViewProjectionMatrix2.m);
// glUniform2fv(uniforms[UtilityPickTerrainDimensionFactors], 1,
// &_temp1 ); //self.factors.v); //I removed this from the shaders
glUniform1f(uniforms[UtilityPickTerrainModelIndex],
1.0f ); // self.modelIndex / 255.0f);
glBindFramebuffer(GL_FRAMEBUFFER, _pickFBO);
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(GLfloat), 0);
NSLog( @"******* 7" );
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, sizeof(parparit51OBJVertices) / sizeof(Vertex));
NSLog( @"******* 7.5" );
const GLfloat width = [glView drawableWidth];
const GLfloat height = [glView drawableHeight];
NSAssert(0 < width && 0 < height, @"Invalid drawble size");
// Get info for picked location
const GLKVector2 scaledProjectionPosition = {
point.x / width,
point.y / height
};
NSLog( @"******* 8" );
GLubyte pixelColor[4]; // Red, Green, Blue, Alpha color
GLint readLocationX = MIN((512 - 1),
(512 - 1) * scaledProjectionPosition.x);
GLint readLocationY = MIN((512 - 1),
(512 - 1) * scaledProjectionPosition.y);
glReadPixels(readLocationX,
readLocationY,
1,
1,
GL_RGBA,
GL_UNSIGNED_BYTE,
pixelColor);
NSLog(@"pixelColor[0]=%i, pixelColor[1]=%i, pixelColor[2]=%i", pixelColor[0], pixelColor[1], pixelColor[2] );
// Restore OpenGL state that pickTerrainEffect changed
glBindFramebuffer(GL_FRAMEBUFFER, 0); // default frame buffer
glViewport(0, 0, width, height); // full area of glView
return 0;
}
-(void) buildFBO
{
if ( 0 == _pickFBO )
{
GLuint colorTexture;
// Create a texture object to apply to model
glGenTextures(1, &colorTexture);
glBindTexture(GL_TEXTURE_2D, colorTexture);
// Set up filter and wrap modes for this texture object
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
// Allocate a texture image we can render into
// Pass NULL for the data parameter since we don't need to
// load image data. We will be generating the image by
// rendering to this texture.
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
512,
512,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
512, 512);
glGenFramebuffers(1, &_pickFBO);
glBindFramebuffer(GL_FRAMEBUFFER, _pickFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
GL_FRAMEBUFFER_COMPLETE)
{
NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
//+++tbd+++UtilityPickTerrainEffectDestroyFBO(fboName);
return;
}
//#ifdef DEBUG
// { // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: 0x%x", error);
}
// }
//#endif
}
}
你的错误是你试图访问一个空指针——你几乎可以肯定是将一个你从未实际初始化过的数组传递给你的 GLKEffect 或者通过 bufferData 调用将其提供给 OpenGL,因为错误发生在 prepareToDraw 或 glDrawArray 内部。我可以看到有几种可能的解释,尽管我无法确认其中任何一个,因为相关信息是你如何分配你在perpareToDraw或glDrawArrays中使用的数据。
首先是"parparit51OBJVertices"可能会在堆上动态分配(您是调用malloc还是类似的东西?您如何指定数组的大小(,在这种情况下,您对 sizeof 的调用将返回不正确的值(我认为为 0(,这可能会导致EXEC_BAD_ACESS。
另一部分似乎可疑的是,您正在调用glDrawArrays并传入顶点数,但在此之前,您为索引绑定了VBO - 这充其量是浪费工作,因为glDrawArrays将忽略索引。更糟糕的是,如果您尝试绘制 OBJ,正如您的变量名称所暗示的那样,那么很可能您根本没有绘制大量几何图形,因此即使您解决了EXEC_BAD_ACCESS问题,您仍然会得到不好的结果。
我有一个BAD_ACCESS错误。我通过删除处理索引的代码来解决此问题:
if(0 == _indexBufferID)
{
// Indices haven't been sent to GPU yet
// Create an element array buffer for mesh indices
glGenBuffers(1, &_indexBufferID);
NSAssert(0 != _indexBufferID,
@"Failed to generate element array buffer");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof( parparit51OBJIndices ),
parparit51OBJIndices,
GL_STATIC_DRAW);
}
else
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferID);
}
现在我仍然需要了解为什么上面更新的代码总是为任何选择的像素打印 0,0,0。