Текстура не появится, если не будет создана непосредственно перед командой отрисовки.

Вопрос или проблема

Я написал функцию для рисования прямоугольника и хочу добавить текстуру. Однако OpenGL не может применить ее, если она была инициализирована не в функции рисования.

class Material {
public:

    Material(const char* filename) {
    
        int width, height, channels;
        unsigned char* data = stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha);
        glEnable(GL_TEXTURE_2D);

        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

        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_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    }

    ~Material() { release(); }

    Material(const Material &) = delete;
    Material &operator=(const Material &) = delete;

    Material(Material &&other) : texture(other.texture) {
        other.texture = 0; 
    }

    Material &operator=(Material &&other) {
        if(this != &other) {
            release();
            std::swap(texture, other.texture);
        }
    }

    GLuint texture = 0; 

private:

    void release() {
        glDeleteTextures(1, &texture);
        texture = 0;
    }
};
class SRender {
public:

    Material* mat = new Material("01.png");
    
    void drawRect () const;
};

float vertex[] = {0,0,0, 0,1,0, 1,1,0, 1,0,0};
float texCord[] = {0,0, 0,1, 1,1, 1,0};

void SRender::drawRect() const {
    
    //Material* mat2 = new Material("01.png");

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, mat->texture);

    glColor3f(1, 1, 1);
    glPushMatrix();
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, vertex);
    glTexCoordPointer(2, GL_FLOAT, 0, texCord);
    
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glPopMatrix();
}
int WINAPI WinMain(...)
{
    
    SRender render;

    /// Код
    while (!bQuit)
    {
        
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glPushMatrix();

        render.drawRect();

        glPopMatrix();

        SwapBuffers(hDC);

        Sleep(1);
    }
}

Если я использую mat в glBindTexture, он рисует белый прямоугольник, но если я использую mat2, это работает. Я не хочу инициализировать его каждый раз, когда я что-то рисую. Что здесь не так?

Ответ или решение

Ваш вопрос касается проблемы отображения текстуры в OpenGL, когда вы пытаетесь использовать уже инициализированный объект Material для наложения текстуры на прямоугольник. Давайте разберемся с тем, почему это происходит и как можно исправить ситуацию.

Проблема

В вашем коде вы создаете объект Material, в котором происходит загрузка текстуры и генерация текстурного объекта OpenGL. Вероятной причиной того, что текстура не отображается, когда вы используете указатель mat, заключается в том, что объект Material не сохраняет состояние текстуры правильно, или текстура не связывается корректно при вызове функции drawRect().

Когда вы используете mat2, вы создаете новый объект Material перед каждым вызовом отрисовки. Это означает, что каждый раз происходит новая загрузка текстуры, и, вероятно, настройки текстуры (например, параметры фильтрации и обертки) применяются корректно, поэтому текстура и отображается.

Возможные решения

  1. Проверьте инициализацию текстуры:
    Убедитесь, что текстура успешно загружается в объекте Material. Вы должны проверить, что data не равно nullptr после вызова stbi_load(). Если оно равно nullptr, это означает, что возникла ошибка при загрузке изображения.
if (!data) {
    std::cerr << "Ошибка загрузки текстуры: " << stbi_failure_reason() << std::endl;
}
  1. Убедитесь в контексте OpenGL:
    Убедитесь, что вы вызываете функции OpenGL в правильном контексте. Возможно, объект Material инициализируется, когда контекст OpenGL не активен, либо происходит попытка использования текстуры в неподходящий момент.

  2. Правильное связывание текстуры:
    В функции drawRect() вы связываете текстуру с глобальным идентификатором текстуры. Убедитесь, что до этого момента вы вызываете glBindTexture(GL_TEXTURE_2D, mat->texture);, где mat указывает на корректно инициализированную текстуру.

  3. Проверка состояния OpenGL:
    После отрисовки можно использовать glGetError(), чтобы проверить, не возникли ли ошибки OpenGL, вы можете добавить проверку перед и после ваших OpenGL вызовов. Это поможет выявить, нет ли других проблем, которые могут мешать корректной отрисовке.

  4. Инициализация в конструкторе:
    Если вы не хотите постоянно создавать новые экземпляры Material, инициализируйте текстуру один раз в конструкторе класса SRender или используйте метод для загрузки текстур, чтобы избегать излишнего использования ресурсов.

Пример кода

Вот как можно немного изменить ваш класс SRender, чтобы гарантировать правильную инициализацию текстуры и ее использование:

class SRender {
public:
    Material* mat;

    SRender(const char* filename) {
        mat = new Material(filename);
    }

    ~SRender() {
        delete mat;
    }

    void drawRect() const {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, mat->texture);

        glColor3f(1, 1, 1);
        glPushMatrix();
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(3, GL_FLOAT, 0, vertex);
        glTexCoordPointer(2, GL_FLOAT, 0, texCord);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glPopMatrix();
    }
};

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...