This document is about: QUANTUM 1
SWITCH TO

What's New In 1.2.4

Entity Filters

Fast Entity Filters are finally here, together with a major refactoring of the way entity iterators work:

  • Both active and free entity slots meta-data are now based on a double-linked list, meaning all operations are optimal: create/destroy is O(1) while Frame.GetAllEntityTypeXYZ() is guaranteed O(a) where "a" is the number of active instances of that entity type (previously all slots were traversed to find the active ones).
  • Frame.FrameFilters bring a lot more options to express entity type groups (check full documentation here) and use the same optimal traversal implementation used on entity iterators.
  • Frame.GetAllComponentXYZ() is now obsolete and because it also uses a slightly different API that involves a buffer allocation (pooled) we recommend migrating to Entity Filters instead.

Besides filters are able to express a lot more than single component iterators. We already added default ones to the pre-built components:

CharacterController3D, DynamicBody3D, DynamicBody2D, NavMeshAgent, Animator and Prefab.

For example when you want to go through all your 2D physics bodies:

C#

public override void Update(Frame f) {
    var iterator = f.Filters.DynamicBody2D(true);
    while (iterator.Next()) {
        Entity* entity = iterator.Current;
        FPVector2 pos = iterator.Transform2D->Position;
        if (iterator.Any.Transform2DVertical != null) {
            var offset = iterator.Any.Transform2DVertical->Position;
        }
    }
}

Of course you can also create your own filters in the DSL:

C#

filter MyEntities {
  has Transform3D;
  has DynamicBody3D;
  not Prefab;
  any {
    PoisonArea;
    EnemyTrigger;
  }
}

The path-finding has two important improvements. We finally found the last piece of fixing the imported Unity NavMesh triangles that sometimes generated incorrect borders. We needed to find out what the problem was (hard part) then detect the triangles that have one vertex exactly lying on another triangles edge (fun part) and then split the triangle (easy part).

Importing Unity Navmesh Triangles
Importing Unity Navmesh Triangles

Secondly we are post-processing the raw A* path (funneling) which improves the visual quality of the chosen waypoints greatly. For this the agent will traverse through triangles rather than only its vertices. The pink path below is the raw path through the selected triangle centers. The green path is the final funneled path. It's basically an optimized line-of-sight check algorithm.

Funneling After Path Finding
Funneling After Path Finding

What else changed that I might like?

  • NavMesh.LineOfSight optionally generates a intersection point of the first border it hits.
  • NavMesh.FindClosestTriangle will perform a grid around the target search for the closest valid position inside the navmesh. This can be automatically activated when setting a navmesh agent target via NavMeshAgentConfig.FindValidTargetCellRange.
  • QuantumEditorSettings.DrawNavMesh will render the navmesh during run-time as gizmos into the scene view.
  • BreakingOnWaypoint can now be deactivated on the agent config.

NavMesh Regions are predefined areas (group of triangles and borders) in a navmesh that can deterministically be toggled on and off during run-time. Think about destroyed buildings opening up the space for walking or you want to block a passage with a wall making it impassable. The pink area in the screenshot means the region is active and can be walked on.

NavMesh Region Active
NavMesh Region Active
NavMesh Region Inactive
NavMesh Region Inactive

There is a section in the navigation manual that explains the workflow: Navigation System - Setting Up Navmesh Regions.

Toggle SimulationConfig.NavMeshAgent.IsMultithreaded to get multithreading optimization for the path-finding triggered by the agents, their steering and avoidance calculations.

Using this in conjunction with EnabledCallbacks is dangerous: because they are called from different threads only the own entity can be changed during the callback. Never anything on the Frame or other entities!

Multithreading Hazard
Multithreading Hazard

New Agent Avoidance (Experimental)

This is an interesting topic and a good example of a feature that can be fine-tailored for one specific game and its requirements into the abyss. Our original (up to 1.2.3) avoidance is a simplified influencing system that performs really well but sometimes does not have the best visual results. It still may be the best choice for a lot of games. But if you have a bit of spare computing power you may want to spend it and crank up the avoidance quality.

We use a technique that works with Velocity Obstacles which is implemented in one form or the other in every bigger game nowadays.

Experimental Avoidance
Experimental Agent Avoidance

We still want to improve this and any feedback is welcome of course.

Avoidance Quality

  • None: all avoidance deactivated
  • Low: uses the legacy avoidance system (best performance)
  • Medium: a minimum number of candidates are calculated to achieve avoidance
  • Good: a reasonable number of candidates are calculated with the best cost-benefit ratio
  • High: maximum number of collision free candidates are generated (experimental, high CPU cost)

