Невозможность сопоставить простую байтовую rgb-текстуру без знака с четырехъядерным:

У меня есть очень простая программа, которая отображает фиктивную красную текстуру на четырехугольник.

Вот определение текстуры в C ++:

struct DummyRGB8Texture2d
{
    uint8_t data[3*4];
    int width;
    int height;

};

DummyRGB8Texture2d myTexture
{
    { 
        255,0,0,
        255,0,0,
        255,0,0,
        255,0,0
    },
    2u,
    2u
};

Вот как я настраиваю текстуру:

void SetupTexture()
{
    // allocate a texture on the default texture unit (GL_TEXTURE0): 

    GL_CHECK(glCreateTextures(GL_TEXTURE_2D, 1, &m_texture));

    // allocate texture:
    GL_CHECK(glTextureStorage2D(m_texture, 1, GL_RGB8, myTexture.width, myTexture.height));

    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_WRAP_S, GL_REPEAT));
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_WRAP_T, GL_REPEAT));
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST));

    // tell the shader that the sampler2d uniform uses the default texture unit (GL_TEXTURE0) 
    GL_CHECK(glProgramUniform1i(m_program->Id(), /* location in shader */ 3, /* texture unit index */ 0));

    // bind the created texture to the specified target. this is necessary even in dsa
    GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));

    GL_CHECK(glGenerateMipmap(GL_TEXTURE_2D));
}

Вот как я рисую текстуру на четырехугольнике:

void Draw()
{
    m_target->ClearTargetBuffers();
    m_program->MakeCurrent();

    // load the texture to the GPU:
    GL_CHECK(glTextureSubImage2D(m_texture, 0, 0, 0, myTexture.width, myTexture.height,
            GL_RGB, GL_UNSIGNED_BYTE, myTexture.data));

    GL_CHECK(glBindVertexArray(m_vao));     

    GL_CHECK(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(VideoQuadElementArray.size()), GL_UNSIGNED_INT, 0));
        m_target->SwapTargetBuffers();
}

Результат:

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

Я не могу понять, почему эта текстура не будет красной. Кроме того, если я изменю внутренний формат текстуры на RGB A / RGB A 8 и массив данных текстуры, чтобы иметь еще один элемент в каждой строке, я получу красивую красную текстуру.


Если это актуально, вот мои атрибуты вершин и мои (очень простые) шейдеры:

struct VideoQuadVertex
{
    glm::vec3 vertex;
    glm::vec2 uv;
};

std::array<VideoQuadVertex, 4> VideoQuadInterleavedArray
{
    /* vec3 */ VideoQuadVertex{ glm::vec3{ -0.25f, -0.25f, 0.5f }, /* vec2 */  glm::vec2{ 0.0f, 0.0f } },
    /* vec3 */ VideoQuadVertex{ glm::vec3{ 0.25f, -0.25f, 0.5f }, /* vec2 */   glm::vec2{ 1.0f, 0.0f } },
    /* vec3 */ VideoQuadVertex{ glm::vec3{ 0.25f, 0.25f, 0.5f }, /* vec2 */    glm::vec2{ 1.0f, 1.0f } },
    /* vec3 */ VideoQuadVertex{ glm::vec3{ -0.25f, 0.25f, 0.5f }, /* vec2 */ glm::vec2{ 0.0f, 1.0f } }


};

настройка вершин:

