opengl iOS glkit颜色选择

时间:2013-09-28 18:52:37

标签: ios opengl-es glkit picking ray-picking

它是关于使用颜色选择选择一个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
    }
}

2 个答案:

答案 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。