5 unstable releases
| 0.2.2 | Dec 26, 2025 |
|---|---|
| 0.2.1 | Dec 23, 2025 |
| 0.1.5 | Dec 19, 2025 |
| 0.1.0 | Dec 15, 2025 |
| 0.0.3 | Dec 11, 2025 |
#928 in Game dev
97KB
2K
SLoC
Realism Scene Manager
A lightweight, fast scene graph for the Charge game engine. Handles hierarchies, spatial culling, and open-world streaming without bloat.
Status: Beta (v0.2.2) - Use at your own risk
What is Realism?
Realism is a scene manager built specifically for Charge. It sits between your gameplay code and renderer, handling:
- Entity hierarchies (parent-child transforms)
- Fast spatial queries (what's visible right now?)
- World streaming (loading/unloading chunks as the player moves)
- Physics synchronization (keeping bodies in sync with transforms)
It's not an ECS. It's not a physics engine. It's the "glue" that connects them.
Why Use Realism?
You have deep entity hierarchies
Characters have bones. Vehicles have wheels and doors. Props attach to other props. Realism processes all of them in parallel using SIMD, not serially like a naive engine would.
You're building an open world
Streaming systems are baked in. Load/unload chunks based on player position. Memory tracking tells you how much RAM you're using.
You want predictable performance
No GC pauses. No hidden allocations. Everything is either dense arrays or sparse sets with known bounds.
Installation
Add to your Cargo.toml:
[dependencies]
realism = "=0.2.1"
glam = "0.30.9"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Requires: Rust 1.70+ (stable)
Quick Start
Spawn Some Entities
use realism::{Scene, transform::Transform};
use glam::Vec3;
let mut scene = Scene::new();
// A simple entity
let player = scene.spawn_with_transform(
Transform::from_xyz(0.0, 1.8, 0.0)
);
// A child entity (like a weapon in hand)
let weapon = scene.spawn_with_transform(
Transform::from_xyz(0.5, 0.0, 0.0)
);
// Attach it
scene.attach(weapon, player);
Propagate Transforms
// Compute world positions for everything
scene.propagate_transforms();
// Now your weapon's world position is (0.5, 1.8, 0.0)
Find What's Visible
use glam::Mat4;
let camera_vp = Mat4::perspective_rh(
70.0_f32.to_radians(),
16.0 / 9.0,
0.1,
1000.0,
);
let visible = scene.extract(Some(camera_vp));
// visible is a Vec<RenderCommand> ready to send to GPU
for cmd in visible {
// renderer.draw_mesh(cmd);
}
Stream Chunks
use realism::streaming::{ChunkManager, ChunkLoader};
let mut manager = ChunkManager::new(500.0, 1000.0);
let mut loader = ChunkLoader::new();
// Each frame
manager.update(player_pos);
for chunk_id in manager.chunks_to_load() {
loader.load_chunk_async(
chunk_id,
&format!("world/chunks/{:?}.json", chunk_id),
);
}
let loaded = loader.poll();
realism::streaming::integrate_chunks(&mut scene, &mut manager, loaded);
Common Tasks
Moving an entity
if let Some(t) = scene.transform_mut(entity) {
t.local_position = Vec3::new(10.0, 5.0, 0.0);
t.mark_dirty();
}
scene.propagate_transforms();
Attaching/detaching
// Attach child to parent
scene.attach(child, parent);
// Detach (becomes a root)
scene.detach(child);
// Child keeps its world position automatically (no drift!)
Physics sync
If you're using a physics engine (Rapier, Jolt, etc.), implement the PhysicsBackend trait:
use realism::physics::{PhysicsHandle, SyncMode};
// Mark entity as physics-driven
let handle = PhysicsHandle { id: 42, mode: SyncMode::Dynamic };
scene.add_physics_handle(entity, handle);
// Later, sync physics back to scene
scene.sync_physics(&mut your_backend);
Performance Notes
Real-world results with v0.2.0 optimizations:
| Task | Time | Notes |
|---|---|---|
| Propagate 100k flat entities | ~1.2ms | All via SIMD |
| Propagate 100k in deep hierarchy | ~2-3ms | Full SIMD coverage with BFS |
| Octree query (frustum cull) | <0.5ms | Even with boundary objects |
| Spawn/despawn entity | <0.1ms | Generational index reuse |
These are realistic numbers, tested with actual hierarchies and boundary cases.
What's Fixed (v0.2.0)
This version addresses the critical issues from v0.1:
- ✅ SIMD batching works for all hierarchy levels, not just roots
- ✅ Compiles on stable Rust (no nightly required by default)
- ✅ Transform decomposition is fixed (detaching preserves world position)
- ✅ Octree is loose (boundary straddling doesn't cause O(N) slowdown)
- ✅ Physics sync is complete (Dynamic/Kinematic bodies work)
Known Limitations
- Skeletal animation: Realism doesn't handle skinned meshes or bone IK. That's your renderer's job.
- LOD management: Multiple mesh variants for different distances? That's handled in your renderer.
- Terrain deformation: Moving terrain patches? You'll update their bounds and let Realism re-query.
Architecture Overview
Three main storage systems:
- Dense entity list: O(1) alloc/dealloc with generational safety.
- Component sparse sets: Cache-friendly iteration, O(1) random access.
- Hierarchy links: Doubly-linked sibling lists for O(1) detach.
The BFS transform propagation processes one hierarchy level at a time, batching 4 entities per SIMD instruction.
Troubleshooting
- "Detached child appears at wrong position": Make sure you call
propagate_transforms()after attaching/detaching. - "Physics body not syncing": Check your
SyncMode.Dynamic= Physics drives scene;Kinematic= Scene drives physics. - "Out of memory with streaming": Use
scene.memory_usage()to monitor RAM usage.
License
Apache 2.0 - See LICENSE file.
Built for the Charge game engine with 💪 and optimism.
Dependencies
~7MB
~215K SLoC