Clamp Agent To Navmesh

When using navmesh agents without physics (UsePhysics is off) the avoidance may move then outside of the navmesh. To prevent this activate Clamp Agent To Navmesh, which moves agent back into the navmesh, just like physics would do.

  • Clamp Agent Radius Threshold will fine-tune the validation check. Agents with a radius (subtract the NavMesh.MinAgentRadius) smaller than this value use computations slightly less efficient. When you see agents with small radius still going outside try to increase this and make the correction harder.
  • Clamp Agent Correction is the percent of correction applies each tick. Increase this to make agents repelled more by borders on the cost of possible jitter.

Known Issues

Agents may jam or block each other close to waypoints which is actually not an exclusive problem to our avoidance solution but requires more efforts.

To mitigate the blocking you can play around with Reduce Avoidance At Waypoints. This will make the agents increasingly ignore the avoidance when getting close to waypoint. They would then penetrate each other but maybe that is better than blocking.

Physics

As stated in our long release notes, several new features were added to Quantum's physics engines in this update.

Some of them are simple optimization options like "LinecastOptions.FirstHitOnly" for 3D casts or toggling Edge collisions for static 2D Polygons. What follows is a more detailed description of the most interesting additions.

Friction and Restitution Combine functions

Prior to SDK 1.2.4, the physics solver had a hard-coded function to compute friction and restitution. Now you can choose between several combine functions for both features:

  • Legacy: retains the old behavior.
  • Max: the largest value between the two materials.
  • Min: the smallest value.
  • Multiply: the product of the two values.
  • Average: the average value between the two materials.

Because this is chosen per material, what would be the friction value used if the two assets have different combine functions?

We decide for precedence using the minimum value using this order: Legacy = 0, Max = 1, Min = 2, Average = 3, Multiply = 4. This makes Legacy the chosen behavior over any other function (if one of the materials use it), and so on.

Unity Terrain Exporter And Mesh Colliders

It's finally possible to export Unity MeshColliders and Terrains to Quantum static 3D triangles. They are stored inside the Map asset as a "triangle soup" that gets injected into 3D physics broadphase's initialization everytime a Map is loaded.

Quantum Terrain Collider Exporter
To export Unity Terrains as static triangles Quantum 3D Physics, just add the quantum TerrainColliderData editor component and hit bake. For 3D meshes, use the StaticMeshCollider3D component.

All narrow phase collision checks, shape overlaps and raycasts functions agains triangles were implemented, so you can expect static meshes to "just work" as intended.

Terrain Collider vs Dynamic Bodies
Terrain Collider vs Dynamic Bodies.

KCC

In addition to meshes, we added a brand new kinematic character controller (KCC) to help with, well, 3D character controlling. It is flexible enough to be either used as a complete turnkey solution, or as a more raw component as part of a custom system.

Here are the main features:

  • Uses a single fast circle overlap per tick to find surfaces, ground, etc;
  • Highly configurable (see the configuration asset below).
  • Frame.CharacterController3D.ComputeRawMovement(entity, velocity, callbacks) function returns a struct with surface normal, tangent movement vector, penetration correction, movement type (fall, slope, ground, etc) and grounded state.
  • Frame.CharacterController3D.Move(entity, velocity, callbacks) can optionally be used as a turnkey solution (internally it uses the function above).
  • Similarly, the KCC component itself has a Jump function that can be used for simple grounded-status-based jumping.
  • CharacterController3D.Init(CharacterController3DConfig config = null) should be used (the optional config param lets you have KCCs with different behaviors.

Here's a screenshot of the KCC configuration asset:

KCC Configuration Asset
Many KCC, very options.

And a short video of it in action:

KCC demo video
KCC moving through slopes and jumping.

3D Physics Performance

We are close to completing the features of the 3D physics engine, so we finally started to optimize the code for performance. Although most parts of the engine still use non-optimized code, a few pieces are already much faster due to the following recent changes:

  • Inlining of all functions related to FPQuaternion (FPQuaternion multiplication to FPVector3 was a major bottleneck in our profiling tests) and some from FPVector3.
  • Per-tick caching of some reusable values inside the auxiliary entity struct over the physics update function (this avoids recomputation every time the value is needed during the same tick's update).

Overall, the performance of the 3D physics engine will still improve a lot, and we expect to have the fully inlined version when we release SDK 1.2.4 R1 or R2.

The other benefit of this is that your code that uses FPQuaternion and FPVector3 will also run faster now that most operations are inlined in those math structs.

Back to top