Микс текстур OpenGL

Итак, у меня есть класс текстур в opengl, который по сути получает буфер и отображает 2D-текстуру на экране. Сам по себе он работает отлично и позволяет мне отображать на экране столько текстур, сколько я хочу. Но я хочу добавить функцию transition, которая получает вторую текстуру вместе с исходной текстурой и объединяет их в один прямоугольник.

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

Итак, вот что ДОЛЖНО произойти: прямоугольник с data1, использующий функцию render, должен просто находиться на экране. Еще один прямоугольник с функцией transition должен быть на экране, но одновременно использует данные2 и данные3. Вот мой код:

main.cpp

class Texture{
private:
    typedef struct transtex_s { 
        uint8_t* buff;
        int w, h;
    } transtex; 


    Shader ourShader;
    unsigned int texture;
    unsigned int texture2;
    unsigned int VBO, VAO, EBO;
public:
    transtex tex2;

    Texture(float pos, bool is_trans, std::string shader): ourShader("camera.vs", shader.c_str())
    {
    float vertices[] = {
        // positions          // colors           // texture coords
         pos,  pos, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
         pos, -pos, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -pos, -pos, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -pos,  pos, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left 
    };
    unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);


    ourShader.use(); 
    glUniform1i(glGetUniformLocation(ourShader.ID, "texture"), 1);

    if (is_trans)
    {
        ourShader.setInt("texture2", 1);
    }
    }

    void transition(int width1,int height1, uint8_t* data1, float progress)
    {
        ourShader.use();
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, data1);
        glGenerateMipmap(GL_TEXTURE_2D);

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

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex2.w, tex2.h, 0, GL_RGB, GL_UNSIGNED_BYTE, tex2.buff);
        glGenerateMipmap(GL_TEXTURE_2D);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glUniform1f(glGetUniformLocation(ourShader.ID, "progress"), progress);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    }

    void render(int w, int h, uint8_t* buffer)
    {
        ourShader.use();
        glEnable(GL_BLEND);

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

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
        glGenerateMipmap(GL_TEXTURE_2D);

        glActiveTexture(GL_TEXTURE2);
        
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    }

    ~Texture()
    {
        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);
        glDeleteBuffers(1, &EBO);
    }
};

int main()
{
    ... // init glfw, opengl and glad.
   
    // Read images as buffers using stbi image.
    int width1, height1, nrChannels1;
    stbi_set_flip_vertically_on_load(true);
    unsigned char *data1 = stbi_load("/home/tb/Desktop/Work/CameraTest/bin/ex2.jpeg", &width1, &height1, &nrChannels1, 0);

    int width2, height2, nrChannels2;
    unsigned char *data2 = stbi_load("/home/tb/Desktop/Work/CameraTest/bin/ex1.jpeg", &width2, &height2, &nrChannels2, 0);

    int width3, height3, nrChannels3;
    unsigned char *data3 = stbi_load("/home/tb/Desktop/Work/CameraTest/bin/WATERMARK.png", &width3, &height3, &nrChannels3, 0);

    Texture rect1 = Texture(0.5f, true, "camera.fs");
    Texture rect2 = Texture(1.0f, false, "normal.fs");

    float progress = 0.0f;

    while (!glfwWindowShouldClose(window))
    {
        rect1.tex2.buff = data2;
        rect1.tex2.w = width2;
        rect1.tex2.h = height2;

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        rect2.render(width3, height3, data3);
        rect1.transition(width1, height1, data1, progress);

        progress += 0.01f;

        if (progress >= 1.0f) progress = 0.0f;

        glfwSwapBuffers(window);
    }

    stbi_image_free(data1);
    stbi_image_free(data2);
    return 0;
}

Векторы:

camera.fs

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float progress;

void main()
{
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), progress);
}

normal.fs

#version 330 core

in vec2 TexCoord;
out vec4 FragColor; 

uniform sampler2D texture1; 

void main()
{
    vec4 texColor = texture(texture1, TexCoord);

    FragColor = texColor;
}

На линии:

rect2.render(width3, height3, data3);
rect1.transition(width1, height1, data1, progress);

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

Почему это происходит? Как я могу это исправить?

Обновлено: после дальнейшего изучения я понял, что ourShader.use(); в рендере (который по сути представляет собой gluseprogram(ID)) вызывает проблему. Но я до сих пор не знаю, как это предотвратить.

Редактировать 2: Проблемы, связанные с функцией перехода, теперь решены. Однако теперь, после первых нескольких кадров, функция render начинает использовать data1 вместо data3.

Сначала вы вызываете render() (который не очищает буфер). Затем вызовите transition, который ДЕЙСТВИТЕЛЬНО очищает буфер... теряя то, что render нарисовал.

Ripi2 13.09.2023 21:50

@Ripi2 Если вы говорите о glClear(GL_COLOR_BUFFER_BIT);, добавление этого к render() ничего не меняет. Если есть другая функция, очищающая буфер, сообщите мне. Я обновил вопрос о том, где я их добавил.

Turgut 13.09.2023 21:56

Ваша главная проблема, похоже, заключается в том, что вы устанавливаете униформу не на тот шейдер. Команды glUniform* всегда работают с активным в данный момент шейдером, поэтому вам необходимо вызвать ourShader.use() перед установкой униформ.

BDL 14.09.2023 11:38

@BDL Это решает проблемы, связанные с функцией перехода. Однако у рендеринга все еще есть проблема, для которой я обновил вопрос.

Turgut 14.09.2023 19:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, в моем коде было две ошибки:

  1. Не использовать сначала шейдеры в каждой функции (рендеринг и переход)

  2. Использование GL_TEXTURE2 в render вместо GL_TEXTURE0.

Исправление этих ошибок дало мне желаемый результат.

Другие вопросы по теме