Как сделать пузырьки в OpenGL?

Чтобы создать эффект пузырьков в OpenGL, нам потребуется использовать простую анимацию и шейдеры.

Для начала создадим окно и контекст OpenGL с помощью библиотеки GLFW:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

int main()
{
    // Инициализация GLFW и создание окна
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(800, 600, "Bubbles", NULL, NULL);
    glfwMakeContextCurrent(window);
    
    // Инициализация GLEW
    glewInit();
    
    // Основной цикл отрисовки
    while (!glfwWindowShouldClose(window))
    {
        // Очистка буферов цвета и глубины
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // Рендеринг пузырьков
        
        // Отображение кадра
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    
    // Освобождение ресурсов и завершение работы
    glfwTerminate();
    return 0;
}

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

Создадим шейдеры в отдельных файлах с расширением .glsl:

vertex_shader.glsl:

#version 330 core

in vec2 position;
in vec3 color;

out vec3 fragmentColor;

void main()
{
    gl_Position = vec4(position.x, position.y, 0.0, 1.0);
    fragmentColor = color;
}

fragment_shader.glsl:

#version 330 core

in vec3 fragmentColor;

out vec4 outColor;

void main()
{
    outColor = vec4(fragmentColor, 1.0);
}

Теперь, в коде программы, мы должны загрузить и скомпилировать шейдеры, а также создать и связать вершинный и фрагментный шейдеры вместе:

// Загрузка и компиляция шейдеров
GLuint vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// Чтение кода шейдеров из файлов
std::string vertexShaderCode = readFile("vertex_shader.glsl");
std::string fragmentShaderCode = readFile("fragment_shader.glsl");
const char* vertexShaderSource = vertexShaderCode.c_str();
const char* fragmentShaderSource = fragmentShaderCode.c_str();
// Компиляция шейдеров
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
// Создание и связывание шейдерной программы
GLuint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);

Теперь мы можем создать вектор вершин и цветов для отрисовки кругов пузырьков и передать их шейдерам:

// Вектор вершин
float vertices[] = {
    // Первая вершина
    -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, // Координаты и цвет
    // Вторая вершина
    0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
    // Третья вершина
    0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
};
// Создание буфера вершин
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Указание атрибутов вершин
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);

Теперь пузырьки должны быть отображены на экране с помощью цикла отрисовки:

while (!glfwWindowShouldClose(window))
{
    // Очистка буферов цвета и глубины
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // Рендеринг пузырьков
    glUseProgram(shaderProgram);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);    
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    // Отображение кадра
    glfwSwapBuffers(window);
    glfwPollEvents();
}

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

while (!glfwWindowShouldClose(window))
{
    // Очистка буферов цвета и глубины
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // Рендеринг пузырьков
    glUseProgram(shaderProgram);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    // Изменение позиции или масштаба пузырьков
    
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    // Отображение кадра
    glfwSwapBuffers(window);
    glfwPollEvents();
}

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