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.
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:
Simulation - update velocities
- integrate positions
- apply constraints
- resolve collisions (if required)
Transform - convert local → world space
- apply rotation, scale
- compute matrices
Culling (optional)- frustum culling
- distance culling
- LOD selection
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
6. Putting It All Together — The Full Pipeline
The full Particle Playground pipeline is easiest to understand as a set of cooperating layers:
Platform Layer - creates the window
- polls input
- tracks time
Simulation Layer - owns the particle data
- updates particles each frame
- exposes a Span<const Particle>
Math Layer - computes camera matrices
- provides transform utilities
Graphics Layer - owns GPU buffers
- owns shader programs
- uploads particle positions
- binds camera matrices
- draws particles
Core Layer - provides handles
- provides spans
- provides timers
- provides result types
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:
float dt = btm::get_elapsed_time(); // btm-framework is the backbone
sim.step_simulation(dt);
matrix4 view = camera.view_matrix();
matrix4 projection = camera.projection_matrix();
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
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.