Совет по алгоритму рендеринга растрового изображения по пикселям

Я работал над загрузчиком растровых изображений с основной целью - не более, чем правильно анализировать данные и отображать их в OpenGL. Я нахожусь в той точке, где мне нужно рисовать пиксели на основе x / y (то есть пиксель за пикселем) (по крайней мере, это то, что я думаю, что мне нужно сделать, что касается рендеринга). Я уже связал объект текстуры и назвал glTexImage2D(...).

В настоящее время у меня проблемы с алгоритмом пиксель за пикселем.

Насколько я понимаю, файлы растровых изображений (также известные как DIB) хранят данные цвета в так называемом массиве пикселей. Каждая строка пикселей состоит из x байтов, причем каждый пиксель содержит количество байтов, делимое на 4 (32 бита на пиксель), 3 (24 бита на пиксель), 2 (16 бит на пиксель) или 1 (8 битов). на пиксель).

Я думаю, что нужно перебрать пиксели, одновременно вычисляя правильное смещение в массиве пикселей, которое относительно его координаты x / y пикселя. Но правда ли это? Если нет, что мне делать? Честно говоря, я немного запутался, несмотря на то, что делал то, что было указано мне в этот вопрос я задал некоторое время назад, это правильный подход.

Я предполагаю, что подход к этому попиксельно - правильный подход, главным образом потому, что рендеринг четырехугольника с glVertex* и glTexCoord* не дал ничего, кроме затененного прямоугольника (в то время я думал, что OpenGL справится с этим сам по себе, поэтому почему пытаясь это сделать в первую очередь).

Я также должен отметить, что, хотя в моем вопросе отображаются шейдеры OpenGL 3.1, я перешел на SDL 1.2, чтобы я мог просто использовать немедленный режим, пока не реализованы правильные алгоритмы, а затем снова переключиться на современный GL.


Тестовое изображение, которое я разбираю:

растровое изображение

Это выходные данные (вставленные из-за очень большой длины): http://pastebin.com/6RVhAVRq

И код:

void R_RenderTexture_PixByPix( texture_bmp_t* const data, const vec3 center )
{


    glBindTexture( GL_TEXTURE_2D, data->texbuf_id );

    glBegin( GL_POINTS );
    {
        const unsigned width  = data->img_data->width + ( unsigned int ) center[ VEC_X ];
        const unsigned height = data->img_data->height + ( unsigned int ) center[ VEC_Y ];

        const unsigned bytecount    = GetByteCount( data->img_data->bpp );

        const unsigned char* pixels = data->img_data->pixels;

        unsigned color_offset = 0;
        unsigned x_pixel;

        for ( x_pixel = center[ VEC_X ]; x_pixel < width; ++x_pixel )
        {
            unsigned y_pixel;

            for ( y_pixel = center[ VEC_Y ]; y_pixel < height; ++y_pixel )
            {

            }

            const bool do_color_update = true; //<--- replace true with a condition which checks to see if the color needs to be updated.

            if ( do_color_update )
            {
                glColor3fv( pixels + color_offset );
            }

            color_offset += bytecount;
        }
    }
    glEnd();

    glBindTexture( GL_TEXTURE_2D, 0 );
}

person zeboidlund    schedule 15.01.2013    source источник
comment
но почему вы хотите делать это попиксельно? не лучше ли нарисовать четырехугольник правильного размера (используя 4 вершины). правильно означает, что последний четырехугольник будет соответствовать размеру растрового изображения.   -  person fen    schedule 15.01.2013
comment
@fan, на самом деле я пытался это сделать ... что сбило меня с толку, главным образом потому, что в результате получился серый прямоугольник.   -  person zeboidlund    schedule 15.01.2013


Ответы (2)


Вы полностью упускаете суть текстуры OpenGL в своем коде. Текстура содержит изображение за вас, а растеризатор выполняет все итерации над пиксельными данными за вас. Не нужно самостоятельно писать медленный цикл смещения пикселей.

В вашем коде прямо сейчас эта текстура полностью поддельная и ничего не делает. Вы можете полностью опустить вызовы glBindTexture, и он все равно будет работать - или нет, потому что вы на самом деле ничего не рисуете, вы просто устанавливаете состояние glColor. Чтобы что-то нарисовать, вам нужно вызвать glVertex.

Так почему бы не использовать производительность современных графических процессоров с выталкиванием пикселей и на самом деле не использовать текстуры? Как насчет этого:

void R_RenderTexture_PixByPix( texture_bmp_t* const data, const vec3 center )
{
    if( 0 == data->texbuf_id ) {
        glGenTextures(1, &(data->texbuf_id));
        glBindTexture( GL_TEXTURE_2D, data->texbuf_id );

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        // there are a few more, but the defaults are ok
        // if you didn't change them no need for further unpack settings

        GLenum internal_format;
        GLenum format;
        GLenum type;
        switch(data->img_data->bpp) {
        case 8:
            // this could be a palette or grayscale
            internal_format = GL_LUMINANCE8;
            format = GL_LUMINANCE;
            type = GL_UNSIGNED_BYTE;
            break;

        case 15:
            internal_format = GL_RGB5;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_SHORT_1_5_5_5;
            break;

        case 16:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_SHORT_5_6_5;
            break;

        case 24:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_BYTE;
            break;

        case 32:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_INT_8_8_8_8;
            break;

        }

        glTexImage2D( GL_TEXTURE_2D, 0, internal_format,
                      data->img_data->width, data->img_data->height, 0,
                      format, type, data->img_data->pixels );
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    } else {
        glBindTexture( GL_TEXTURE_2D, data->texbuf_id );
    }


    static GLfloat verts[] = {
            0, 0, 
            1, 0,
            1, 1,
            0, 1
    };    
    // the following is to address texture image pixel centers
    // tex coordinates 0 and 1 are not on pixel centers!
    float const s0 = 1. / (2.*tex_width);
    float const s1 = ( 2.*(tex_width-1) + 1.) / (2.*tex_width);
    float const t0 = 1. / (2.*tex_height);
    float const t1 = ( 2.*(tex_height-1) + 1.) / (2.*tex_height);
    GLfloat texcoords[] = {
            s0, t0,
            s1, t0,
            s1, t1,
            s0, t1
    };

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glEnable(GL_TEXTURE_2D);

    glVertexPointer(2, GL_FLOAT, 0, verts);
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);

    glColor4f(1., 1., 1., 1.);
    glDrawArrays(GL_QUADS, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindTexture( GL_TEXTURE_2D, 0 );
}
person datenwolf    schedule 15.01.2013

Ваша интуиция в основном верна. Пиксели хранятся в виде массива байтов, но байты организованы в последовательные группы, каждая из которых представляет один пиксель. Чтобы обратиться к одному пикселю, вам нужно произвести такой расчет:

unsigned char* image_data = start_of_pixel_data;
unsigned char* pixel_addr = image_data + bytes_per_pixel * (y * width_in_pixels + x);

Будьте осторожны с шириной в пикселях, так как иногда в конце строки есть отступ, чтобы общая ширина строки в байтах была кратной 4/8/16/32/64 / и т. Д. Я рекомендую сначала посмотреть фактические байты растрового изображения в шестнадцатеричном формате, чтобы понять, что происходит. Это отличное обучающее упражнение, которое придаст вам уверенности в своем коде обхода пикселей, а это именно то, что вам нужно. Вы можете использовать для этого отладчик или написать простой цикл с printf над байтами изображения.

person Randall Cook    schedule 15.01.2013
comment
Спасибо, ценю помощь и советы. - person zeboidlund; 15.01.2013