OpenGL ES отрисовывает предварительный просмотр камеры, дополнительные горизонтальные линии только для некоторых размеров изображения

У меня есть буфер RGB, который я рисую на текстуре, помещенной в GLSurfaceView. Размер изображения RGB такой же, как размер GLSurfaceView.

Изображение размером 1024x600 (16:9, на весь экран) прорисовывается корректно. Но изображение размером 800x600 (4:3) рисуется горизонтальными линиями как здесь, но без дополнительных столбцов.

Вот код, как я рисую изображения: Код SurfaceView

public void onSurfaceChanged(GL10 gl, int width, int height) {
    if(height == 0) {                       //Prevent A Divide By Zero By
        height = 1;                         //Making Height Equal One
    }

    currHalfWidth = width/2;
    currHalfHeight = height/2;

    cameraDist = (float)(currHalfHeight / Math.tan(Math.toRadians(45.0f / 2.0f)));

    gl.glViewport(0, 0, width, height);     //Reset The Current Viewport
    gl.glMatrixMode(GL10.GL_PROJECTION);    //Select The Projection Matrix
    gl.glLoadIdentity();                    //Reset The Projection Matrix

    //Calculate The Aspect Ratio Of The Window
    GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 2000.0f);
    //GLU.gluPerspective(gl, 0.0f, (float)width / (float)height, 0.1f, 100.0f);

    gl.glMatrixMode(GL10.GL_MODELVIEW);     //Select The Modelview Matrix
    gl.glLoadIdentity();                    //Reset The Modelview Matrix

    cameraPreview.setSurfaceSize(width, height);
}

Код CameraPreview

public void setSurfaceSize(int width, int height)
{
    surfaceWidth = width;
    surfaceHeight = height;
    out = new byte[width*height*2];

    vertexBuffer.clear();

    vertices = new float[]{ 
            -height/2.0f, -width/2.0f, 0.0f, //Bottom Left
            height/2.0f, -width/2.0f, 0.0f,     //Bottom Right
            -height/2.0f, width/2.0f, 0.0f,     //Top Left
            height/2.0f, width/2.0f, 0.0f   //Top Right
                            };
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);
}

public void draw(GL10 gl, byte[] yuv_data, Context context) {

    if(yuv_data != null && context != null)
        this.loadGLTexture(gl, yuv_data, context);


    // bind the previously generated texture        
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);       

    // Point to our buffers
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    // Set the face rotation
    gl.glFrontFace(GL10.GL_CW); 

    // Point to our vertex buffer
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); 

    // Draw the vertices as triangle strip
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);        

    //Disable the client state before leaving
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

public void loadGLTexture(GL10 gl, byte[] yuv_data, Context context) {      


    Camera.Parameters params = MainScreen.getCameraParameters();
    int imageWidth = params.getPreviewSize().width;
    int imageHeight = params.getPreviewSize().height;           

    textureWidth = 512;
    textureHeight = 512;        

    NativeConverter.convertPreview(yuv_data, out, imageWidth, imageHeight, textureWidth, textureHeight);        

    //...and bind it to our array
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);  

    //Create Nearest Filtered Texture
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);

    //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);             

    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, textureWidth, textureHeight, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(out));      
}

UPD: Проблемы решены! Это не было проблемой openGL, но входной буфер yuv_data уже был поврежден.


person Grinchman    schedule 17.09.2012    source источник
comment
Что именно делает NativeConverter? Я предполагаю, что он преобразует данные yuv в rgb и записывает их. Совпадают ли ширина и высота с шириной и высотой предварительного просмотра камеры? И почему размер ширины * высоты * 2?   -  person Slartibartfast    schedule 17.09.2012
comment
Вы правы, он преобразует данные yuv (NV21) в rgb. Размер out зависит от bpp, в моем случае bpp = 2.   -  person Grinchman    schedule 18.09.2012


Ответы (1)


Невозможно быть полностью уверенным, не зная, что делает NativeConverter, но это очень похоже на проблему выравнивания распаковки пикселей.

По умолчанию OpenGL ожидает, что все строки текстуры будут кратны 4 байтам. У вас могут возникнуть проблемы, когда вы используете значения байт на пиксель, отличные от 4, с размерами изображения, отличными от степени двойки, оба из которых вы, похоже, используете.

Если вы не хотите выравнивать строки текстуры по 4-байтовым границам, вы сообщаете OpenGL, что они не выравниваются по 4-байтовым границам, установив glPixelStorei(GL_UNPACK_ALIGNMENT, 1); перед загрузкой текстуры.

person Tim    schedule 17.09.2012
comment
Раньше пробовал GL_UNPACK_ALIGNMENT, безрезультатно. Сейчас проверяю правильность буфера 'out', возможно ошибка в NativeConverter. - person Grinchman; 18.09.2012