OpenGL 2D текстуры не отображаются должным образом C ++ - PullRequest
2 голосов
/ 02 апреля 2019

Я довольно новичок в OpenGL и столкнулся с проблемой, которую не могу решить. Я пытаюсь добавить простую 2D-текстуру в треугольник, текстура, кажется, загружается нормально, но она отображается зернистой и в черно-белом режиме.

текстура

Original texture

результат

Resulting triangle

Вот мой связанный код:

main.cxx

#include <iostream>
#include "display.h"
#include "shader.h"
#include "texture.h"
#include "mesh.h"
#include <glm/glm.hpp>
#include <GLFW/glfw3.h>

int main() 
{

    Display display(800, 600, "project2");

    Vertex vertices[] = {
        Vertex(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec2(0.0f, 0.0f)),
        Vertex(glm::vec3(0.5f, -0.5f, 0.0f), glm::vec2(1.0f, 0.0f)),
        Vertex(glm::vec3(0.0f, 0.5f, 0.0f), glm::vec2(0.5f, 1.0f)),
    };

    Mesh mesh(vertices, sizeof(vertices)/sizeof(vertices[0]));

    Shader shader("./shaders/shader");

    Texture texture("./textures/container.jpg");

    while (!display.IsClosed())
    {
        display.ProcessInput();

        display.Clear(0.0f, 0.15f, 0.3f, 1.0f);

        texture.Bind(0);
        shader.Bind();

        mesh.Draw();

        display.Update();
    } 

    return 0;
}

texture.cxx

#include "texture.h"

Texture::Texture(const std::string &filePath)
{
    int width, height, numComponents;
    unsigned char* imageData = stbi_load(filePath.c_str(), &width, &height, &numComponents, 4);

    if (!imageData) {
        std::cerr << "Failed to load texture: " << filePath << std::endl;
        return;
    }

    stbi_set_flip_vertically_on_load(true);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
    glGenerateMipmap(GL_TEXTURE_2D);

    stbi_image_free(imageData);
}

Texture::~Texture()
{
    glDeleteTextures(1, &texture); 
}

void Texture::Bind(unsigned int unit)
{
    glActiveTexture(GL_TEXTURE0 + unit); 
    glBindTexture(GL_TEXTURE_2D, texture);
}

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

#version 330 core

out vec4 FragColor;
uniform sampler2D diffuse;
in vec2 texCoord0;

void main() {
    FragColor = texture(diffuse, texCoord0);
}

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

#version 330 core
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;

out vec2 texCoord0;

void main() {
    gl_Position = vec4(position, 1.0);
    texCoord0 = texCoord;
}

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

1 Ответ

5 голосов
/ 02 апреля 2019

Когда изображение RGB с 3 цветными каналами загружается в объект текстуры, тогда для GL_UNPACK_ALIGNMENT необходимо установить значение 1:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
             GL_UNSIGNED_BYTE, imageData);

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

Чтобы правильно прочитать изображение, последний параметр stbi_load должен быть 0 (так как формат jpg обеспечивает 3-х цветной канал) или 3 (чтобы заставить 3 цветовых канала):

unsigned char* imageData = stbi_load(filePath.c_str(),
     &width, &height, &numComponents, 0);

stbi_load можно принудительно сгенерировать изображение с 4 цветовыми каналами, явно передав 4 к последнему параметру:

См. stb_image.h:

Basic usage (see HDR discussion below for HDR usage):
      int x,y,n;
      unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
      // ... process data if not NULL ...
      // ... x = width, y = height, n = # 8-bit components per pixel ...

// ... replace '0' with '1'..'4' to force that many components per pixel

      // ... but 'n' will always be the number that it would have been if you said 0
      stbi_image_free(data)

В этом случае параметр формата должен быть изменен с GL_RGB до GL_RGBA при загрузке изображения:

unsigned char* imageData = stbi_load(filePath.c_str(),
     &width, &height, &numComponents, 0);

// [...]

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, imageData);
...