"A frame-budget method for stylized s&box scenes"
- Stylized scene hitching / low FPS despite "only" mid-poly props.
- AI kits deliver ~7–12k tris per asset regardless of screen size.
- Per-poly colliders make traces noisy and burn CPU on clutter.
GPU cost tracks transformed triangles in the frame, not file size. The worst offender is often the most-instanced asset:
cost ≈ tris_per_mesh × instance_countAn 11k grass tuft × ~1150 scatter instances ≈ 13M scene tris — a large slice of a heavy frame.
Per-poly ModelCollider on decorative meshes is wasted cost; traces get noisy. Hand-sized BoxColliders from model bounds are usually enough.
1. Census before tooling
For each asset category, compute tris × instances. Budget by screen size × instance count, not densest file first.
| Role | Budget instinct |
|---|---|
| Scatter / ground clutter | Aggressive decimation OK — faceting invisible at screen size |
| Mid-ground props with thin silhouettes | Conservative — silhouette fails before UVs |
| Hero / close-up | Keep detail; cut instances elsewhere |
2. Decimate with eyes
Collapse decimation preserves painted UVs; silhouette is the failure mode (domes, wheels collapse below ~2k tris). Verify with a textured before/after on one complex prop before batching. See decimating-ai-meshes.
3. Collider policy
// Prefer for props:
var box = go.Components.Create<BoxCollider>();
box.Scale = model.Bounds.Size; // from catalog / bounds at gen time
box.Center = model.Bounds.Center;Reserve ModelCollider / PhysicsMeshFile for cases that need real mesh collision (climbable shelves, precise statics) — and only when the vmdl actually has physics parts (model-no-collision).
Capsule vs box cost/behavior: capsule-vs-box-collider-choice.
4. Instance discipline
Prefer fewer unique high-tri heroes + many cheap scatter LODs over one dense kit stamped everywhere at full res.
The frame doesn't care that each file is "only 10k tris" — it cares how many times that mesh is transformed. Separating census → budget → decimate → collider policy stops you from optimizing the wrong mesh while scatter eats the frame.