Performance
What CCDS exposes to the player, what each option costs, and where frame time actually goes in a driving game.
The player-facing options
Seven graphics settings, all persisted per player and all changeable at runtime.
| Setting | Range | Shipped default | Cost when raised |
|---|---|---|---|
| Shadows | on/off | false |
High — an extra render pass over the city |
| Shadow resolution | 0–3 | 0 (Low) |
High — memory and fill rate |
| Soft shadows | on/off | false |
Moderate — extra filtering |
| Max realtime lights | 0–16 | 0 |
High — per-light cost on every affected object |
| Draw distance | 500–5000 m | 700 |
High — more geometry per frame |
| Antialiasing | 0–2 | 0 (None) |
Low (FXAA) to moderate (SMAA) |
| Image effects | on/off | false |
Moderate to high, depends on the volume profile |
CCDS.SetShadows(true);
CCDS.SetShadowResolution(2); // 0 Low, 1 Medium, 2 High, 3 Very High
CCDS.SetSoftShadows(true);
CCDS.SetMaxRealtimeLights(4);
CCDS.SetDrawDistance(2000f);
CCDS.SetAntialiasingMode(1); // 0 None, 1 FXAA, 2 SMAA
CCDS.SetImageEffects(true);
Each setter persists and raises CCDS_Events.OnQualityChanged. Hook that if your own systems need to react.
The shipped defaults are a low-end baseline, not a recommendation. A desktop title should ship higher starting values; edit the default* fields in CCDS_Settings.asset — see Settings Reference.
URP quality tiers
Four pipeline assets in Assets/CCDS/URP/:
| Asset | Tier |
|---|---|
CCDS_Low.asset |
Low |
CCDS_Med.asset |
Medium |
CCDS_High.asset |
High |
CCDS_Ultra.asset |
Ultra |
CCDS_Renderer.asset is the renderer they share. Camera post-processing profiles: CCDS_CameraProfile_Default, _Day, _Day_MM, _Night.
Wire the tiers to Unity's Quality levels in Project Settings → Quality. CCDS's own settings adjust values within the active tier; they do not switch tiers for you.
The biggest costs in a city driving game
In rough order of impact:
| Cost | Why it dominates | What to do |
|---|---|---|
| Traffic vehicle count | Every traffic car is a physics body with wheel colliders | Lower traffic density |
| Draw distance | A city has a lot of geometry; 5000 m draws nearly all of it | Keep it as low as the game allows, use LODs and fog |
| Realtime lights + shadows | Multiplied by every affected renderer | Bake lighting; keep realtime lights for the player's vehicle |
| WheelCollider count | Physics cost scales with active vehicles | Cap concurrent AI and traffic |
| Draw calls | Many small props defeat batching | Static-batch the city, atlas materials |
Traffic density is the single most effective dial, and it is already player-facing:
CCDS.SetTrafficDensity(0.5f); // 0–2, 1.0 = 100%
CCDS.DisableTrafficForAWhile(); // temporary, e.g. during a race
CCDS.ToggleTrafficPermanently(false); // until re-enabled
Lighting
Bake it. A city lit in realtime will not hold frame rate on any platform.
- Bake lightmaps for static geometry, and keep realtime lights for vehicles and dynamic effects.
- Re-bake after any geometry change — stale lighting data does not warn you.
- Re-bake reflection probes alongside, for the same reason.
overrideLightmapTexturescaps lightmaps at 1024 with crunch compression at build time. It trades bake quality for download size; leave it on for mobile.
Optional URP features degrade silently
If a URP feature's resources are stripped from a project — SSAO is the usual case — URP can log an error every frame. CCDS force-disables the feature and logs a single warning instead.
The implementation is in CCDS_UI_Options (ApplySSAOEnabled / IsSSAOResourceAvailable) and is fully reflection-based, so URP API changes degrade to "unavailable" rather than breaking compilation.
If you add optional renderer features of your own, follow the same pattern. A per-frame error log is itself a performance problem.
Measuring
Use the Unity Profiler, not frame-rate impressions.
| Profiler area | Look for |
|---|---|
| CPU → Rendering | Draw call and batch counts |
| CPU → Physics | Cost scaling with vehicle count |
| CPU → Scripts | Per-frame allocations |
| GPU | Shadow and post-processing passes |
| Memory | Texture and lightmap footprint |
CCDS's own F12 debug panel includes a performance module for a quick in-game read, but it is not a substitute for the Profiler. It is also off in release builds — see Build and Deploy.
Profile in a build, not in the editor. Editor overhead is large enough to hide and to invent problems.
Writing performant CCDS code
- Cache component lookups.
ACCDS_ComponentandACCDS_Vehiclealready cache the common ones. - Use
TryGetComponent(out var x)instead of a null-checkedGetComponent. - Use
FindAnyObjectByType<T>()/FindObjectsByType<T>(); the legacy find APIs are deprecated in Unity 6. - Keep LINQ out of per-frame code.
- Subscribe to
CCDS_Eventsinstead of polling state inUpdate. - Gate verbose logging behind
CCDS.DebugLog, which respectsenableDebugMessages.
Mobile
| Concern | Guidance |
|---|---|
| Colour space | Gamma. autoSetColorSpacePerPlatform handles it at build time. |
| Traffic | Lower the default density |
| Shadows | Off, or Low resolution only |
| Realtime lights | 0 |
| Draw distance | Near the 500 m floor |
| Lightmaps | Enable overrideLightmapTextures |
| Post-processing | Off by default |