NPC Plugins
Non ego traffic vehicles (NPCs) are plugins that have the ability to be customized in appearance and behavior in your simulations. This allows you to add local variations of vehicle styles and brands or implement encounters with vehicles displaying distinguished behaviors, such as erratic driving or vehicles stopping frequently (e.g., delivery vehicles, trash pick up, bicycles).
NOTE: Default NPCs are no longer included in simulator source and must be built locally from source for custom binaries. See build instructions.
Table of Contents
NPC Models top#
NPC Models allow customization of NPC visuals, most notably the 3D model of vehicles, but also the material used for the car paint or windows. With supporting custom NPC models we also added the support for motorbikes and vehicles with more two axles as well as more than one steering axle as is found on heavy vehicles.
NPC models must include a named Collider
node that is a simplified mesh to attach a Unity mesh collider. The mesh renderer is NOT active and the collider must be marked Convex.
We classify NPCs into size categories which decide the spawning frequency as well as which paint colors are more common for which NPC size type. The following table lists all currently implemented size types and the weight that correlates to their relative probability of encountering this type.
NPC Size Type | Spawn Weight |
---|---|
Compact | 5 |
MidSize | 6 |
Luxury | 2 |
Sport | 1 |
LightTruck | 2 |
SUV | 4 |
MiniVan | 3 |
Large | 2 |
Emergency | 1 |
Bus | 1 |
Trailer | 0 |
Motorcycle | 1 |
Bicycle | 1 |
In this example, trailer type has a weight of zero, indicating that it should not spawn by itself, while MidSize type has the highest weight, indicating that it is the most frequent vehicle on the road. The NPC Type is configured via a Component added to the root of the prefab.
Similarly, colors for each spawned vehicle is picked from a table for each vehicle type.
NPC asset bundles are detected from <simulator installation path>/AssetBundles/NPCs
and added to the simulation automatically.
NPC Animations top#
NPC animations are supported in SVL Simulator. They must be included in the model data and require an AnimationController.controller asset. This controller is the animation state machine that is referenced in the Animator component on the model root object.
In the animation controller, the animation parameter named speed
must be setup and set as a transition condition. With this parameter, npc animation speed and transitions can be effected by the npc rigidbody speed. This is the only default parameter supported in the npc controller.
Building NPC Plugins top#
NPCs can be grouped into collections to allow you to import regional collections of vehicles. Place NPCs in Assets/External/NPCs/CollectionFolder/
in separate named folders to have all CollectionFolder
vehicles show up in the build menu in a group.
To build an external NPC,
- Open
Simulator -> Build...
menu item - Select an NPC in the build window
- Click
Build
The bundle named npc_XXX
will be placed in the AssetBundles/NPCs/CollectionFolder
folder in source code. This is where simulator loads NPC bundles at runtime. To have NPCs load in a binary, they must be placed in the AssetBundles/NPCs/ folder in that binary.
See build instructions for more details.
NPC Behaviors top#
NPC Behaviors allow NPC Vehicles to behave in custom ways different from the provided built-in NPC behavior and are enabled and configured through the Python API.
Before running the simulator (running the executable or pressing Play
in the Editor) NPC behavior plugins must be built by the simulator using Simulator -> Build...
menu and the built asset placed in the AssetBundles/NPCs
folder in the source code or binary.
Open-source example:
Creating NPC Behavior Plugins top#
Create a folder in under your collection folder for each behavior, eg. Assets/External/NPCs/BehavioursNPC/DrunkDriver/
.
If your plugin is a pure behavior, that is it has no visual components, we require one C# file to have the same name as the folder under the collection folder, for example note how the name DrunkDriver
repeats in both the folder name and file name: Assets/External/NPCs/BehavioursNPC/DrunkDriver/DrunkDriver.cs
.
The main class has to inherit from NPCBehaviourBase
and implement its abstract methods to hook into the NPC simulation framework. It is also possible to inherit from NPCLaneFollowingBehaviour
if you want to implement a slight modification of the default lane following behavior, such as this simple DrunkDriver
example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Simulator.Api;
using Simulator.Map;
using Simulator.Utilities;
using SimpleJSON;
// In this example, we try to simulate a driver under ther influence of alcohol.
// We modify the default NPCLaneFollowingBehaviour because in principle this behavior
// shuld just add variation the the default behavior.
public class NPCDrunkDriverBehaviour : NPCLaneFollowBehaviour
{
public float steerCorrectionMinTime = 0.0f;
public float steerCorrectionMaxTime = 0.4f;
public float steerDriftMin = 0.00f;
public float steerDriftMax = 0.09f;
protected float currentSteerDrift = 0.0f;
protected float nextSteerCorrection = 0;
// This function in the base class controls the NPC steering
protected override void SetTargetTurn()
{
// we reduce the frequency at which steering is updated to the target heading to
// simulate loss of attention or reduced reaction time
if(nextSteerCorrection < Time.fixedTime)
{
float steerCorrectionIn = RandomGenerator.NextFloat(steerCorrectionMinTime, steerCorrectionMaxTime);
nextSteerCorrection = Time.fixedTime + steerCorrectionIn;
// we add drift to the steering to simulate loss of fine motor skills
currentSteerDrift = RandomGenerator.NextFloat(steerDriftMin, steerDriftMax);
currentSteerDrift = currentSteerDrift * Mathf.Abs(RandomGenerator.NextFloat(-1.0f, 1.0f));
// we can reuse the base steering at reduced frequency
base.SetTargetTurn();
}
else
{
// steering drift correlating to driving speed
currentTurn += currentSteerDrift * currentSpeed;
}
}
}
If you want to configure aspects of your NPC behavior from the Python API, you can add a class implementing the ICommand
interface as shown in this example:
class DrunkDriverControl : ICommand
{
public string Name => "agent/drunk/config";
public void Execute(JSONNode args)
{
var uid = args["uid"].Value;
var api = ApiManager.Instance;
if (!api.Agents.TryGetValue(uid, out GameObject npc))
{
api.SendError(this, $"Agent '{uid}' not found");
return;
}
var behaviour = npc.GetComponent<NPCDrunkDriverBehaviour>();
if (behaviour == null)
{
api.SendError(this, $"Agent '{uid}' is not a drunk driving NPC agent");
return;
}
if(args.HasKey("correctionMinTime")) behaviour.steerCorrectionMinTime = args["correctionMinTime"].AsFloat;
if(args.HasKey("correctionMaxTime")) behaviour.steerCorrectionMaxTime = args["correctionMaxTime"].AsFloat;
if(args.HasKey("steerDriftMin")) behaviour.steerDriftMin = args["steerDriftMin"].AsFloat;
if(args.HasKey("steerDriftMax")) behaviour.steerDriftMax = args["steerDriftMax"].AsFloat;
api.SendResult(this);
}
}
example usage from Python:
# common setup code omitted, check PythonAPI/quickstart for examples
# you can check if it has been loaded:
behaviours = sim.available_npc_behaviours
for i in range(len(behaviours)):
if behaviours[i]["name"]=="NPCDrunkDriverBehaviour": drunkDriverAvailable = True
#later...
npc = sim.add_agent(agent, lgsvl.AgentType.NPC, state)
if drunkDriverAvailable:
inp = input("make drunk driver? yN")
if (inp == "y" or inp == "Y"):
npc.set_behaviour("NPCDrunkDriverBehaviour")
# usage of example command from C# plugin.
npc.remote.command("agent/drunk/config", { "uid": npc.uid, "correctionMinTime":0.0, "correctionMaxTime":0.6, "steerDriftMin": 0.00, "steerDriftMax":0.09})
# can still use lane following methods as those are inherited
npc.follow_closest_lane(True, 5.6)
Creating NPC Model Plugins top#
Create a folder under your collection folder for each Model, eg. Assets/External/NPCs/YourCollection/YourNPC/
.
All assets of a NPC such as textures, additional materials or scripts are expected to live inside its folder.
When an NPC is spawned, a NPCController script is attached to the root of the prefab instance, and it will try to find several components to animate the vehicle. To identify the components, we look at the Name property of the Components as follows:
GameObject Name | Component Type | Description |
---|---|---|
LightHeadLeft | Light | Headlights which are controlled by the NPCController to off, regular, high beam etc states |
LightHeadRight | Light | Headlights which are controlled by the NPCController to off, regular, high beam etc states |
LightBrakeLeft | Light | Braking lights, controlled by the NPCController to reflect the vehicle braking |
LightBrakeRight | Light | Braking lights, controlled by the NPCController to reflect the vehicle braking |
IndicatorLeftFront | Light | Left indicator lights controlled by the NPCController when turning or when hazard lights are on |
IndicatorLeftRear | Light | Left indicator lights controlled by the NPCController when turning or when hazard lights are on |
IndicatorRightFront | Light | Right indicator lights controlled by the NPCController when turning or when hazard lights are on |
IndicatorRightRear | Light | Right indicator lights controlled by the NPCController when turning or when hazard lights are on |
IndicatorReverse | Light | Light turns on when NPC is reversing |
Body | Renderer | Main vehicle body mesh |
Body | Material | Material will have its _BaseColor changed to give each NPC a random color from a list |
Collider | Renderer | Simplified collision mesh set to convex and less than 256 polygons |
LightHead | Material | Material which is controlled to emit light in conjunction with headlight Lights |
LightBrake | Material | Material which is controlled to emit light in conjunction with brake Lights |
IndicatorLeft | Material | Material which is controlled to emit light in conjunction with left indicator Lights |
IndicatorRight | Material | Material which is controlled to emit light in conjunction with right indicator Lights |
IndicatorReverse | Material | Material which is controlled to emit light in conjunction with reversing Light |
Wheel | Renderer | Renderer is used to create WheelCollider. NPCs with less than four wheels are assumed to be bikes |
"Wheel" and "Front" or "Rear" | Renderer | Wheels that are supposed to turn when steering |
NPC Meta Data top#
Additional information about the NPC prefab is added by attaching a Unity MonoBehaviour
Component called NPCMetaData
added to each prefab.