Skip to content

HappySapeta/TrafficAI

Repository files navigation

Traffic AI

A traffic simulation model developed in Unreal Engine 5.

Inspired by modern open-world video games, this project was developed to learn the basics of a large-scale real-time traffic simulation.

Please note, that TrafficAI does not use UE5's Mass Entity Framework. The goal was to learn about AI used in games and employ strategies that help simulate on a large scale. Hence, a custom Data-Oriented-Design approach was favored against an existing framework.

Bird's eye view demo - Simulating 100 vehicles.

birds_eye_view.mp4

Core Systems

Behind the scenes, the simulation is managed by two core systems - TrRepresentationSystem and TrSimulationSystem.

  1. TrSimulationSystem
    • It is the brain of the simulation and is responsible for driving all autonomous vehicles. For each vehicle, TrSimulationSystem uses the Kinematic Bicycle Model to steer and move the vehicle, Intelligent Driver Model (IDM) to determine a safe acceleration value to prevent collision against the leading vehicle and Craig Reynold's path following algorithm to keep the vehicle on track.
    • Additionally, for each vehicle, it queries vehicles in the vicinity and filters those on a direct course of collision.
    • Although no collision avoidance maneuvers are applied, the braking effect caused by the IDM is enough to prevent head-on collisions.
    • The system also employs another system called TrIntersectionManager that simulates traffic signals by periodically blocking certain nodes at intersections while allowing the passage of traffic from the rest of the nodes.
    • Last but not least, TrSimulationSystem is based on a DOD solution that treats vehicles as numerical entities. It incorporates multiple arrays of floating point values that define the state of each entity. This plays a major role in making the simulation run on the CPU at respectable framerates. The following values are used to define the state of a vehicle/entity: Position, Velocity, Acceleration, Heading, Goal (the location the vehicle is supposed to go to), and some metadata values such as the index of the vehicle directly in front of the current vehicle, and information about its current path.
  2. TrRepresentationSystem
    • No matter how realistic an AI system becomes, in most games it becomes useless if it cannot be interacted with.
    • This system allows players to interact with the vehicles without taxing the CPU too much.
    • Each vehicle has two LODs. One with the least amount of detail is represented with an Instanced Static Mesh while the other with the highest amount of detail is represented by an actor.
    • Actors can be controlled by players and can physically interact with the world and other vehicles.
    • TrRepresentationSystem seamlessly swaps ISMCs with Actors and vice-versa as they come in and out of range of the player.
    • While ISMCs are moved by directly overriding their position & orientation received from TrSimulationSystem, actors are moved by a more sophisticated system.
    • Vehicle Actors are types of AWheeledVehiclePawn derived from UE's Chaos Vehicle System. A PID Controller is used, to determine the magnitude and direction of the force required to anchor the vehicle to the desired position and steer the vehicle's actor to match its orientation, to the values received from the simulation system.

Collision Avoidance and Path Following Demo

intersection.mp4

Collison Avoidance

In TrafficAI, vehicles don't actively try to avoid obstacles or other vehicles by using specialized maneuvers. Instead, they detect vehicles that are directly in front of them and choose the one that poses the greatest risk of collision. They then apply brakes to prevent an imminent collision.

Detecting objects in the surroundings can be a challenging task, especially if we want to avoid doing too many comparisons. To solve this problem, a spatial acceleration structure called Implicit Grid was used, which allows us to query nearby vehicles very quickly.

After the query is complete, a mathematical operation using the position of each queried vehicle is performed to determine which vehicles overlap against the sensing region of the current vehicle. Here's how it has been implemented in TrafficAI -

const FVector& CurrentPosition = Positions[Index];
const FVector EndPosition = CurrentPosition + Headings[Index] * VehicleConfig.CollisionSensorRange;
ImplicitGrid.LineSearch(CurrentPosition, EndPosition, Results);
LeadingVehicleIndices[Index] = -1;
float ClosestDistance = TNumericLimits<float>().Max();
FTransform CurrentTransform(Headings[Index].ToOrientationRotator(), CurrentPosition);
uint8 Count = Results.Num();
for(auto Itr = Results.Array.begin(); Count > 0; --Count, ++Itr)
{
const FVector& OtherPosition = Positions[*Itr];
const FVector OtherLocalVector = CurrentTransform.InverseTransformPosition(OtherPosition);
if(OtherLocalVector.Y >= -Bound && OtherLocalVector.Y <= Bound)
{
const float Distance = OtherLocalVector.X;
if(Distance > 0.0f && Distance < ClosestDistance)
{
ClosestDistance = Distance;
LeadingVehicleIndices[Index] = *Itr;
}
}
}
It is a straightforward procedure that converts a world position into a relative local position relative to the sensing vehicle's position and heading, and verifies if it falls within the collision boundaries of the vehicle.

This, by far is the most time-consuming operation in the entire simulation update. Any efforts to further optimize the system must be focussed on this region in UTrSimulationSystem::UpdateCollisionData

Path Following

TrafficAI uses a slightly modified version of Craig Reynolds' Path Following algorithm. It uses the distance between the vehicle's current position and projected position to decide if it's on track or off.

const FVector FutureOnPath = ProjectPointOnPathClamped(Future, OffsetPath);
const FVector PositionOnPath = ProjectPointOnPathClamped(Positions[Index], OffsetPath);
const float Distance = FVector::Distance(Positions[Index], PositionOnPath);
if (Distance < PathFollowingConfig.PathFollowThreshold)
{
Goals[Index] = OffsetPath.End;
PathFollowingStates[Index] = true;
}
else
{
Goals[Index] = FutureOnPath;
PathFollowingStates[Index] = false;
}

References

Requirements

Unreal Engine 5.2+

Note

The paid assets used in the demonstrations are not included in the repository but can be found at Polygon - City Pack.

About

Large Scale Traffic Simulation model made with UE5.

Topics

Resources

Stars

Watchers

Forks