Step 8

Patterns for Simulation & Graphics

How simulation data moves through an engine and becomes pixels.

Abstract

Simulation and graphics are often taught as separate disciplines: physics on one side, rendering on the other. In real-time engines, however, they are tightly connected stages of the same pipeline, with data moving from CPU to GPU in a predictable rhythm every frame.

Using the Particle Playground engine as a concrete example, this article examines the patterns that connect simulation, transformation, batching, and rendering into one coherent flow.

1. The Data Flow Perspective

Every frame in a real time engine follows the same high level pattern:

Input → Simulation → Transform → Culling → Rendering → Present

Even simple demos follow this pattern; they simply skip some stages.

For the Particle Playground, the pipeline is:

Simulation → Particle Positions → GPU Buffer → Vertex Shader → Fragment Shader

This perspective is valuable because it shifts attention from isolated objects to the flow of data.

Simulation produces the data.

Graphics consumes that data.

The engine coordinates that movement clearly, efficiently, and at the right time.

2. Component Like Structures Without ECS Overkill

Many modern engines use Entity Component Systems (ECS), and for large projects they can be an excellent fit. In a compact project or educational demo, however, a full ECS can add more structure than the design requires.

Particle Playground uses a lighter composition-based approach:

  • particle defines the basic object type
  • particle_system stores particles in a contiguous array
  • particle_renderer consumes particle positions for rendering
  • camera provides view and projection matrices
  • transform provides world-space transforms when needed

The design preserves the practical benefits of ECS:

  • separation of data
  • predictable memory layout
  • clear ownership
  • easy batching

It also avoids the overhead of:

  • entity registries
  • archetypes
  • sparse sets
  • dynamic component graphs

The result is an architecture that stays small, explicit, and easy to reason about.

3. Update Pipelines

In an engine, execution order is a design decision.

Simulation → Transform → Rendering

For particles, the transform stage is intentionally simple: each particle needs only a position. The same pattern, however, scales cleanly to more complex objects.

A typical frame pipeline looks like this:

  1. Simulation
    • update velocities
    • integrate positions
    • apply constraints
    • resolve collisions (if required)
  2. Transform
    • convert local → world space
    • apply rotation, scale
    • compute matrices
  3. Culling (optional)
    • frustum culling
    • distance culling
    • LOD selection
  4. Rendering
    • upload data to GPU
    • bind shaders
    • draw

This ordered sequence becomes the backbone that keeps the engine predictable.

4. Batching and Contiguous Data

Batching is one of the central performance patterns in real-time graphics.

Why Batching Matters

Every draw call, buffer update, and state change carries a cost.

Batching keeps that cost under control by letting the engine:

  • group similar objects
  • upload them together
  • draw them together

Particles are naturally suited to batching because they share:

  • the same shader
  • the same vertex format
  • the same draw call
  • contiguous memory

That is why the Playground uses:

ppg_array particle_system;

rather than:

std::vector entities;

Contiguous data enables fast iteration, straightforward batching, and predictable performance.

5. When to Use Templates

Templates are powerful, but they are most effective when used with restraint.

Use templates when they clarify types or compile-time behavior, such as:

  • math types (vector, matrix)
  • handle types (Handle<Tag>)
  • small inlineable utilities
  • compile time configuration

Avoid using them to define broad architectural behavior, such as:

  • simulation logic
  • rendering logic
  • engine architecture
  • resource management

In short: templates should clarify types, not carry entire systems.

6. Putting It All Together — The Full Pipeline

The full Particle Playground pipeline is easiest to understand as a set of cooperating layers:

  1. Platform Layer
    • creates the window
    • polls input
    • tracks time
  2. Simulation Layer
    • owns the particle data
    • updates particles each frame
    • exposes a Span<const Particle>
  3. Math Layer
    • computes camera matrices
    • provides transform utilities
  4. Graphics Layer
    • owns GPU buffers
    • owns shader programs
    • uploads particle positions
    • binds camera matrices
    • draws particles
  5. Core Layer
    • provides handles
    • provides spans
    • provides timers
    • provides result types
  6. App Layer
    • orchestrates the system
    • defines the main loop
    • connects simulation, graphics, and platform concerns

Together, these layers form a practical engine architecture: small enough to study, clean enough to maintain, and structured enough to grow.

7. Example Frame Walkthrough

A single frame makes the architecture concrete:

Step 1 — Platform
float dt = btm::get_elapsed_time();  // btm-framework is the backbone
Step 2 — Simulation
sim.step_simulation(dt);
Step 3 — Camera
matrix4 view = camera.view_matrix();
matrix4 projection = camera.projection_matrix();
Step 4 — Renderer
renderer.init(positions, colors);
renderer.render(camera, positions);

Inside render(), the renderer performs four operations:

  • uploads data to the GPU buffer
  • binds the shader program
  • sets uniforms
  • draws points
Step 5 — Present
begin_render(draw_surface);
end_render(draw_surface);
while (application_active()) { ... }

Together, these steps capture the engine loop in miniature.

8. Why This Matters

These patterns make engines easier to build, extend, and debug. More importantly, they help systems remain:

  • predictable
  • scalable
  • maintainable
  • debuggable
  • performant

They also mark the difference between:

  • a demo that works
  • an engine that can grow

At this point, Particle Playground has become a modular, pipeline-driven engine: approachable enough to understand and structured enough to extend.

Closing Thoughts

Simulation and graphics are not separate worlds. They are stages of a single pipeline, unified by:

  • contiguous data
  • predictable update loops
  • batching
  • transforms
  • camera math
  • GPU friendly layouts
  • modular architecture

This article closes the series by showing how the earlier ideas connect into one cohesive engine model.

Together, the series now forms a complete learning path:

  • Article 1: C++ as a Simulation Language
  • Article 2: C++ as a Graphics Language
  • Article 3: C++ as an Engineering Tool
  • Article 4: Patterns for Simulation & Graphics

Together, these articles build an intermediate-level arc from language fundamentals to engine architecture.