ImGui Particle Background

Wednesday, February 14, 2024
5 min read

Creating a Dynamic Particle Background with ImGui

Do you want to improve the style of your application? Here's a glimpse into crafting a dynamic particle background using ImGui. This implementation introduces a mesmerizing interplay of lines and particles that react to cursor movements within an ImGui window.

img-of-it

Initialization of Particles:

The magic begins by initializing particles with random positions and velocities. Each particle finds its home within the ImGui window, equipped with a unique trajectory for future animation.

cpp Copy code
static bool initialized = false;
              if (!initialized)
              {
                  for (int i = 0; i < numParticles; ++i)
                  {
                      particlePositions[i] = ImVec2(
                          ImGui::GetWindowPos().x + ImGui::GetWindowSize().x * static_cast<float>(rand()) / RAND_MAX,
                          ImGui::GetWindowPos().y + ImGui::GetWindowSize().y * static_cast<float>(rand()) / RAND_MAX
                      );
              
                      particleVelocities[i] = ImVec2(
                          static_cast<float>((rand() % 11) - 5),
                          static_cast<float>((rand() % 11) - 5)
                      );
                  }
                  initialized = true;
              }

Drawing Lines to Cursor and Particles:

The visual spectacle unfolds as lines are drawn between particles and the cursor, creating an intricate dance of connections. Opacity gracefully changes with distance, contributing to the ethereal ambiance.

cpp Copy code
ImVec2 cursorPos = ImGui::GetIO().MousePos;
              for (int i = 0; i < numParticles; ++i)
              {
                  // draw lines to particles
                  for (int j = i + 1; j < numParticles; ++j)
                  {
                      float distance = std::hypotf(particlePositions[j].x - particlePositions[i].x, particlePositions[j].y - particlePositions[i].y);
                      float opacity = 1.0f - (distance / 55.0f);  // opacity change
              
                      if (opacity > 0.0f)
                      {
                          ImU32 lineColor = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, opacity));
                          drawList->AddLine(particlePositions[i], particlePositions[j], lineColor);
                      }
                  }
              
                  // draw lines to cursor
                  float distanceToCursor = std::hypotf(cursorPos.x - particlePositions[i].x, cursorPos.y - particlePositions[i].y);
                  float opacityToCursor = 1.0f - (distanceToCursor / 52.0f);  // Adjust the divisor to control the opacity change
              
                  if (opacityToCursor > 0.0f)
                  {
                      ImU32 lineColorToCursor = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, opacityToCursor));
                      drawList->AddLine(cursorPos, particlePositions[i], lineColorToCursor);
                  }
              }

Updating and Rendering Particles:

Particles undergo a continuous update, adjusting positions while staying within the bounds of the ImGui window. Each particle leaves a luminous trail behind, rendering a stunning visual symphony.

cpp Copy code
float deltaTime = ImGui::GetIO().DeltaTime;
              for (int i = 0; i < numParticles; ++i)
              {
                  particlePositions[i].x += particleVelocities[i].x * deltaTime;
                  particlePositions[i].y += particleVelocities[i].y * deltaTime;
              
                  // Stay in window
                  if (particlePositions[i].x < ImGui::GetWindowPos().x)
                      particlePositions[i].x = ImGui::GetWindowPos().x + ImGui::GetWindowSize().x;
                  else if (particlePositions[i].x > ImGui::GetWindowPos().x + ImGui::GetWindowSize().x)
                      particlePositions[i].x = ImGui::GetWindowPos().x;
              
                  if (particlePositions[i].y < ImGui::GetWindowPos().y)
                      particlePositions[i].y = ImGui::GetWindowPos().y + ImGui::GetWindowSize().y;
                  else if (particlePositions[i].y > ImGui::GetWindowPos().y + ImGui::GetWindowSize().y)
                      particlePositions[i].y = ImGui::GetWindowPos().y;
              
                  ImU32 particleColour = ImGui::ColorConvertFloat4ToU32(settings::particleColour);
              
                  // render particles behind components
                  drawList->AddCircleFilled(particlePositions[i], 1.5f, particleColour);
              }

Conclusion

Unlock the world of ImGui creativity by implementing this dynamic particle background. Tweak the parameters, explore color variations, and let your imagination run wild. The result is a captivating visual experience that adds a touch of enchantment to your ImGui applications.

Check out the full code and experiment with your own particle playground here.

Happy coding! 👋