void SetupVertexData()
{


// create a VAO to hold all node rendering states, no need for binding:
    GL_CHECK(glCreateVertexArrays(1, &m_vao));

// create vertex buffer objects for data and indices and initialize them:
GL_CHECK(glCreateBuffers(static_cast<GLsizei>(m_vbo.size()), m_vbo.data()));

// allocate memory for interleaved vertex attributes and transfer them to the GPU:
GL_CHECK(glNamedBufferData(m_vbo[EVbo::Data], VideoQuadInterleavedArray.size() * sizeof(VideoQuadVertex), VideoQuadInterle

GL_CHECK(glVertexArrayAttribBinding(m_vao, 0, 0));
GL_CHECK(glVertexArrayVertexBuffer(m_vao, 0, m_vbo[EVbo::Data], 0, sizeof(VideoQuadVertex)));


// setup the indices array:
GL_CHECK(glNamedBufferData(m_vbo[EVbo::Element], VideoQuadElementArray.size() * sizeof(GLuint), VideoQuadElementArray.data
GL_CHECK(glVertexArrayElementBuffer(m_vao, m_vbo[EVbo::Element]));

// enable the relevant attributes for this VAO and
// specify their format and binding point:

// vertices:
GL_CHECK(glEnableVertexArrayAttrib(m_vao, 0 /* location in shader*/));
GL_CHECK(glVertexArrayAttribFormat(
    m_vao,
    0,                  // attribute location
    3,                  // number of components in each data member
    GL_FLOAT,           // type of each component
    GL_FALSE,           // should normalize
    offsetof(VideoQuadVertex, vertex)   // offset from the begining of the buffer
));

// uvs:
GL_CHECK(glEnableVertexArrayAttrib(m_vao, 1 /* location in shader*/));
GL_CHECK(glVertexAttribFormat(
    1,                                  // attribute location
    2,                                  // number of components in each data member
    GL_FLOAT,                           // type of each component
    GL_FALSE,                           // should normalize
    offsetof(VideoQuadVertex, uv)   // offset from the begining of the buffer
));

GL_CHECK(glVertexArrayAttribBinding(m_vao, 1, 0));

}

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

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texture_coordinate;


out FragmentData
{
    vec2 uv;
} toFragment;


void main(void)
{   
    toFragment.uv = texture_coordinate;
    gl_Position = vec4 (position, 1.0f);
}

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

in FragmentData
{
    vec2 uv;
} data;

out vec4 color;

layout (location = 3) uniform sampler2D tex_object;

void main()
{
    color = texture(tex_object, data.uv);   
}

person    schedule 13.09.2017    source источник
comment
Я предполагаю, что вы оставили GL_UNPACK_ALIGNMENT со значением по умолчанию 4, что заставит GL ожидать некоторых байтов заполнения в конце каждой строки в массиве на стороне клиента. Подробнее см. Распространенные ошибки: загрузка текстуры и чтение пикселей в вики OpenGL.   -  person derhass    schedule 13.09.2017
comment
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); до glTextureSubImage2D   -  person Rabbid76    schedule 13.09.2017


Ответы (1)


GL_UNPACK_ALIGNMENT определяет требования к выравниванию для начала каждой строки пикселей в памяти. По умолчанию для GL_UNPACK_ALIGNMENT установлено значение 4. Это означает, что каждая строка текстуры должна иметь длину 4 * N байтов.

Вы указываете текстуру 2 * 2 с данными: 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0

Если для GL_UNPACK_ALIGNMENT установлено значение 4, это интерпретируется как

         column 1          column 2              alignment
row 1:   255, 0,   0,      255, 0,     0,        255, 0,
row 2:   0,   255, 0,      0,   undef, undef

Итак, текстура читается как

          column 1   olumn 2  
row 1:    red,       red,
row 2:    green,     RGB(0, ?, ?)


Перед glTextureSubImage2D, для чтения плотно упакованной текстуры.


Если вы не хотите изменять GL_UNPACK_ALIGNMENT (выравнивание остается равным 4), вы должны адаптировать данные следующим образом:

struct DummyRGB8Texture2d
{
    uint8_t data[8*2];
    int width;
    int height;
};

DummyRGB8Texture2d myTexture
{
    { 
        255, 0, 0, 255, 0, 0, // row 1
        0, 0,                 // 2 bytes alignment
        255, 0, 0, 255, 0, 0, // row 2
        0, 0                  // 2 bytes alignment
    },
    2u,
    2u
};


Смотрите далее:

person Rabbid76    schedule 13.09.2017