它是关于使用颜色选择选择一个3d对象。我绘制我的网格(更新:它位于静态头文件中并在同一项目中显示在屏幕上)到新的屏幕外帧缓冲区然后我使用glReadPixels来识别用户是否触摸它。
根据Erik M.Buck出版的“学习OpenGLES for iOS”一书中的项目opengles_ch10_1中的代码,我编写了以下代码,该代码总是向nslog打印所选(通过点击)像素的颜色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
}
}
答案 0 :(得分:0)
您的错误是您正在尝试访问Null指针 - 您几乎肯定会传递一个您从未实际初始化为GLKEffect的数组,或者通过bufferData调用将其传递给OpenGL,因为错误发生在prepareToDraw或glDrawArrays。我可以看到有几种可能的解释,但我无法确认其中任何一种,因为相关信息是如何在perpareToDraw或glDrawArrays中分配您正在使用的数据。
第一个是“parparit51OBJVertices”可能是动态分配在堆上的(你是在调用malloc之类的吗?你如何指定数组的大小),在这种情况下你对sizeof的调用将返回不正确的值( 0我认为)可能导致EXEC_BAD_ACESS。
这个看起来很可疑的另一部分是你正在调用glDrawArrays并传入顶点的数量,但在此之前你绑定一个VBO用于索引 - 充其量这是浪费的工作,因为glDrawArrays将忽略索引。更糟糕的是,如果你试图绘制一个OBJ,就像你的变量名所暗示的那样,那么你可能根本没有绘制相当数量的几何体,所以即使你修复了EXEC_BAD_ACCESS问题,你仍然会得到不好的结果。
答案 1 :(得分:0)
我遇到了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。