OpenGL iOS GlKIT выбор цвета

Речь идет о выборе 3D-объекта с помощью выбора цвета. Я рисую свою сетку (обновление: которая находится в статическом заголовочном файле и хорошо отображается на экране в том же проекте) в новый закадровый кадровый буфер, а затем я использую glReadPixels, чтобы определить, прикоснулся ли пользователь к нему.

Следуя коду из проекта opengles_ch10_1 из книги Эрика М. Бака "Изучение OpenGLES для iOS", я написал следующий код, который всегда печатает в 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 ответа

Ваша ошибка в том, что вы пытаетесь получить доступ к нулевому указателю - вы почти наверняка передаете массив, который вы фактически никогда не инициализировали, в свой GLKEffect или передаете его в OpenGL с помощью вызова bufferData, учитывая, что ошибка происходит внутри prepareToDraw или glDrawArrays, Для этого есть несколько возможных объяснений, хотя я не могу подтвердить ни одно из них, поскольку соответствующая информация - это то, как вы распределяете данные, которые используете, либо в perpareToDraw, либо в glDrawArrays.

Во-первых, parparit51OBJVertices может динамически размещаться в куче (вы вызываете malloc и т. П. Как вы указываете размер массива), и в этом случае ваши вызовы size of будут возвращать неправильные значения (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 для любого выбранного пикселя.

Другие вопросы по тегам