Итак, у меня есть класс текстур в 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.
@Ripi2 Если вы говорите о glClear(GL_COLOR_BUFFER_BIT);
, добавление этого к render()
ничего не меняет. Если есть другая функция, очищающая буфер, сообщите мне. Я обновил вопрос о том, где я их добавил.
Ваша главная проблема, похоже, заключается в том, что вы устанавливаете униформу не на тот шейдер. Команды glUniform*
всегда работают с активным в данный момент шейдером, поэтому вам необходимо вызвать ourShader.use()
перед установкой униформ.
@BDL Это решает проблемы, связанные с функцией перехода. Однако у рендеринга все еще есть проблема, для которой я обновил вопрос.
Итак, в моем коде было две ошибки:
Не использовать сначала шейдеры в каждой функции (рендеринг и переход)
Использование GL_TEXTURE2
в render
вместо GL_TEXTURE0
.
Исправление этих ошибок дало мне желаемый результат.
Сначала вы вызываете
render()
(который не очищает буфер). Затем вызовитеtransition
, который ДЕЙСТВИТЕЛЬНО очищает буфер... теряя то, чтоrender
нарисовал.