Проблема с интерполяцией шейдеров Opengles

Я вижу проблемы, связанные с точностью интерполяции шейдерами. Я получаю искаженную синюю линию, как показано ниже, из-за точности интерполяции переменной переменной (в данном случае высоты) шейдерами. Как это исправить?

введите здесь описание изображения

Вот как я передаю данные шейдерам:

    uint8_t * oglData = CVPixelBufferGetBaseAddress(_pixelBuffer);  

    for (NSInteger i = 0; i < 256; i++) {

       /* Only first two columns blue in BGRA 256x1 buffer */     
        if (i < 2) {
            oglData[4 * i] =   255;
            oglData[4 * i + 1] =  0;
            oglData[4 * i +2]   = 0;
            oglData[4 * i +3] = 1;
        } else {
            oglData[4 * i] =   0;
            oglData[4 * i + 1] =  0;
            oglData[4 * i +2]   = 0;
            oglData[4 * i +3] = 1;
        }
    }
}

А вот и шейдеры:

Вершинный шейдер:

   attribute vec4 position;
   attribute vec4 inputTextureCoordinate;

   varying vec2 textureCoordinate;
   varying float height;

   void main()
   {
     gl_Position = position;                                                          
     textureCoordinate = vec2(inputTextureCoordinate.x, 0.0);
     height = inputTextureCoordinate.y;
   }

Фрагментный шейдер:

   varying highp vec2 textureCoordinate;
   varying highp float height;

   uniform sampler2D inputImageTexture;
   uniform lowp vec4 backgroundColor;

   void main() {
     lowp vec3 colorChannels = texture2D(inputImageTexture, textureCoordinate).rgb;
                                                               //  
    if (colorChannels.b >= height) {                
                 gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
    } else {                                                      
        gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);                                                  
    }

  }

Вот код рисования:

glActiveTexture( GL_TEXTURE0 );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, oglData);

glUniform1i( _inputImageTexture, 0 );

// Set texture parameters
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

glVertexAttribPointer( ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices );
glEnableVertexAttribArray( ATTRIB_VERTEX );

glVertexAttribPointer( ATTRIB_TEXTURECOORDINATE, 2, GL_FLOAT, 0, 0, textureCoordinates );
glEnableVertexAttribArray( ATTRIB_TEXTURECOORDINATE );

glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

glBindRenderbuffer( GL_RENDERBUFFER, _colorBufferHandle );
[_oglContext presentRenderbuffer:GL_RENDERBUFFER];

РЕДАКТИРОВАТЬ: изменение GL_LINEAR на GL_NEAREST устраняет проблему, что означает, что различные переменные интерполируются в зависимости от типа фильтров min и mag в параметрах текстуры? Но использование GL_Nearest создает негладкие кривые.


person Deepak Sharma    schedule 16.02.2018    source источник


Ответы (1)


Как это исправить?

Вы не можете (по крайней мере, не напрямую) — это аппаратная фиксированная функция внутри графического процессора, поэтому вам просто придется с этим смириться.

Изменение GL_LINEAR на GL_NEAREST устраняет проблему, что означает, что различные переменные интерполируются в зависимости от типа фильтров min и mag в параметрах текстуры?

Нет - переменная интерполяция не имеет ничего общего с текстурными фильтрами min/mag.

Ваша проблема заключается в том, что неточность в различной интерполяции приводит к тому, что входная точка выборки в ваш вызов функции texture() отклоняется от центра текселя, поэтому фильтрация текстуры GL_LINEAR начинает действовать. Используя GL_NEAREST, вы эффективно квантоваете точки выборки, поэтому, пока ошибка составляет менее половины ширины текселя, вы возвращаетесь к нужному текселю.

person solidpixel    schedule 21.02.2018
comment
То есть вы говорите, что виновата разная точность интерполяции и невозможно нарисовать вертикальную линию одним цветом? - person Deepak Sharma; 22.02.2018
comment
Должно быть возможно - highp - это fp32, поэтому дает вам 23 дробных бита, поэтому вы должны иметь возможность точно решить это. Однако без полного репродуктора будет трудно точно определить, что идет не так. Насколько велик ваш экран и какие координаты текстуры вы передаете ему по углам? - person solidpixel; 24.02.2018