From 3a75f8eef97013a3f04a756f7f5070f73ab7ef64 Mon Sep 17 00:00:00 2001 From: Xu Yuanshan Date: Fri, 11 Sep 2026 19:21:17 +0800 Subject: [PATCH 1/2] Register spawnObject actors for instance GT and materials.csv stencil. Co-authored-by: Cursor --- Unreal/Plugins/AirSim/Source/WorldSimApi.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp index 1df0dea0d..fed6484c3 100644 --- a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp +++ b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp @@ -8,6 +8,7 @@ #include "Runtime/Engine/Classes/Components/LineBatchComponent.h" #include "Runtime/Engine/Classes/Engine/Engine.h" #include "Misc/OutputDeviceNull.h" +#include "Misc/FileHelper.h" #include "ImageUtils.h" #include #include @@ -133,6 +134,18 @@ std::string WorldSimApi::spawnObject(const std::string& object_name, const std:: if (IsValid(NewActor)) { spawned_object = true; simmode_->scene_object_map.Add(FString(final_object_name.c_str()), NewActor); + // Dynamically spawned actors were missing UnrealCV RGB888 instance paint and + // materials.csv custom-depth stencil (needed for GPU LiDAR intensity / GT). + // Docs already require AddNewActorToSegmentation for runtime spawns. + simmode_->AddNewActorToInstanceSegmentation(NewActor, true); + FString materialListContent; + const auto& material_list_file = + msr::airlib::AirSimSettings::singleton().material_list_file; + if (FFileHelper::LoadFileToString( + materialListContent, + UTF8_TO_TCHAR(material_list_file.c_str()))) { + UAirBlueprintLib::InitializeMeshStencilIDs(true, materialListContent); + } } UAirBlueprintLib::setSimulatePhysics(NewActor, physics_enabled); From 78df09e67ae6a2269de627db66d9643947209f57 Mon Sep 17 00:00:00 2001 From: jcfurey Date: Sat, 3 Oct 2026 18:15:51 -0500 Subject: [PATCH 2/2] Keep cars and skid-steer vehicles that fall out of the world A vehicle that drops below the level's KillZ, for example driven off the edge of the map or pushed through the floor after a collision, is destroyed by the engine. AirSim keeps using the pawn, so the next sim update or reset crashes (PawnSimApi::updateKinematics from CarPawnSimApi::updateRenderedState). CarPawn and SkidVehiclePawn now override FellOutOfWorld to keep the vehicle, log a warning, and move it back to its start pose on the next tick, with its velocities zeroed. The teleport happens in Tick because FellOutOfWorld is called from the physics sync, which overrides a teleport made there. Found and tested in HERCULES (a fork of Cosys-AirSim) with Unreal Engine 5.8.3: a car teleported 500 m to 11 km below the Blocks map is back at its start pose within 0.3 s and the simulation and reset() keep working. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01JmWqXFCY6vDdpRe4VHoaQX --- .../AirSim/Source/Vehicles/Car/CarPawn.cpp | 26 +++++++++++++++++++ .../AirSim/Source/Vehicles/Car/CarPawn.h | 6 +++++ .../Vehicles/SkidSteer/SkidVehiclePawn.cpp | 26 +++++++++++++++++++ .../Vehicles/SkidSteer/SkidVehiclePawn.h | 6 +++++ 4 files changed, 64 insertions(+) diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp index ccf326da2..358f7664d 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp @@ -240,9 +240,34 @@ void ACarPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void ACarPawn::FellOutOfWorld(const UDamageType& dmgType) +{ + // The engine destroys actors that drop below the level's KillZ, but AirSim keeps using its + // vehicle pawns and crashes on a destroyed one. Keep the vehicle and put it back at its start + // pose on the next tick: this is called from the physics sync, which overrides a teleport here. + if (!fell_out_of_world_) { + UE_LOG(LogTemp, Warning, TEXT("%s fell out of the world; moving it back to its start pose"), *GetName()); + UAirBlueprintLib::LogMessage(GetName(), TEXT("fell out of the world and was moved back to its start pose"), LogDebugLevel::Failure); + } + fell_out_of_world_ = true; +} + +void ACarPawn::respawnIfFellOutOfWorld() +{ + if (!fell_out_of_world_) + return; + fell_out_of_world_ = false; + for (UPrimitiveComponent* phys_comp : UAirBlueprintLib::getPhysicsComponents(this)) { + phys_comp->SetPhysicsLinearVelocity(FVector::ZeroVector); + phys_comp->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector); + } + SetActorTransform(start_transform_, false, nullptr, ETeleportType::TeleportPhysics); +} + void ACarPawn::Tick(float Delta) { Super::Tick(Delta); + respawnIfFellOutOfWorld(); // update physics material updatePhysicsMaterial(); @@ -264,6 +289,7 @@ void ACarPawn::Tick(float Delta) void ACarPawn::BeginPlay() { Super::BeginPlay(); + start_transform_ = GetActorTransform(); // Start an engine sound playing engine_sound_audio_->Play(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h index f8637b7bc..50447b892 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h +++ b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h @@ -37,6 +37,7 @@ class ACarPawn : public AWheeledVehiclePawn virtual void BeginPlay() override; virtual void Tick(float Delta) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void FellOutOfWorld(const class UDamageType& dmgType) override; virtual void NotifyHit(class UPrimitiveComponent* MyComp, class AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) override; @@ -53,6 +54,11 @@ class ACarPawn : public AWheeledVehiclePawn return keyboard_controls_; } +private: + void respawnIfFellOutOfWorld(); + FTransform start_transform_; + bool fell_out_of_world_ = false; + private: void updateHUDStrings(); void setupVehicleMovementComponent(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp index 917a9b768..e083e22ae 100755 --- a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp @@ -244,9 +244,34 @@ void ASkidVehiclePawn::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void ASkidVehiclePawn::FellOutOfWorld(const UDamageType& dmgType) +{ + // The engine destroys actors that drop below the level's KillZ, but AirSim keeps using its + // vehicle pawns and crashes on a destroyed one. Keep the vehicle and put it back at its start + // pose on the next tick: this is called from the physics sync, which overrides a teleport here. + if (!fell_out_of_world_) { + UE_LOG(LogTemp, Warning, TEXT("%s fell out of the world; moving it back to its start pose"), *GetName()); + UAirBlueprintLib::LogMessage(GetName(), TEXT("fell out of the world and was moved back to its start pose"), LogDebugLevel::Failure); + } + fell_out_of_world_ = true; +} + +void ASkidVehiclePawn::respawnIfFellOutOfWorld() +{ + if (!fell_out_of_world_) + return; + fell_out_of_world_ = false; + for (UPrimitiveComponent* phys_comp : UAirBlueprintLib::getPhysicsComponents(this)) { + phys_comp->SetPhysicsLinearVelocity(FVector::ZeroVector); + phys_comp->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector); + } + SetActorTransform(start_transform_, false, nullptr, ETeleportType::TeleportPhysics); +} + void ASkidVehiclePawn::Tick(float Delta) { Super::Tick(Delta); + respawnIfFellOutOfWorld(); USkeletalMeshComponent* mesh = CastChecked(getVehicleMesh()); if (mesh->GetPhysicsAngularVelocityInDegrees().Size() > max_angular_velocity_) @@ -274,6 +299,7 @@ void ASkidVehiclePawn::Tick(float Delta) void ASkidVehiclePawn::BeginPlay() { Super::BeginPlay(); + start_transform_ = GetActorTransform(); // Start an engine sound playing engine_sound_audio_->Play(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h index ebae31912..0ef0b2c3f 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h +++ b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h @@ -37,6 +37,7 @@ class ASkidVehiclePawn : public AWheeledVehiclePawn virtual void BeginPlay() override; virtual void Tick(float Delta) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void FellOutOfWorld(const class UDamageType& dmgType) override; virtual void NotifyHit(class UPrimitiveComponent* MyComp, class AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) override; @@ -64,6 +65,11 @@ class ASkidVehiclePawn : public AWheeledVehiclePawn UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SkidVehicle|General") bool stop_turn_ = false; +private: + void respawnIfFellOutOfWorld(); + FTransform start_transform_; + bool fell_out_of_world_ = false; + private: void updateHUDStrings(); void setupVehicleMovementComponent();