Merge remote-tracking branch 'origin/nestor' into xisco
This commit is contained in:
commit
bdfbf53670
|
@ -0,0 +1,32 @@
|
|||
## CARLA 0.2.3
|
||||
|
||||
* Fixed rounding errors in HUD (100% was shown as 99%, 30 FPS as 29 FPS).
|
||||
* Fixed crash when player goes out of road map.
|
||||
* Fixed several issues related to the transform of the road map (wasn't working in CARLA_ORIGIN_1).
|
||||
|
||||
## CARLA 0.2.2
|
||||
|
||||
* Implemented signals for off-road and opposite lane invasion
|
||||
* Fixed linking issues (use Unreal's libpng)
|
||||
* Fixed memory leak in PNG compression
|
||||
|
||||
## CARLA 0.2.1
|
||||
|
||||
* Fixed the memory leak related to protobuf issues
|
||||
* Fixed color shift in semantic segmentation and depth
|
||||
* Added in-game timestamp (now sending both OS and in-game)
|
||||
|
||||
## CARLA 0.2.0
|
||||
|
||||
* Fixed Depth issues
|
||||
* Added semantic segmentation
|
||||
* Changed codification to PNG
|
||||
* Camera configuration through config INI file
|
||||
|
||||
## CARLA 0.1.1
|
||||
|
||||
* Added build system for Windows and Linux
|
||||
|
||||
## CARLA 0.1.0
|
||||
|
||||
* Added basic functionality
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "0.2.1",
|
||||
"VersionName": "0.2.3",
|
||||
"FriendlyName": "CARLA",
|
||||
"Description": "",
|
||||
"Category": "Science",
|
||||
|
|
|
@ -3,6 +3,8 @@ CARLA UE4 Plugin
|
|||
|
||||
Plugin for Unreal Engine 4.
|
||||
|
||||
See [CHANGELOG](CHANGELOG.md).
|
||||
|
||||
Settings
|
||||
--------
|
||||
|
||||
|
|
|
@ -9,3 +9,14 @@ Other CARLA related command-line options
|
|||
|
||||
* `-carla-settings=<ini-file-path>` Load settings from the given INI file. See Example.CarlaSettings.ini.
|
||||
* `-world-port=<port-number>` Listen for client connections at <port-number>, write and read ports are set to <port-number>+1 and <port-number>+2 respectively.
|
||||
|
||||
To activate semantic segmentation
|
||||
---------------------------------
|
||||
|
||||
In the config file `CarlaUE4/Saved/Config/LinuxNoEditor/Engine.ini`, add the
|
||||
following
|
||||
|
||||
```
|
||||
[/Script/Engine.RendererSettings]
|
||||
r.CustomDepth=3
|
||||
```
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
#include "CityMapGenerator.h"
|
||||
|
||||
#include "MapGen/GraphGenerator.h"
|
||||
#include "MapGen/RoadMap.h"
|
||||
#include "Tagger.h"
|
||||
|
||||
#include "Components/InstancedStaticMeshComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Paths.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -16,35 +22,59 @@
|
|||
// =============================================================================
|
||||
|
||||
ACityMapGenerator::ACityMapGenerator(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer) {}
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
RoadMap = ObjectInitializer.CreateDefaultSubobject<URoadMap>(this, TEXT("RoadMap"));
|
||||
}
|
||||
|
||||
ACityMapGenerator::~ACityMapGenerator() {}
|
||||
|
||||
// =============================================================================
|
||||
// -- Map construction and update related methods ------------------------------
|
||||
// -- Overriden from UObject ---------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACityMapGenerator::UpdateMap() {
|
||||
void ACityMapGenerator::PreSave(const ITargetPlatform *TargetPlatform)
|
||||
{
|
||||
if (bGenerateRoadMapOnSave) {
|
||||
check(RoadMap != nullptr);
|
||||
GenerateRoadMap();
|
||||
}
|
||||
|
||||
Super::PreSave(TargetPlatform);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Overriden from ACityMapMeshHolder ----------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACityMapGenerator::UpdateMap()
|
||||
{
|
||||
UpdateSeeds();
|
||||
GenerateGraph();
|
||||
if (bGenerateRoads) {
|
||||
GenerateRoads();
|
||||
}
|
||||
if (bTriggerRoadMapGeneration) {
|
||||
bTriggerRoadMapGeneration = false;
|
||||
GenerateRoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void ACityMapGenerator::UpdateSeeds() {
|
||||
// =============================================================================
|
||||
// -- Map construction and update related methods ------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACityMapGenerator::UpdateSeeds()
|
||||
{
|
||||
if (!bUseFixedSeed) {
|
||||
bUseMultipleFixedSeeds = false;
|
||||
FRandomStream randomStream;
|
||||
randomStream.GenerateNewSeed();
|
||||
Seed = randomStream.GetCurrentSeed();
|
||||
}
|
||||
if (!bUseMultipleFixedSeeds) {
|
||||
RoadPlanningSeed = Seed;
|
||||
}
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateGraph() {
|
||||
void ACityMapGenerator::GenerateGraph()
|
||||
{
|
||||
if ((MapSizeX < 5u) || (MapSizeY < 5u)) {
|
||||
MapSizeX = 5u;
|
||||
MapSizeY = 5u;
|
||||
|
@ -54,7 +84,7 @@ void ACityMapGenerator::GenerateGraph() {
|
|||
// Delete the dcel before the new one is created so indices are restored.
|
||||
Dcel.Reset(nullptr);
|
||||
#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
|
||||
Dcel = MapGen::GraphGenerator::Generate(MapSizeX, MapSizeY, RoadPlanningSeed);
|
||||
Dcel = MapGen::GraphGenerator::Generate(MapSizeX, MapSizeY, Seed);
|
||||
UE_LOG(LogCarla, Log,
|
||||
TEXT("Generated DCEL with: { %d vertices, %d half-edges, %d faces }"),
|
||||
Dcel->CountNodes(),
|
||||
|
@ -87,7 +117,8 @@ void ACityMapGenerator::GenerateGraph() {
|
|||
#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateRoads() {
|
||||
void ACityMapGenerator::GenerateRoads()
|
||||
{
|
||||
check(Dcel != nullptr);
|
||||
using Graph = MapGen::DoublyConnectedEdgeList;
|
||||
const Graph &graph = *Dcel;
|
||||
|
@ -157,3 +188,115 @@ void ACityMapGenerator::GenerateRoads() {
|
|||
|
||||
#undef ADD_INTERSECTION
|
||||
}
|
||||
|
||||
// Find first component of type road (checking at its stencil value).
|
||||
static bool LineTrace(
|
||||
UWorld *World,
|
||||
const FVector &Start,
|
||||
const FVector &End,
|
||||
FHitResult &HitResult)
|
||||
{
|
||||
TArray <FHitResult> OutHits;
|
||||
static FName TraceTag = FName(TEXT("RoadTrace"));
|
||||
const bool Success = World->LineTraceMultiByObjectType(
|
||||
OutHits,
|
||||
Start,
|
||||
End,
|
||||
FCollisionObjectQueryParams(ECollisionChannel::ECC_WorldDynamic),
|
||||
FCollisionQueryParams(TraceTag, true));
|
||||
|
||||
if (Success) {
|
||||
for (FHitResult &Item : OutHits) {
|
||||
if (Item.Component->CustomDepthStencilValue == static_cast<uint8>(CityObjectLabel::Roads)) {
|
||||
HitResult = Item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateRoadMap()
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Generating road map..."));
|
||||
|
||||
auto World = GetWorld();
|
||||
check(GetWorld() != nullptr);
|
||||
check(RoadMap != nullptr);
|
||||
|
||||
ATagger::TagActorsInLevel(*GetWorld()); // We need the tags.
|
||||
|
||||
const float IntersectionSize = CityMapMeshTag::GetRoadIntersectionSize();
|
||||
const uint32 Margin = IntersectionSize / 2u;
|
||||
const float Offset = GetMapScale() * Margin;
|
||||
|
||||
const float CmPerPixel = GetMapScale() / static_cast<float>(PixelsPerMapUnit);
|
||||
|
||||
const uint32 SizeX = PixelsPerMapUnit * (MapSizeX + 2u * Margin);
|
||||
const uint32 SizeY = PixelsPerMapUnit * (MapSizeY + 2u * Margin);
|
||||
|
||||
const FTransform &ActorTransform = GetActorTransform();
|
||||
|
||||
RoadMap->RoadMap.Empty();
|
||||
for (uint32 PixelY = 0u; PixelY < SizeY; ++PixelY) {
|
||||
for (uint32 PixelX = 0u; PixelX < SizeX; ++PixelX) {
|
||||
const float X = static_cast<float>(PixelX) * CmPerPixel - Offset;
|
||||
const float Y = static_cast<float>(PixelY) * CmPerPixel - Offset;
|
||||
const FVector Start = ActorTransform.TransformPosition(FVector(X, Y, 50.0f));
|
||||
const FVector End = ActorTransform.TransformPosition(FVector(X, Y, -50.0f));
|
||||
|
||||
bool Success = false;
|
||||
|
||||
// Do the ray tracing.
|
||||
FHitResult Hit;
|
||||
if (LineTrace(World, Start, End, Hit)) {
|
||||
auto InstancedStaticMeshComponent = Cast<UInstancedStaticMeshComponent>(Hit.Component.Get());
|
||||
if (InstancedStaticMeshComponent == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Road component is not UInstancedStaticMeshComponent"));
|
||||
} else {
|
||||
FTransform InstanceTransform;
|
||||
if (!InstancedStaticMeshComponent->GetInstanceTransform(Hit.Item, InstanceTransform, true)) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to get instance's transform"));
|
||||
} else {
|
||||
RoadMap->AppendPixel(
|
||||
GetTag(*InstancedStaticMeshComponent->GetStaticMesh()),
|
||||
InstanceTransform,
|
||||
bLeftHandTraffic);
|
||||
Success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Success) {
|
||||
RoadMap->AppendEmptyPixel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FVector MapOffset(-Offset, -Offset, 0.0f);
|
||||
RoadMap->Set(SizeX, SizeY, 1.0f / CmPerPixel, ActorTransform.Inverse(), MapOffset);
|
||||
const float MapSizeInMB = // Only map data, not the class itself.
|
||||
static_cast<float>(sizeof(FRoadMapPixelData) * RoadMap->RoadMap.Num()) /
|
||||
(1024.0f * 1024.0f);
|
||||
UE_LOG(
|
||||
LogCarla,
|
||||
Log,
|
||||
TEXT("Generated road map %dx%d (%.2fMB) with %.2f cm/pixel"),
|
||||
RoadMap->GetWidth(),
|
||||
RoadMap->GetHeight(),
|
||||
MapSizeInMB,
|
||||
CmPerPixel);
|
||||
|
||||
if (!RoadMap->IsValid()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Error generating road map"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bSaveRoadMapToDisk) {
|
||||
const FString MapName = World->GetMapName() + TEXT(".png");
|
||||
const FString FilePath = FPaths::Combine(FPaths::GameSavedDir(), MapName);
|
||||
RoadMap->SaveAsPNG(FilePath);
|
||||
}
|
||||
|
||||
RoadMap->DrawDebugPixelsToLevel(GetWorld(), !bDrawDebugPixelsToLevel);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#include "MapGen/GraphParser.h"
|
||||
#include "CityMapGenerator.generated.h"
|
||||
|
||||
class URoadMap;
|
||||
|
||||
/// Generates a random city using the meshes provided.
|
||||
///
|
||||
/// @note At this point it only generates roads and sidewalks.
|
||||
UCLASS(HideCategories=(Rendering, Input))
|
||||
UCLASS(HideCategories=(Input,Rendering,Actor))
|
||||
class CARLA_API ACityMapGenerator : public ACityMapMeshHolder
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
@ -27,14 +29,42 @@ public:
|
|||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Map construction and update related methods
|
||||
/// @name Overriden from UObject
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
public:
|
||||
|
||||
virtual void PreSave(const ITargetPlatform *TargetPlatform) override;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Overriden from ACityMapMeshHolder
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
private:
|
||||
|
||||
/// Update the map based on the current settings.
|
||||
virtual void UpdateMap() override;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Road map
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
URoadMap *GetRoadMap()
|
||||
{
|
||||
return RoadMap;
|
||||
}
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Map construction and update related methods
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
private:
|
||||
|
||||
/// Update the random seeds. Generate random if no fixed seed is used.
|
||||
void UpdateSeeds();
|
||||
|
||||
|
@ -44,6 +74,9 @@ private:
|
|||
/// Add the road meshes to the scene based on the current DCEL.
|
||||
void GenerateRoads();
|
||||
|
||||
/// Generate the road map image and save to disk if requested.
|
||||
void GenerateRoadMap();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Map generation properties
|
||||
|
@ -51,33 +84,76 @@ private:
|
|||
/// @{
|
||||
private:
|
||||
|
||||
/** Size X of the map in map units. The map unit is calculated based in the
|
||||
* tile mesh of the road (see Map Scale).
|
||||
*/
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere, meta = (ClampMin = "10", ClampMax = "200"))
|
||||
uint32 MapSizeX = 20u;
|
||||
|
||||
/** Size Y of the map in map units. The map unit is calculated based in the
|
||||
* tile mesh of the road (see Map Scale).
|
||||
*/
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere, meta = (ClampMin = "10", ClampMax = "200"))
|
||||
uint32 MapSizeY = 20u;
|
||||
|
||||
/** If false, no mesh is added, only the internal representation of road is
|
||||
* generated.
|
||||
*/
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere)
|
||||
bool bGenerateRoads = true;
|
||||
|
||||
/** If false, a random seed is generated each time. */
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere)
|
||||
bool bUseFixedSeed = true;
|
||||
|
||||
/** Seed of the random map generated. */
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere, meta = (EditCondition = bUseFixedSeed))
|
||||
int32 Seed = 123456789;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Map generation properties - advance display
|
||||
/// @name Road Map
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
private:
|
||||
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere, AdvancedDisplay, meta = (EditCondition = bUseFixedSeed))
|
||||
bool bUseMultipleFixedSeeds = false;
|
||||
/** Trigger the generation a the road map image of the current layout (used
|
||||
* for off-road and opposite lane invasion detection).
|
||||
*/
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere)
|
||||
bool bTriggerRoadMapGeneration = false;
|
||||
|
||||
UPROPERTY(Category = "Map Generation", EditAnywhere, AdvancedDisplay, meta = (EditCondition = bUseMultipleFixedSeeds))
|
||||
int32 RoadPlanningSeed;
|
||||
/** The resolution in pixels per map unit of the road map. The map unit is
|
||||
* calculated based in the tile mesh of the road (see Map Scale).
|
||||
*/
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere, meta = (ClampMin = "1", ClampMax = "500"))
|
||||
uint32 PixelsPerMapUnit = 50u;
|
||||
|
||||
/** Whether the road map should be generated based on left-hand traffic. */
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere)
|
||||
bool bLeftHandTraffic = false;
|
||||
|
||||
/** If true, the road map encoded as an image is saved to disk. The image is
|
||||
* saved to the "Saved" folder of the project.
|
||||
*/
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere)
|
||||
bool bSaveRoadMapToDisk = true;
|
||||
|
||||
/** If true, a debug point is drawn in the level for each pixel of the road
|
||||
* map.
|
||||
*/
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere)
|
||||
bool bDrawDebugPixelsToLevel = false;
|
||||
|
||||
/** The road map is re-computed on save so we always store an up-to-date
|
||||
* version. Uncheck this only for testing purposes as the road map might get
|
||||
* out-of-sync with the current road layout.
|
||||
*/
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere, AdvancedDisplay)
|
||||
bool bGenerateRoadMapOnSave = true;
|
||||
|
||||
UPROPERTY()
|
||||
URoadMap *RoadMap;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
|
|
|
@ -70,7 +70,7 @@ void ACarlaGameMode::RestartPlayer(AController* NewPlayer)
|
|||
void ACarlaGameMode::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
TagObjectsForSemanticSegmentation();
|
||||
TagActorsForSemanticSegmentation();
|
||||
GameController->BeginPlay();
|
||||
}
|
||||
|
||||
|
@ -102,11 +102,10 @@ void ACarlaGameMode::AttachCaptureCamerasToPlayer(AController &Player)
|
|||
}
|
||||
}
|
||||
|
||||
void ACarlaGameMode::TagObjectsForSemanticSegmentation()
|
||||
void ACarlaGameMode::TagActorsForSemanticSegmentation()
|
||||
{
|
||||
auto Tagger = GetWorld()->SpawnActor<ATagger>();
|
||||
Tagger->TagObjects();
|
||||
Tagger->Destroy(); // We don't need you anymore.
|
||||
check(GetWorld() != nullptr);
|
||||
ATagger::TagActorsInLevel(*GetWorld());
|
||||
}
|
||||
|
||||
APlayerStart *ACarlaGameMode::FindUnOccupiedStartPoints(
|
||||
|
|
|
@ -35,7 +35,7 @@ private:
|
|||
|
||||
void AttachCaptureCamerasToPlayer(AController &Player);
|
||||
|
||||
void TagObjectsForSemanticSegmentation();
|
||||
void TagActorsForSemanticSegmentation();
|
||||
|
||||
/// Iterate all the APlayerStart present in the world and add the ones with
|
||||
/// unoccupied locations to @a UnOccupiedStartPoints.
|
||||
|
@ -47,7 +47,9 @@ private:
|
|||
|
||||
CarlaGameControllerBase *GameController;
|
||||
|
||||
UPROPERTY()
|
||||
UCarlaGameInstance *GameInstance;
|
||||
|
||||
UPROPERTY()
|
||||
AController *PlayerController;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
static FText RoundedFloatAsText(float Value)
|
||||
{
|
||||
return FText::AsNumber(FMath::FloorToInt(Value));
|
||||
return FText::AsNumber(FMath::RoundHalfFromZero(Value));
|
||||
}
|
||||
|
||||
static FText GetVectorAsText(const FVector &Vector)
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
#include "Carla.h"
|
||||
#include "CarlaVehicleController.h"
|
||||
|
||||
#include "SceneCaptureCamera.h"
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "SceneCaptureCamera.h"
|
||||
#include "WheeledVehicle.h"
|
||||
#include "WheeledVehicleMovementComponent.h"
|
||||
|
||||
|
@ -82,6 +85,14 @@ void ACarlaVehicleController::Possess(APawn *aPawn)
|
|||
// Get vehicle movement component.
|
||||
MovementComponent = WheeledVehicle->GetVehicleMovementComponent();
|
||||
check(MovementComponent != nullptr);
|
||||
// Get vehicle box component.
|
||||
TArray<UBoxComponent *> BoundingBoxes;
|
||||
WheeledVehicle->GetComponents<UBoxComponent>(BoundingBoxes);
|
||||
if (BoundingBoxes.Num() > 0) {
|
||||
VehicleBounds = BoundingBoxes[0];
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Pawn is missing the bounding box!"));
|
||||
}
|
||||
// Get custom player state.
|
||||
CarlaPlayerState = Cast<ACarlaPlayerState>(PlayerState);
|
||||
check(CarlaPlayerState != nullptr);
|
||||
|
@ -111,6 +122,11 @@ void ACarlaVehicleController::BeginPlay()
|
|||
Image.PostProcessEffect = Camera->GetPostProcessEffect();
|
||||
}
|
||||
}
|
||||
|
||||
TActorIterator<ACityMapGenerator> It(GetWorld());
|
||||
if (It) {
|
||||
RoadMap = It->GetRoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void ACarlaVehicleController::Tick(float DeltaTime)
|
||||
|
@ -126,7 +142,7 @@ void ACarlaVehicleController::Tick(float DeltaTime)
|
|||
const FVector CurrentSpeed = CarlaPlayerState->ForwardSpeed * CarlaPlayerState->Orientation;
|
||||
CarlaPlayerState->Acceleration = (CurrentSpeed - PreviousSpeed) / DeltaTime;
|
||||
CarlaPlayerState->CurrentGear = GetVehicleCurrentGear();
|
||||
/// @todo #15 Set intersection factors.
|
||||
IntersectPlayerWithRoadMap();
|
||||
const auto NumberOfCameras = SceneCaptureCameras.Num();
|
||||
check(NumberOfCameras == CarlaPlayerState->Images.Num());
|
||||
for (auto i = 0; i < NumberOfCameras; ++i) {
|
||||
|
@ -283,3 +299,27 @@ void ACarlaVehicleController::ChangeCameraRight(float Value)
|
|||
Rotation.Yaw -= Value;
|
||||
SpringArm->SetRelativeRotation(Rotation);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Other --------------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACarlaVehicleController::IntersectPlayerWithRoadMap()
|
||||
{
|
||||
if (RoadMap == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Controller doesn't have a road map"));
|
||||
return;
|
||||
} else if (VehicleBounds == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Vehicle doesn't have a bounding box"));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr float ChecksPerCentimeter = 0.1f;
|
||||
auto Result = RoadMap->Intersect(
|
||||
GetPawn()->GetTransform(),
|
||||
VehicleBounds->GetScaledBoxExtent(),
|
||||
ChecksPerCentimeter);
|
||||
|
||||
CarlaPlayerState->OffRoadIntersectionFactor = Result.OffRoad;
|
||||
CarlaPlayerState->OtherLaneIntersectionFactor = Result.OppositeLane;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
class ACarlaHUD;
|
||||
class ACarlaPlayerState;
|
||||
class ASceneCaptureCamera;
|
||||
class UBoxComponent;
|
||||
class UCameraComponent;
|
||||
class URoadMap;
|
||||
class USpringArmComponent;
|
||||
class UWheeledVehicleMovementComponent;
|
||||
struct FCameraDescription;
|
||||
|
@ -160,6 +162,22 @@ private:
|
|||
|
||||
void SetupControllerInput();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Other
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
public:
|
||||
|
||||
void SetRoadMap(URoadMap *inRoadMap)
|
||||
{
|
||||
RoadMap = inRoadMap;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void IntersectPlayerWithRoadMap();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
// -- Member variables -------------------------------------------------------
|
||||
|
@ -181,6 +199,12 @@ private:
|
|||
UPROPERTY()
|
||||
TArray<ASceneCaptureCamera *> SceneCaptureCameras;
|
||||
|
||||
UPROPERTY()
|
||||
URoadMap *RoadMap;
|
||||
|
||||
UPROPERTY()
|
||||
UBoxComponent *VehicleBounds;
|
||||
|
||||
// Cast for quick access to the custom player state.
|
||||
UPROPERTY()
|
||||
ACarlaPlayerState *CarlaPlayerState;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadMap.h"
|
||||
|
||||
#include "CapturedImage.h"
|
||||
|
||||
static FVector2D Decode(const FColor &Color);
|
||||
|
||||
// void RoadMap::SetCapture(FCapturedImage &inMapCapture, const FVector2D &inMapSizeInCm)
|
||||
// {
|
||||
// MapCapture = &inMapCapture;
|
||||
// MapSizeInCm = inMapSizeInCm
|
||||
// }
|
||||
|
||||
// bool RoadMap::IsValid() const
|
||||
// {
|
||||
// return ((MapCapture != nullptr) &&
|
||||
// (MapCapture->BitMap.Num() > 0) &&
|
||||
// (MapSizeInCm.X > 0.0f) &&
|
||||
// (MapSizeInCm.Y > 0.0f));
|
||||
// }
|
||||
|
||||
// FVector2D RoadMap::GetDirectionAt(const FVector &Location) const
|
||||
// {
|
||||
// check(IsValid());
|
||||
// return FVector2D();
|
||||
// }
|
|
@ -1,29 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Math/Vector.h"
|
||||
|
||||
struct FCapturedImage;
|
||||
|
||||
/// Road map of the level. Contains information in 2D of which areas are road
|
||||
/// and lane directions.
|
||||
class CARLA_API RoadMap
|
||||
{
|
||||
public:
|
||||
|
||||
void SetCapture(
|
||||
const FCapturedImage &MapCapture,
|
||||
const FVector2D &Origin,
|
||||
const FVector2D &MapExtent);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
FVector2D GetDirectionAt(const FVector &Location) const;
|
||||
|
||||
private:
|
||||
|
||||
uint32 GetPixelIndexAt(const FVector2D &Location) const;
|
||||
|
||||
TArray<FVector2D> DirectionMap;
|
||||
};
|
|
@ -67,6 +67,9 @@ FVector ACityMapMeshHolder::GetTileLocation(uint32 X, uint32 Y) const
|
|||
void ACityMapMeshHolder::SetStaticMesh(ECityMapMeshTag Tag, UStaticMesh *Mesh)
|
||||
{
|
||||
StaticMeshes[Tag] = Mesh;
|
||||
if (Mesh != nullptr) {
|
||||
TagMap.Add(Mesh, Tag);
|
||||
}
|
||||
}
|
||||
|
||||
UStaticMesh *ACityMapMeshHolder::GetStaticMesh(ECityMapMeshTag Tag)
|
||||
|
@ -79,6 +82,12 @@ const UStaticMesh *ACityMapMeshHolder::GetStaticMesh(ECityMapMeshTag Tag) const
|
|||
return StaticMeshes[Tag];
|
||||
}
|
||||
|
||||
ECityMapMeshTag ACityMapMeshHolder::GetTag(const UStaticMesh &StaticMesh) const
|
||||
{
|
||||
const ECityMapMeshTag *Tag = TagMap.Find(&StaticMesh);
|
||||
return (Tag != nullptr ? *Tag : ECityMapMeshTag::INVALID);
|
||||
}
|
||||
|
||||
void ACityMapMeshHolder::AddInstance(ECityMapMeshTag Tag, uint32 X, uint32 Y)
|
||||
{
|
||||
AddInstance(Tag, FTransform(GetTileLocation(X, Y)));
|
||||
|
|
|
@ -38,6 +38,11 @@ protected:
|
|||
// ===========================================================================
|
||||
protected:
|
||||
|
||||
float GetMapScale() const
|
||||
{
|
||||
return MapScale;
|
||||
}
|
||||
|
||||
/// Return the 3D world location (relative to this actor) of the given 2D
|
||||
/// tile.
|
||||
FVector GetTileLocation(uint32 X, uint32 Y) const;
|
||||
|
@ -51,6 +56,9 @@ protected:
|
|||
/// Return the static mesh corresponding to @a Tag.
|
||||
const UStaticMesh *GetStaticMesh(ECityMapMeshTag Tag) const;
|
||||
|
||||
/// Return the tag corresponding to @a StaticMesh.
|
||||
ECityMapMeshTag GetTag(const UStaticMesh &StaticMesh) const;
|
||||
|
||||
/// Add an instance of a mesh with a given tile location.
|
||||
/// @param Tag The mesh' tag
|
||||
/// @param X Tile coordinate X
|
||||
|
@ -89,12 +97,15 @@ private:
|
|||
UPROPERTY()
|
||||
USceneComponent *SceneRootComponent;
|
||||
|
||||
UPROPERTY(Category = "Map Generation", VisibleAnywhere)
|
||||
float MapScale;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
TMap<ECityMapMeshTag, UStaticMesh *> StaticMeshes;
|
||||
|
||||
UPROPERTY(Category = "Meshes|Debug", VisibleAnywhere)
|
||||
float MapScale;
|
||||
UPROPERTY()
|
||||
TMap<UStaticMesh *, ECityMapMeshTag> TagMap;
|
||||
|
||||
UPROPERTY(Category = "Meshes|Debug", VisibleAnywhere)
|
||||
UPROPERTY(Category = "Meshes", VisibleAnywhere)
|
||||
TArray<UInstancedStaticMeshComponent *> MeshInstatiators;
|
||||
};
|
||||
|
|
|
@ -46,7 +46,8 @@ enum class ECityMapMeshTag : uint8
|
|||
RoadXIntersection_Sidewalk3 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 3"),
|
||||
RoadXIntersection_LaneMarking UMETA(DisplayName = "Road: X-Intersection - Lane Marking"),
|
||||
|
||||
NUMBER_OF_TAGS UMETA(Hidden)
|
||||
NUMBER_OF_TAGS UMETA(Hidden),
|
||||
INVALID UMETA(Hidden)
|
||||
};
|
||||
|
||||
/// Helper class for working with ECityMapMeshTag.
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadMap.h"
|
||||
|
||||
#include "DrawDebugHelpers.h"
|
||||
#include "HighResScreenshot.h"
|
||||
|
||||
static uint32 ClampFloatToUInt(const float Value, int32 Min, int32 Max)
|
||||
{
|
||||
return FMath::Clamp(FMath::FloorToInt(Value), Min, Max);
|
||||
}
|
||||
|
||||
// Creates a valid empty map (every point is off-road).
|
||||
URoadMap::URoadMap(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer),
|
||||
PixelsPerCentimeter(1.0f),
|
||||
Width(1u),
|
||||
Height(1u)
|
||||
{
|
||||
AppendEmptyPixel();
|
||||
}
|
||||
|
||||
FVector URoadMap::GetWorldLocation(uint32 PixelX, uint32 PixelY) const
|
||||
{
|
||||
const FVector RelativePosition(
|
||||
static_cast<float>(PixelX) / PixelsPerCentimeter,
|
||||
static_cast<float>(PixelY) / PixelsPerCentimeter,
|
||||
0.0f);
|
||||
return WorldToMap.InverseTransformPosition(RelativePosition + MapOffset);
|
||||
}
|
||||
|
||||
const FRoadMapPixelData &URoadMap::GetDataAt(const FVector &WorldLocation) const
|
||||
{
|
||||
check(IsValid());
|
||||
const FVector Location = WorldToMap.TransformPosition(WorldLocation) - MapOffset;
|
||||
uint32 X = ClampFloatToUInt(PixelsPerCentimeter * Location.X, 0, Width - 1);
|
||||
uint32 Y = ClampFloatToUInt(PixelsPerCentimeter * Location.Y, 0, Height - 1);
|
||||
return GetDataAt(X, Y);
|
||||
}
|
||||
|
||||
FRoadMapIntersectionResult URoadMap::Intersect(
|
||||
const FTransform &BoxTransform,
|
||||
const FVector &BoxExtent,
|
||||
float ChecksPerCentimeter) const
|
||||
{
|
||||
const auto &DirectionOfMovement = BoxTransform.GetRotation().GetForwardVector();
|
||||
uint32 CheckCount = 0u;
|
||||
FRoadMapIntersectionResult Result = {0.0f, 0.0f};
|
||||
const float Step = 1.0f / ChecksPerCentimeter;
|
||||
for (float X = -BoxExtent.X; X < BoxExtent.X; X += Step) {
|
||||
for (float Y = -BoxExtent.Y; Y < BoxExtent.Y; Y += Step) {
|
||||
++CheckCount;
|
||||
auto Location = BoxTransform.TransformPosition(FVector(X, Y, 0.0f));
|
||||
auto &Data = GetDataAt(Location);
|
||||
if (Data.bIsOffRoad) {
|
||||
Result.OffRoad += 1.0f;
|
||||
} else if (Data.bHasDirection &&
|
||||
0.0f < FVector::DotProduct(Data.Direction, DirectionOfMovement)) {
|
||||
Result.OppositeLane += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CheckCount > 0u) {
|
||||
Result.OffRoad /= static_cast<float>(CheckCount);
|
||||
Result.OppositeLane /= static_cast<float>(CheckCount);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("URoadMap::Intersect did zero checks"));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
static FColor Encode(const FRoadMapPixelData &Data)
|
||||
{
|
||||
if (Data.bIsOffRoad) {
|
||||
return FColor(0u, 0u, 0u, 255u);
|
||||
} else if (!Data.bHasDirection) {
|
||||
return FColor(255u, 255u, 255u, 255u);
|
||||
} else {
|
||||
// Assumes normalized direction.
|
||||
auto ToColor = [](float X){
|
||||
return FMath::FloorToInt(255.0 * (X + 1.0f) / 2.0f);
|
||||
};
|
||||
return FColor(ToColor(Data.Direction.X), ToColor(Data.Direction.Y), ToColor(Data.Direction.Z));
|
||||
}
|
||||
}
|
||||
|
||||
bool URoadMap::SaveAsPNG(const FString &Path) const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Cannot save invalid road map to disk"));
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FColor> BitMap;
|
||||
for (auto &Data : RoadMap) {
|
||||
BitMap.Emplace(Encode(Data));
|
||||
}
|
||||
|
||||
FIntPoint DestSize(Width, Height);
|
||||
FString ResultPath;
|
||||
FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
|
||||
HighResScreenshotConfig.SaveImage(Path, BitMap, DestSize, &ResultPath);
|
||||
UE_LOG(LogCarla, Log, TEXT("Saved road map to \"%s\""), *ResultPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void URoadMap::DrawDebugPixelsToLevel(UWorld *World, const bool bJustFlushDoNotDraw) const
|
||||
{
|
||||
FlushPersistentDebugLines(World);
|
||||
if (!bJustFlushDoNotDraw) {
|
||||
for (auto X = 0u; X < Width; ++X) {
|
||||
for (auto Y = 0u; Y < Height; ++Y) {
|
||||
auto Location = GetWorldLocation(X, Y);
|
||||
auto Color = Encode(GetDataAt(X, Y));
|
||||
DrawDebugPoint(World, Location, 20.0f, Color, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URoadMap::AppendPixel(
|
||||
ECityMapMeshTag Tag,
|
||||
const FTransform &Transform,
|
||||
const bool bInvertDirection)
|
||||
{
|
||||
AppendEmptyPixel();
|
||||
auto &Data = RoadMap.Last();
|
||||
Data.bIsOffRoad = false;
|
||||
|
||||
auto Rotator = Transform.GetRotation().Rotator();
|
||||
switch (Tag) {
|
||||
case ECityMapMeshTag::RoadTwoLanes_LaneRight:
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane0:
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::RoadTwoLanes_LaneLeft:
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane1:
|
||||
Rotator.Yaw += 180.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane2:
|
||||
Rotator.Yaw += 90.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane3:
|
||||
Rotator.Yaw += 270.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
}
|
||||
if (Data.bHasDirection) {
|
||||
FQuat Rotation(Rotator);
|
||||
Data.Direction = Rotation.GetForwardVector();
|
||||
if (bInvertDirection) {
|
||||
Data.Direction *= -1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URoadMap::Set(
|
||||
const uint32 inWidth,
|
||||
const uint32 inHeight,
|
||||
const float inPinxelsPerCentimeter,
|
||||
const FTransform &inWorldToMap,
|
||||
const FVector &inMapOffset)
|
||||
{
|
||||
Width = inWidth;
|
||||
Height = inHeight;
|
||||
PixelsPerCentimeter = inPinxelsPerCentimeter;
|
||||
WorldToMap = inWorldToMap;
|
||||
MapOffset = inMapOffset;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "RoadMap.generated.h"
|
||||
|
||||
USTRUCT()
|
||||
struct FRoadMapIntersectionResult
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Percentage of the box lying off-road */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
float OffRoad;
|
||||
|
||||
/** Percentage of the box invading opposite lane (wrong direction) */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
float OppositeLane;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FRoadMapPixelData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
bool bIsOffRoad = true;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
bool bHasDirection = false;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
FVector Direction;
|
||||
};
|
||||
|
||||
/// Road map of the level. Contains information in 2D of which areas are road
|
||||
/// and lane directions.
|
||||
UCLASS()
|
||||
class CARLA_API URoadMap : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
URoadMap(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool IsValid() const
|
||||
{
|
||||
return ((RoadMap.Num() > 0) && (RoadMap.Num() == Height * Width));
|
||||
}
|
||||
|
||||
uint32 GetWidth() const
|
||||
{
|
||||
return Width;
|
||||
}
|
||||
|
||||
uint32 GetHeight() const
|
||||
{
|
||||
return Height;
|
||||
}
|
||||
|
||||
FVector GetWorldLocation(uint32 PixelX, uint32 PixelY) const;
|
||||
|
||||
const FRoadMapPixelData &GetDataAt(uint32 PixelX, uint32 PixelY) const
|
||||
{
|
||||
check(IsValid());
|
||||
return RoadMap[PixelX + Width * PixelY];
|
||||
}
|
||||
|
||||
/** Clamps value if lies outside map limits */
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const FRoadMapPixelData &GetDataAt(const FVector &WorldLocation) const;
|
||||
|
||||
/** Intersect actor bounds with map.
|
||||
*
|
||||
* Bounds box is projected to the map and checked against it for possible
|
||||
* intersections with off-road areas and opposite lanes.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable)
|
||||
FRoadMapIntersectionResult Intersect(
|
||||
const FTransform &BoxTransform,
|
||||
const FVector &BoxExtent,
|
||||
float ChecksPerCentimeter) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool SaveAsPNG(const FString &Path) const;
|
||||
|
||||
/** Draw every pixel of the image as debug point */
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DrawDebugPixelsToLevel(UWorld *World, bool bJustFlushDoNotDraw = false) const;
|
||||
|
||||
private:
|
||||
|
||||
friend class ACityMapGenerator;
|
||||
|
||||
void AppendEmptyPixel()
|
||||
{
|
||||
RoadMap.AddDefaulted(1);
|
||||
}
|
||||
|
||||
void AppendPixel(
|
||||
ECityMapMeshTag Tag,
|
||||
const FTransform &Transform,
|
||||
bool bInvertDirection);
|
||||
|
||||
void Set(
|
||||
uint32 Width,
|
||||
uint32 Height,
|
||||
float PixelsPerCentimeter,
|
||||
const FTransform &WorldToMap,
|
||||
const FVector &MapOffset);
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
FTransform WorldToMap;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
FVector MapOffset;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
float PixelsPerCentimeter;
|
||||
|
||||
/** Width of the map in pixels */
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
uint32 Width;
|
||||
|
||||
/** Height of the map in pixels */
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
uint32 Height;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<FRoadMapPixelData> RoadMap;
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "StaticMeshCollection.h"
|
||||
|
||||
#include "Components/InstancedStaticMeshComponent.h"
|
||||
#include "Engine/StaticMesh.h"
|
||||
|
||||
AStaticMeshCollection::AStaticMeshCollection(
|
||||
const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
RootComponent =
|
||||
ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComponent"));
|
||||
RootComponent->SetMobility(EComponentMobility::Static);
|
||||
}
|
||||
|
||||
void AStaticMeshCollection::PushBackInstantiator(UStaticMesh *Mesh)
|
||||
{
|
||||
auto Instantiator = NewObject<UInstancedStaticMeshComponent>(this);
|
||||
check(Instantiator != nullptr);
|
||||
Instantiator->SetMobility(EComponentMobility::Static);
|
||||
Instantiator->SetupAttachment(RootComponent);
|
||||
Instantiator->SetStaticMesh(Mesh);
|
||||
Instantiator->RegisterComponent();
|
||||
MeshInstantiators.Add(Instantiator);
|
||||
}
|
||||
|
||||
void AStaticMeshCollection::SetStaticMesh(uint32 i, UStaticMesh *Mesh)
|
||||
{
|
||||
if ((GetNumberOfInstantiators() > i) && (MeshInstantiators[i] != nullptr)) {
|
||||
MeshInstantiators[i]->SetStaticMesh(Mesh);
|
||||
}
|
||||
}
|
||||
|
||||
void AStaticMeshCollection::AddInstance(uint32 i, const FTransform &Transform)
|
||||
{
|
||||
if ((GetNumberOfInstantiators() > i) && (MeshInstantiators[i] != nullptr)) {
|
||||
MeshInstantiators[i]->AddInstance(Transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AStaticMeshCollection::ClearInstances()
|
||||
{
|
||||
for (auto *Instantiator : MeshInstantiators) {
|
||||
if (Instantiator != nullptr) {
|
||||
Instantiator->ClearInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AStaticMeshCollection::ClearInstantiators()
|
||||
{
|
||||
ClearInstances();
|
||||
MeshInstantiators.Empty();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "StaticMeshCollection.generated.h"
|
||||
|
||||
class UInstancedStaticMeshComponent;
|
||||
|
||||
/// Holds static mesh instatiators.
|
||||
UCLASS(Abstract)
|
||||
class CARLA_API AStaticMeshCollection : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
AStaticMeshCollection(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
protected:
|
||||
|
||||
uint32 GetNumberOfInstantiators() const
|
||||
{
|
||||
return MeshInstantiators.Num();
|
||||
}
|
||||
|
||||
void PushBackInstantiator(UStaticMesh *Mesh);
|
||||
|
||||
void SetStaticMesh(uint32 i, UStaticMesh *Mesh);
|
||||
|
||||
void AddInstance(uint32 i, const FTransform &Transform);
|
||||
|
||||
void ClearInstances();
|
||||
|
||||
/// Clear the instances too.
|
||||
void ClearInstantiators();
|
||||
|
||||
private:
|
||||
|
||||
UPROPERTY(Category = "Instanced Static Mesh Collection", VisibleAnywhere)
|
||||
TArray<UInstancedStaticMeshComponent *> MeshInstantiators;
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadIntersection.h"
|
||||
|
||||
ARoadIntersection::ARoadIntersection(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
RootComponent =
|
||||
ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("RootComponent"));
|
||||
RootComponent->SetMobility(EComponentMobility::Static);
|
||||
|
||||
#define CARLA_CREATE_STATIC_MESH_COMPONENT(Mesh) \
|
||||
{ \
|
||||
auto Component = CreateDefaultSubobject<UStaticMeshComponent>(TEXT(#Mesh) TEXT("Component")); \
|
||||
Component->SetMobility(EComponentMobility::Static); \
|
||||
Component->SetupAttachment(RootComponent); \
|
||||
StaticMeshComponents.Add(Component); \
|
||||
StaticMeshes.Add(ERoadIntersectionItem:: Mesh, nullptr); \
|
||||
}
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Lane0)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Lane1)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Lane2)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Lane3)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Sidewalk0)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Sidewalk1)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Sidewalk2)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(Sidewalk3)
|
||||
CARLA_CREATE_STATIC_MESH_COMPONENT(LaneMarking)
|
||||
#undef CARLA_CREATE_STATIC_MESH_COMPONENT
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void ARoadIntersection::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
if (PropertyChangedEvent.Property) {
|
||||
UpdateMeshes();
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
void ARoadIntersection::SetStaticMesh(ERoadIntersectionItem Item, UStaticMesh *StaticMesh)
|
||||
{
|
||||
if (static_cast<uint8>(Item) < StaticMeshes.Num()) {
|
||||
StaticMeshes[Item] = StaticMesh;
|
||||
}
|
||||
}
|
||||
|
||||
void ARoadIntersection::UpdateMeshes()
|
||||
{
|
||||
check(StaticMeshes.Num() == StaticMeshComponents.Num());
|
||||
int32 i = 0;
|
||||
for (auto Item : StaticMeshes) {
|
||||
check(StaticMeshComponents[i] != nullptr);
|
||||
StaticMeshComponents[i]->SetStaticMesh(Item.Value);
|
||||
++i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "RoadIntersection.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ERoadIntersectionItem : uint8
|
||||
{
|
||||
Lane0 UMETA(DisplayName = "Lane 1"),
|
||||
Lane1 UMETA(DisplayName = "Lane 2"),
|
||||
Lane2 UMETA(DisplayName = "Lane 3"),
|
||||
Lane3 UMETA(DisplayName = "Lane 4"),
|
||||
Sidewalk0 UMETA(DisplayName = "Sidewalk 1"),
|
||||
Sidewalk1 UMETA(DisplayName = "Sidewalk 2"),
|
||||
Sidewalk2 UMETA(DisplayName = "Sidewalk 3"),
|
||||
Sidewalk3 UMETA(DisplayName = "Sidewalk 4"),
|
||||
LaneMarking UMETA(DisplayName = "LaneMarking"),
|
||||
};
|
||||
|
||||
/// A road intersection.
|
||||
UCLASS()
|
||||
class CARLA_API ARoadIntersection : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
ARoadIntersection(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetStaticMesh(ERoadIntersectionItem Item, UStaticMesh *StaticMesh);
|
||||
|
||||
private:
|
||||
|
||||
void UpdateMeshes();
|
||||
|
||||
UPROPERTY()
|
||||
TArray<UStaticMeshComponent *> StaticMeshComponents;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
TMap<ERoadIntersectionItem, UStaticMesh *> StaticMeshes;
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadSegment.h"
|
||||
|
||||
#include "Engine/StaticMesh.h"
|
||||
|
||||
enum RoadSegmentItems {
|
||||
ELaneLeft,
|
||||
ELaneRight,
|
||||
ESidewalkLeft,
|
||||
ESidewalkRight,
|
||||
ELaneMarkingSolid,
|
||||
ELaneMarkingBroken,
|
||||
NUMBER_OF_ITEMS
|
||||
};
|
||||
|
||||
ARoadSegment::ARoadSegment(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
}
|
||||
|
||||
void ARoadSegment::OnConstruction(const FTransform &Transform)
|
||||
{
|
||||
Super::OnConstruction(Transform);
|
||||
UpdateMeshes();
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void ARoadSegment::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
if (PropertyChangedEvent.Property) {
|
||||
GenerateRoad();
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
void ARoadSegment::GenerateRoad()
|
||||
{
|
||||
UpdateMeshes();
|
||||
UpdateRoad();
|
||||
}
|
||||
|
||||
void ARoadSegment::UpdateMeshes()
|
||||
{
|
||||
if (GetNumberOfInstantiators() != NUMBER_OF_ITEMS) {
|
||||
ClearInstantiators();
|
||||
for (auto i = 0u; i < NUMBER_OF_ITEMS; ++i) {
|
||||
PushBackInstantiator(nullptr);
|
||||
}
|
||||
}
|
||||
SetStaticMesh(ELaneLeft, LaneLeft);
|
||||
SetStaticMesh(ELaneRight, LaneRight);
|
||||
SetStaticMesh(ESidewalkLeft, SidewalkLeft);
|
||||
SetStaticMesh(ESidewalkRight, SidewalkRight);
|
||||
SetStaticMesh(ELaneMarkingSolid, LaneMarkingSolid);
|
||||
SetStaticMesh(ELaneMarkingBroken, LaneMarkingBroken);
|
||||
}
|
||||
|
||||
void ARoadSegment::UpdateRoad()
|
||||
{
|
||||
ClearInstances();
|
||||
Scale = (LaneLeft != nullptr ? LaneLeft->GetBoundingBox().GetSize().X : 1.0f);
|
||||
FVector Translation(0.0f, 0.0f, 0.0f);
|
||||
for (auto &Item : RoadDescription) {
|
||||
FTransform Transform{Translation};
|
||||
AddInstance(ELaneLeft, Transform);
|
||||
AddInstance(ELaneRight, Transform);
|
||||
if (Item.bHasRightSidewalk) {
|
||||
AddInstance(ESidewalkRight, Transform);
|
||||
}
|
||||
if (Item.bHasLeftSidewalk) {
|
||||
AddInstance(ESidewalkLeft, Transform);
|
||||
}
|
||||
if (Item.LaneMarking == ELaneMarkingType::Solid) {
|
||||
AddInstance(ELaneMarkingSolid, Transform);
|
||||
} else if (Item.LaneMarking == ELaneMarkingType::Broken) {
|
||||
AddInstance(ELaneMarkingBroken, Transform);
|
||||
}
|
||||
Translation.X += Scale;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MapGen/StaticMeshCollection.h"
|
||||
#include "RoadSegment.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ELaneMarkingType : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
Solid UMETA(DisplayName = "Solid Lane Marking"),
|
||||
Broken UMETA(DisplayName = "Broken Lane Marking")
|
||||
};
|
||||
|
||||
/// Description of a road segment piece.
|
||||
USTRUCT()
|
||||
struct FRoadSegmentPiece
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bHasLeftSidewalk = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bHasRightSidewalk = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
ELaneMarkingType LaneMarking = ELaneMarkingType::Solid;
|
||||
};
|
||||
|
||||
/// A straight segment of road.
|
||||
///
|
||||
/// Please call GenerateRoad after modifying it.
|
||||
UCLASS()
|
||||
class CARLA_API ARoadSegment : public AStaticMeshCollection
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
ARoadSegment(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void OnConstruction(const FTransform &Transform) override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Road Description")
|
||||
void GenerateRoad();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Road Description")
|
||||
int32 GetNumberOfPieces() const
|
||||
{
|
||||
return RoadDescription.Num();
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Road Description")
|
||||
void AppendPiece(const FRoadSegmentPiece &RoadSegmentPiece)
|
||||
{
|
||||
RoadDescription.Add(RoadSegmentPiece);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Road Description")
|
||||
void RemoveAllPieces()
|
||||
{
|
||||
RoadDescription.Empty();
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_LaneLeft(UStaticMesh *StaticMesh)
|
||||
{
|
||||
LaneLeft = StaticMesh;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_LaneRight(UStaticMesh *StaticMesh)
|
||||
{
|
||||
LaneRight = StaticMesh;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_SidewalkLeft(UStaticMesh *StaticMesh)
|
||||
{
|
||||
SidewalkLeft = StaticMesh;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_SidewalkRight(UStaticMesh *StaticMesh)
|
||||
{
|
||||
SidewalkRight = StaticMesh;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_LaneMarkingSolid(UStaticMesh *StaticMesh)
|
||||
{
|
||||
LaneMarkingSolid = StaticMesh;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Set Static Mesh")
|
||||
void SetStaticMesh_LaneMarkingBroken(UStaticMesh *StaticMesh)
|
||||
{
|
||||
LaneMarkingBroken = StaticMesh;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void UpdateMeshes();
|
||||
|
||||
void UpdateRoad();
|
||||
|
||||
UPROPERTY(Category = "Road Description", EditAnywhere)
|
||||
TArray<FRoadSegmentPiece> RoadDescription;
|
||||
|
||||
UPROPERTY(Category = "Road Description", AdvancedDisplay, EditAnywhere)
|
||||
float Scale = 1.0f;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *LaneLeft;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *LaneRight;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *SidewalkLeft;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *SidewalkRight;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *LaneMarkingSolid;
|
||||
|
||||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
UStaticMesh *LaneMarkingBroken;
|
||||
};
|
|
@ -9,43 +9,112 @@
|
|||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
|
||||
enum class Label : uint8
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
static FString GetLabelAsString(const CityObjectLabel Label)
|
||||
{
|
||||
None = 0u,
|
||||
Buildings = 1u,
|
||||
Fences = 2u,
|
||||
Other = 3u,
|
||||
Pedestrians = 4u,
|
||||
Poles = 5u,
|
||||
RoadLines = 6u,
|
||||
Roads = 7u,
|
||||
Sidewalks = 8u,
|
||||
Vegetation = 9u,
|
||||
Vehicles = 10u,
|
||||
Walls = 11u,
|
||||
};
|
||||
|
||||
static Label GetLabel(const FString &str) {
|
||||
if (str == "Buildings") return Label::Buildings;
|
||||
else if (str == "Fences") return Label::Fences;
|
||||
else if (str == "Pedestrians") return Label::Pedestrians;
|
||||
else if (str == "Pole") return Label::Poles;
|
||||
else if (str == "Props") return Label::Other;
|
||||
else if (str == "Road") return Label::Roads;
|
||||
else if (str == "RoadLines") return Label::RoadLines;
|
||||
else if (str == "SideWalk") return Label::Sidewalks;
|
||||
else if (str == "Vegetation") return Label::Vegetation;
|
||||
else if (str == "Vehicles") return Label::Vehicles;
|
||||
else if (str == "Walls") return Label::Walls;
|
||||
else return Label::None;
|
||||
switch (Label) {
|
||||
#define CARLA_GET_LABEL_STR(lbl) case CityObjectLabel:: lbl : return #lbl;
|
||||
default:
|
||||
CARLA_GET_LABEL_STR(None)
|
||||
CARLA_GET_LABEL_STR(Buildings)
|
||||
CARLA_GET_LABEL_STR(Fences)
|
||||
CARLA_GET_LABEL_STR(Other)
|
||||
CARLA_GET_LABEL_STR(Pedestrians)
|
||||
CARLA_GET_LABEL_STR(Poles)
|
||||
CARLA_GET_LABEL_STR(RoadLines)
|
||||
CARLA_GET_LABEL_STR(Roads)
|
||||
CARLA_GET_LABEL_STR(Sidewalks)
|
||||
CARLA_GET_LABEL_STR(Vegetation)
|
||||
CARLA_GET_LABEL_STR(Vehicles)
|
||||
CARLA_GET_LABEL_STR(Walls)
|
||||
#undef CARLA_GET_LABEL_STR
|
||||
}
|
||||
}
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
template <typename T>
|
||||
static auto cast(T label)
|
||||
static auto CastEnum(T label)
|
||||
{
|
||||
return static_cast<typename std::underlying_type<T>::type>(label);
|
||||
}
|
||||
|
||||
static CityObjectLabel GetLabelByFolderName(const FString &String) {
|
||||
if (String == "Buildings") return CityObjectLabel::Buildings;
|
||||
else if (String == "Fences") return CityObjectLabel::Fences;
|
||||
else if (String == "Pedestrians") return CityObjectLabel::Pedestrians;
|
||||
else if (String == "Pole") return CityObjectLabel::Poles;
|
||||
else if (String == "Props") return CityObjectLabel::Other;
|
||||
else if (String == "Road") return CityObjectLabel::Roads;
|
||||
else if (String == "RoadLines") return CityObjectLabel::RoadLines;
|
||||
else if (String == "SideWalk") return CityObjectLabel::Sidewalks;
|
||||
else if (String == "Vegetation") return CityObjectLabel::Vegetation;
|
||||
else if (String == "Vehicles") return CityObjectLabel::Vehicles;
|
||||
else if (String == "Walls") return CityObjectLabel::Walls;
|
||||
else return CityObjectLabel::None;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static CityObjectLabel GetLabelByPath(const T *Object)
|
||||
{
|
||||
const FString Path = Object->GetPathName();
|
||||
TArray<FString> StringArray;
|
||||
Path.ParseIntoArray(StringArray, TEXT("/"), false);
|
||||
return (StringArray.Num() > 3 ? GetLabelByFolderName(StringArray[3]) : CityObjectLabel::None);
|
||||
}
|
||||
|
||||
static void SetStencilValue(UPrimitiveComponent *comp, const CityObjectLabel &Label) {
|
||||
if (Label != CityObjectLabel::None) {
|
||||
comp->SetRenderCustomDepth(true);
|
||||
comp->SetCustomDepthStencilValue(CastEnum(Label));
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- static ATagger functions -------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ATagger::TagActor(const AActor &Actor)
|
||||
{
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("Actor: %s"), *Actor.GetName());
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
// Iterate static meshes.
|
||||
TArray<UStaticMeshComponent *> StaticMeshComponents;
|
||||
Actor.GetComponents<UStaticMeshComponent>(StaticMeshComponents);
|
||||
for (UStaticMeshComponent *Component : StaticMeshComponents) {
|
||||
const auto Label = GetLabelByPath(Component->GetStaticMesh());
|
||||
SetStencilValue(Component, Label);
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT(" + StaticMeshComponent: %s"), *Component->GetName());
|
||||
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
}
|
||||
|
||||
// Iterate skeletal meshes.
|
||||
TArray<USkeletalMeshComponent *> SkeletalMeshComponents;
|
||||
Actor.GetComponents<USkeletalMeshComponent>(SkeletalMeshComponents);
|
||||
for (USkeletalMeshComponent *Component : SkeletalMeshComponents) {
|
||||
const auto Label = GetLabelByPath(Component->GetPhysicsAsset());
|
||||
SetStencilValue(Component, Label);
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT(" + SkeletalMeshComponent: %s"), *Component->GetName());
|
||||
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
}
|
||||
}
|
||||
|
||||
void ATagger::TagActorsInLevel(UWorld &World)
|
||||
{
|
||||
for (TActorIterator<AActor> it(&World); it; ++it) {
|
||||
TagActor(**it);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- non-static ATagger functions ---------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
ATagger::ATagger()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
@ -56,81 +125,10 @@ void ATagger::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent
|
|||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
if (PropertyChangedEvent.Property) {
|
||||
if (bTriggerTagObjects) {
|
||||
TagObjects();
|
||||
if (bTriggerTagObjects && (GetWorld() != nullptr)) {
|
||||
TagActorsInLevel(*GetWorld());
|
||||
}
|
||||
}
|
||||
bTriggerTagObjects = false;
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
static void setStencilValue(UPrimitiveComponent *comp, const Label &label) {
|
||||
if (label != Label::None)
|
||||
{
|
||||
comp->SetRenderCustomDepth(true);
|
||||
comp->SetCustomDepthStencilValue(cast(label));
|
||||
}
|
||||
}
|
||||
|
||||
void ATagger::TagObjects()
|
||||
{
|
||||
for (TActorIterator<AActor> it(GetWorld()); it; ++it) {
|
||||
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT("Actor: %s"), *it->GetName());
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
/// get UStaticMeshComponents
|
||||
TArray<UStaticMeshComponent*> staticComponents;
|
||||
it->GetComponents<UStaticMeshComponent>(staticComponents);
|
||||
|
||||
for (auto& meshIt : staticComponents)
|
||||
{
|
||||
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT(" + StaticMeshComponent: %s"), *meshIt->GetName());
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
FString Path = meshIt->GetStaticMesh()->GetPathName();
|
||||
TArray<FString> stringArray;
|
||||
Path.ParseIntoArray(stringArray, TEXT("/"), false);
|
||||
/*for (int32 i = 0; i < stringArray.Num(); i++) {
|
||||
UE_LOG(LogCarla, Warning, TEXT(" -\"%s\""), *stringArray[i]);
|
||||
}*/
|
||||
if (stringArray.Num() > 3)
|
||||
{
|
||||
Label lab = GetLabel(stringArray[3]);
|
||||
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT(" - Label: \"%s\""), *stringArray[3]);
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
setStencilValue(meshIt, lab);
|
||||
}
|
||||
}
|
||||
|
||||
/// get USkeletalMeshComponents
|
||||
TArray<USkeletalMeshComponent*> skeletalComponents;
|
||||
it->GetComponents<USkeletalMeshComponent>(skeletalComponents);
|
||||
|
||||
for (auto& meshIt : skeletalComponents)
|
||||
{
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT(" + SkeletalMeshComponent: %s"), *meshIt->GetName());
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
FString Path = meshIt->GetPhysicsAsset()->GetPathName();
|
||||
TArray<FString> stringArray;
|
||||
Path.ParseIntoArray(stringArray, TEXT("/"), false);
|
||||
if (stringArray.Num() > 3)
|
||||
{
|
||||
Label lab = GetLabel(stringArray[3]);
|
||||
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT(" - Label: \"%s\""), *stringArray[3]);
|
||||
#endif // CARLA_TAGGER_EXTRA_LOG
|
||||
|
||||
setStencilValue(meshIt, lab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,27 @@
|
|||
#include "GameFramework/Actor.h"
|
||||
#include "Tagger.generated.h"
|
||||
|
||||
enum class CityObjectLabel : uint8
|
||||
{
|
||||
None = 0u,
|
||||
Buildings = 1u,
|
||||
Fences = 2u,
|
||||
Other = 3u,
|
||||
Pedestrians = 4u,
|
||||
Poles = 5u,
|
||||
RoadLines = 6u,
|
||||
Roads = 7u,
|
||||
Sidewalks = 8u,
|
||||
Vegetation = 9u,
|
||||
Vehicles = 10u,
|
||||
Walls = 11u,
|
||||
};
|
||||
|
||||
/// Sets actors' custom depth stencil value for semantic segmentation according
|
||||
/// to their meshes.
|
||||
///
|
||||
/// Non-static functions present so it can be dropped into the scene for testing
|
||||
/// purposes.
|
||||
UCLASS()
|
||||
class CARLA_API ATagger : public AActor
|
||||
{
|
||||
|
@ -12,9 +33,11 @@ class CARLA_API ATagger : public AActor
|
|||
|
||||
public:
|
||||
|
||||
ATagger();
|
||||
static void TagActor(const AActor &Actor);
|
||||
|
||||
void TagObjects();
|
||||
static void TagActorsInLevel(UWorld &World);
|
||||
|
||||
ATagger();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
Loading…
Reference in New Issue