2013-09-28 4 views
0

Его о выборе 3d-объекта с использованием выбора цвета. Я рисую свою сетку (обновление: которое находится в статическом файле заголовка и отображается на экране в том же проекте отлично) в новый заставку фреймбуфера, а затем я использую glReadPixels, чтобы определить, коснулся ли пользователь его.opengl iOS glkit colouring

Следуя коду проекта 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 
    } 
} 

ответ

0

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

Во-первых, что «parparit51OBJVertices» может быть распределено динамически динамически (вы вызываете malloc или тому подобное? Как вы определяете размер массива), и в этом случае ваши вызовы sizeof будут возвращать неправильные значения (0, я думаю), что может привести к EXEC_BAD_ACESS.

Другая часть этого, что кажется подозрительным, заключается в том, что вы вызываете glDrawArrays и передаете число вершин, но до этого вы привязываете VBO для индексов - в лучшем случае это тратится впустую, так как glDrawArrays игнорирует индексы , Хуже того, если вы пытаетесь нарисовать OBJ, как следует из вашего имени переменной, то, вероятно, существует значительная геометрия, которую вы вообще не рисуете, поэтому даже если вы исправите проблему EXEC_BAD_ACCESS, вы все равно получите плохие результаты.

+0

Спасибо Бен за подробный ответ, но я верю, что это не решение. Оба массива шагов (вершины-3, цвета-4, текстурыUVs-2, нормали-3) и массив индексов являются статическими и определяются в файле заголовка. Оба работают хорошо, когда я показываю их на экране в том же проекте, используя Gldrawarrays. – user2492853

+0

Я вижу. Да, этот размер звонка явно не является вашей проблемой, но я уверен, что ваша проблема в том, что вы предоставляете OpenGL нулевой указатель где-то вдоль линии. Учитывая, что он рисует где-то в другом месте (было бы полезно увидеть этот код, а также где все эти вещи были инициализированы), моя новая теория будет заключаться в том, что ваш вызов glBindVertexArrayOES (0) для очистки VAO очищает некоторые данные, которые вы затем забываете переустановить. –

+0

Я также подозрительно отношусь к вашему glVertexAttribPointer (GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12 * sizeof (GLfloat), 0-вызов. Это на самом деле размер paraprit51OBJVertices? Это работает в другом обратном вызове? Кроме того, это был мой что paraprit51OBJVertices имеет тип Vertex (структура, я полагаю, учитывая ваш вызов glDrawArrays), но вы даете ему шаг нуля. –

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 для любого пикселя выбрал.

Смежные вопросы