Merge remote-tracking branch 'origin/dev' into xisco
This commit is contained in:
commit
f9f2dbe1ff
|
@ -1,3 +1,7 @@
|
||||||
|
## CARLA 0.2.4
|
||||||
|
|
||||||
|
* Fixed serialization of road map resulting in a huge map size.
|
||||||
|
|
||||||
## CARLA 0.2.3
|
## CARLA 0.2.3
|
||||||
|
|
||||||
* Fixed rounding errors in HUD (100% was shown as 99%, 30 FPS as 29 FPS).
|
* Fixed rounding errors in HUD (100% was shown as 99%, 30 FPS as 29 FPS).
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"FileVersion": 3,
|
"FileVersion": 3,
|
||||||
"Version": 1,
|
"Version": 1,
|
||||||
"VersionName": "0.2.3",
|
"VersionName": "0.2.4",
|
||||||
"FriendlyName": "CARLA",
|
"FriendlyName": "CARLA",
|
||||||
"Description": "",
|
"Description": "",
|
||||||
"Category": "Science",
|
"Category": "Science",
|
||||||
|
|
|
@ -162,6 +162,12 @@ void ACityMapGenerator::GenerateRoads()
|
||||||
AddInstance(tag ##_Lane1, x, y, angle); \
|
AddInstance(tag ##_Lane1, x, y, angle); \
|
||||||
AddInstance(tag ##_Lane2, x, y, angle); \
|
AddInstance(tag ##_Lane2, x, y, angle); \
|
||||||
AddInstance(tag ##_Lane3, x, y, angle); \
|
AddInstance(tag ##_Lane3, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane4, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane5, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane6, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane7, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane8, x, y, angle); \
|
||||||
|
AddInstance(tag ##_Lane9, x, y, angle); \
|
||||||
AddInstance(tag ##_Sidewalk0, x, y, angle); \
|
AddInstance(tag ##_Sidewalk0, x, y, angle); \
|
||||||
AddInstance(tag ##_Sidewalk1, x, y, angle); \
|
AddInstance(tag ##_Sidewalk1, x, y, angle); \
|
||||||
AddInstance(tag ##_Sidewalk2, x, y, angle); \
|
AddInstance(tag ##_Sidewalk2, x, y, angle); \
|
||||||
|
@ -189,7 +195,7 @@ void ACityMapGenerator::GenerateRoads()
|
||||||
#undef ADD_INTERSECTION
|
#undef ADD_INTERSECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find first component of type road (checking at its stencil value).
|
// Find first component of type road.
|
||||||
static bool LineTrace(
|
static bool LineTrace(
|
||||||
UWorld *World,
|
UWorld *World,
|
||||||
const FVector &Start,
|
const FVector &Start,
|
||||||
|
@ -207,7 +213,7 @@ static bool LineTrace(
|
||||||
|
|
||||||
if (Success) {
|
if (Success) {
|
||||||
for (FHitResult &Item : OutHits) {
|
for (FHitResult &Item : OutHits) {
|
||||||
if (Item.Component->CustomDepthStencilValue == static_cast<uint8>(CityObjectLabel::Roads)) {
|
if (ATagger::MatchComponent(*Item.Component, ECityObjectLabel::Roads)) {
|
||||||
HitResult = Item;
|
HitResult = Item;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +230,7 @@ void ACityMapGenerator::GenerateRoadMap()
|
||||||
check(GetWorld() != nullptr);
|
check(GetWorld() != nullptr);
|
||||||
check(RoadMap != nullptr);
|
check(RoadMap != nullptr);
|
||||||
|
|
||||||
ATagger::TagActorsInLevel(*GetWorld()); // We need the tags.
|
ATagger::TagActorsInLevel(*GetWorld(), bTagForSemanticSegmentation); // We need the tags.
|
||||||
|
|
||||||
const float IntersectionSize = CityMapMeshTag::GetRoadIntersectionSize();
|
const float IntersectionSize = CityMapMeshTag::GetRoadIntersectionSize();
|
||||||
const uint32 Margin = IntersectionSize / 2u;
|
const uint32 Margin = IntersectionSize / 2u;
|
||||||
|
@ -237,7 +243,9 @@ void ACityMapGenerator::GenerateRoadMap()
|
||||||
|
|
||||||
const FTransform &ActorTransform = GetActorTransform();
|
const FTransform &ActorTransform = GetActorTransform();
|
||||||
|
|
||||||
RoadMap->RoadMap.Empty();
|
const FVector MapOffset(-Offset, -Offset, 0.0f);
|
||||||
|
RoadMap->Reset(SizeX, SizeY, 1.0f / CmPerPixel, ActorTransform.Inverse(), MapOffset);
|
||||||
|
|
||||||
for (uint32 PixelY = 0u; PixelY < SizeY; ++PixelY) {
|
for (uint32 PixelY = 0u; PixelY < SizeY; ++PixelY) {
|
||||||
for (uint32 PixelX = 0u; PixelX < SizeX; ++PixelX) {
|
for (uint32 PixelX = 0u; PixelX < SizeX; ++PixelX) {
|
||||||
const float X = static_cast<float>(PixelX) * CmPerPixel - Offset;
|
const float X = static_cast<float>(PixelX) * CmPerPixel - Offset;
|
||||||
|
@ -245,8 +253,6 @@ void ACityMapGenerator::GenerateRoadMap()
|
||||||
const FVector Start = ActorTransform.TransformPosition(FVector(X, Y, 50.0f));
|
const FVector Start = ActorTransform.TransformPosition(FVector(X, Y, 50.0f));
|
||||||
const FVector End = ActorTransform.TransformPosition(FVector(X, Y, -50.0f));
|
const FVector End = ActorTransform.TransformPosition(FVector(X, Y, -50.0f));
|
||||||
|
|
||||||
bool Success = false;
|
|
||||||
|
|
||||||
// Do the ray tracing.
|
// Do the ray tracing.
|
||||||
FHitResult Hit;
|
FHitResult Hit;
|
||||||
if (LineTrace(World, Start, End, Hit)) {
|
if (LineTrace(World, Start, End, Hit)) {
|
||||||
|
@ -258,39 +264,21 @@ void ACityMapGenerator::GenerateRoadMap()
|
||||||
if (!InstancedStaticMeshComponent->GetInstanceTransform(Hit.Item, InstanceTransform, true)) {
|
if (!InstancedStaticMeshComponent->GetInstanceTransform(Hit.Item, InstanceTransform, true)) {
|
||||||
UE_LOG(LogCarla, Error, TEXT("Failed to get instance's transform"));
|
UE_LOG(LogCarla, Error, TEXT("Failed to get instance's transform"));
|
||||||
} else {
|
} else {
|
||||||
RoadMap->AppendPixel(
|
RoadMap->SetPixelAt(
|
||||||
|
PixelX,
|
||||||
|
PixelY,
|
||||||
GetTag(*InstancedStaticMeshComponent->GetStaticMesh()),
|
GetTag(*InstancedStaticMeshComponent->GetStaticMesh()),
|
||||||
InstanceTransform,
|
InstanceTransform,
|
||||||
bLeftHandTraffic);
|
bLeftHandTraffic);
|
||||||
Success = true;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Success) {
|
#ifdef WITH_EDITOR
|
||||||
RoadMap->AppendEmptyPixel();
|
RoadMap->Log();
|
||||||
}
|
#endif // WITH_EDITOR
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
if (bSaveRoadMapToDisk) {
|
||||||
const FString MapName = World->GetMapName() + TEXT(".png");
|
const FString MapName = World->GetMapName() + TEXT(".png");
|
||||||
|
@ -298,5 +286,7 @@ void ACityMapGenerator::GenerateRoadMap()
|
||||||
RoadMap->SaveAsPNG(FilePath);
|
RoadMap->SaveAsPNG(FilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
RoadMap->DrawDebugPixelsToLevel(GetWorld(), !bDrawDebugPixelsToLevel);
|
RoadMap->DrawDebugPixelsToLevel(GetWorld(), !bDrawDebugPixelsToLevel);
|
||||||
|
#endif // WITH_EDITOR
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,14 @@ private:
|
||||||
UPROPERTY(Category = "Road Map", EditAnywhere, AdvancedDisplay)
|
UPROPERTY(Category = "Road Map", EditAnywhere, AdvancedDisplay)
|
||||||
bool bGenerateRoadMapOnSave = true;
|
bool bGenerateRoadMapOnSave = true;
|
||||||
|
|
||||||
|
/** If true, activate the custom depth pass of each tagged actor in the level.
|
||||||
|
* This pass is necessary for rendering the semantic segmentation. However,
|
||||||
|
* it may add a performance penalty since occlusion doesn't seem to be
|
||||||
|
* applied to objects having this value active.
|
||||||
|
*/
|
||||||
|
UPROPERTY(Category = "Road Map", EditAnywhere, AdvancedDisplay)
|
||||||
|
bool bTagForSemanticSegmentation = false;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
URoadMap *RoadMap;
|
URoadMap *RoadMap;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||||
|
|
||||||
|
#include "Carla.h"
|
||||||
|
#include "DynamicWeather.h"
|
||||||
|
|
||||||
|
#include "Components/ArrowComponent.h"
|
||||||
|
|
||||||
|
ADynamicWeather::ADynamicWeather(const FObjectInitializer& ObjectInitializer)
|
||||||
|
{
|
||||||
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
|
|
||||||
|
RootComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComponent0"));
|
||||||
|
|
||||||
|
#if WITH_EDITORONLY_DATA
|
||||||
|
ArrowComponent = CreateEditorOnlyDefaultSubobject<UArrowComponent>(TEXT("ArrowComponent0"));
|
||||||
|
if (ArrowComponent) {
|
||||||
|
ArrowComponent->ArrowColor = FColor(150, 200, 255);
|
||||||
|
ArrowComponent->bTreatAsASprite = true;
|
||||||
|
ArrowComponent->SpriteInfo.Category = TEXT("Lighting");
|
||||||
|
ArrowComponent->SpriteInfo.DisplayName = NSLOCTEXT( "SpriteCategory", "Lighting", "Lighting" );
|
||||||
|
ArrowComponent->SetupAttachment(RootComponent);
|
||||||
|
ArrowComponent->bLightAttachment = true;
|
||||||
|
ArrowComponent->bIsScreenSizeScaled = true;
|
||||||
|
}
|
||||||
|
#endif // WITH_EDITORONLY_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicWeather::OnConstruction(const FTransform &Transform)
|
||||||
|
{
|
||||||
|
Super::OnConstruction(Transform);
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
|
||||||
|
void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event)
|
||||||
|
{
|
||||||
|
Super::PostEditChangeProperty(Event);
|
||||||
|
const FName PropertyName = (Event.Property != NULL ? Event.Property->GetFName() : NAME_None);
|
||||||
|
if (PropertyName == GET_MEMBER_NAME_CHECKED(ADynamicWeather, Weather)) {
|
||||||
|
Update();
|
||||||
|
} else {
|
||||||
|
AdjustSunPositionBasedOnActorRotation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicWeather::EditorApplyRotation(
|
||||||
|
const FRotator &DeltaRotation,
|
||||||
|
bool bAltDown,
|
||||||
|
bool bShiftDown,
|
||||||
|
bool bCtrlDown)
|
||||||
|
{
|
||||||
|
Super::EditorApplyRotation(DeltaRotation, bAltDown, bShiftDown, bCtrlDown);
|
||||||
|
AdjustSunPositionBasedOnActorRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WITH_EDITOR
|
||||||
|
|
||||||
|
FVector ADynamicWeather::GetSunDirection() const
|
||||||
|
{
|
||||||
|
const FVector2D SphericalCoords(
|
||||||
|
FMath::DegreesToRadians(Weather.SunPolarAngle),
|
||||||
|
FMath::DegreesToRadians(Weather.SunAzimuthAngle));
|
||||||
|
return - SphericalCoords.SphericalToUnitCartesian();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicWeather::Update()
|
||||||
|
{
|
||||||
|
// Modify this actor's rotation according to Sun position.
|
||||||
|
if (!SetActorRotation(FQuat(GetSunDirection().Rotation()), ETeleportType::None)) {
|
||||||
|
UE_LOG(LogCarla, Warning, TEXT("Unable to rotate actor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshWeather();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicWeather::AdjustSunPositionBasedOnActorRotation()
|
||||||
|
{
|
||||||
|
const FVector Direction = - GetActorQuat().GetForwardVector();
|
||||||
|
const FVector2D SphericalCoords = Direction.UnitCartesianToSpherical();
|
||||||
|
Weather.SunPolarAngle = FMath::RadiansToDegrees(SphericalCoords.X);
|
||||||
|
Weather.SunAzimuthAngle = FMath::RadiansToDegrees(SphericalCoords.Y);
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "WeatherDescription.h"
|
||||||
|
#include "DynamicWeather.generated.h"
|
||||||
|
|
||||||
|
class UArrowComponent;
|
||||||
|
|
||||||
|
UCLASS(Abstract)
|
||||||
|
class CARLA_API ADynamicWeather : public AActor
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ADynamicWeather(const FObjectInitializer& ObjectInitializer);
|
||||||
|
|
||||||
|
virtual void OnConstruction(const FTransform &Transform) override;
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
|
||||||
|
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||||
|
|
||||||
|
virtual void EditorApplyRotation(const FRotator & DeltaRotation, bool bAltDown, bool bShiftDown, bool bCtrlDown) override;
|
||||||
|
|
||||||
|
#endif // WITH_EDITOR
|
||||||
|
|
||||||
|
void SetWeatherDescription(const FWeatherDescription &WeatherDescription)
|
||||||
|
{
|
||||||
|
Weather = WeatherDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
const FWeatherDescription &GetWeatherDescription() const
|
||||||
|
{
|
||||||
|
return Weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintImplementableEvent)
|
||||||
|
void RefreshWeather();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
FVector GetSunDirection() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
void AdjustSunPositionBasedOnActorRotation();
|
||||||
|
|
||||||
|
#if WITH_EDITORONLY_DATA
|
||||||
|
UPROPERTY()
|
||||||
|
UArrowComponent* ArrowComponent;
|
||||||
|
#endif // WITH_EDITORONLY_DATA
|
||||||
|
|
||||||
|
UPROPERTY(Category = "Weather", EditAnywhere)
|
||||||
|
FWeatherDescription Weather;
|
||||||
|
};
|
|
@ -70,7 +70,9 @@ void ACarlaGameMode::RestartPlayer(AController* NewPlayer)
|
||||||
void ACarlaGameMode::BeginPlay()
|
void ACarlaGameMode::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
if (GameInstance->GetCarlaSettings().bSemanticSegmentationEnabled) {
|
||||||
TagActorsForSemanticSegmentation();
|
TagActorsForSemanticSegmentation();
|
||||||
|
}
|
||||||
GameController->BeginPlay();
|
GameController->BeginPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +107,7 @@ void ACarlaGameMode::AttachCaptureCamerasToPlayer(AController &Player)
|
||||||
void ACarlaGameMode::TagActorsForSemanticSegmentation()
|
void ACarlaGameMode::TagActorsForSemanticSegmentation()
|
||||||
{
|
{
|
||||||
check(GetWorld() != nullptr);
|
check(GetWorld() != nullptr);
|
||||||
ATagger::TagActorsInLevel(*GetWorld());
|
ATagger::TagActorsInLevel(*GetWorld(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
APlayerStart *ACarlaGameMode::FindUnOccupiedStartPoints(
|
APlayerStart *ACarlaGameMode::FindUnOccupiedStartPoints(
|
||||||
|
|
|
@ -39,9 +39,23 @@ void ACarlaPlayerState::CopyProperties(APlayerState *PlayerState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACarlaPlayerState::RegisterCollision(AActor * /*Actor*/, FVector NormalImpulse)
|
void ACarlaPlayerState::RegisterCollision(
|
||||||
|
AActor * /*Actor*/,
|
||||||
|
AActor * /*OtherActor*/,
|
||||||
|
const FVector &NormalImpulse,
|
||||||
|
const FHitResult &Hit)
|
||||||
{
|
{
|
||||||
|
switch (ATagger::GetTagOfTaggedComponent(*Hit.Component)) {
|
||||||
|
case ECityObjectLabel::Vehicles:
|
||||||
|
CollisionIntensityCars += NormalImpulse.Size();
|
||||||
|
break;
|
||||||
|
case ECityObjectLabel::Pedestrians:
|
||||||
|
CollisionIntensityPedestrians += NormalImpulse.Size();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
CollisionIntensityOther += NormalImpulse.Size();
|
CollisionIntensityOther += NormalImpulse.Size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32 RoundToMilliseconds(float Seconds)
|
static int32 RoundToMilliseconds(float Seconds)
|
||||||
|
|
|
@ -130,7 +130,11 @@ public:
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void RegisterCollision(AActor *Actor, FVector NormalImpulse);
|
void RegisterCollision(
|
||||||
|
AActor *Actor,
|
||||||
|
AActor *OtherActor,
|
||||||
|
const FVector &NormalImpulse,
|
||||||
|
const FHitResult &Hit);
|
||||||
|
|
||||||
void UpdateTimeStamp(float DeltaSeconds);
|
void UpdateTimeStamp(float DeltaSeconds);
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,11 @@ static void ValidateCameraDescription(FCameraDescription &Camera)
|
||||||
Camera.ImageSizeY = (Camera.ImageSizeY == 0u ? 512u : Camera.ImageSizeY);
|
Camera.ImageSizeY = (Camera.ImageSizeY == 0u ? 512u : Camera.ImageSizeY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool RequestedSemanticSegmentation(const FCameraDescription &Camera)
|
||||||
|
{
|
||||||
|
return (Camera.PostProcessEffect == EPostProcessEffect::SemanticSegmentation);
|
||||||
|
}
|
||||||
|
|
||||||
static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settings)
|
static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settings)
|
||||||
{
|
{
|
||||||
UE_LOG(LogCarla, Log, TEXT("Loading settings from \"%s\""), *FileName);
|
UE_LOG(LogCarla, Log, TEXT("Loading settings from \"%s\""), *FileName);
|
||||||
|
@ -141,6 +146,7 @@ static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settin
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateCameraDescription(Camera);
|
ValidateCameraDescription(Camera);
|
||||||
|
Settings.bSemanticSegmentationEnabled |= RequestedSemanticSegmentation(Camera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +154,9 @@ static bool GetSettingsFileName(FString &Value)
|
||||||
{
|
{
|
||||||
// Try to get it from the command-line arguments.
|
// Try to get it from the command-line arguments.
|
||||||
if (FParse::Value(FCommandLine::Get(), TEXT("-carla-settings="), Value)) {
|
if (FParse::Value(FCommandLine::Get(), TEXT("-carla-settings="), Value)) {
|
||||||
|
if (FPaths::IsRelative(Value)) {
|
||||||
|
Value = FPaths::ConvertRelativePathToFull(FPaths::LaunchDir(), Value);
|
||||||
|
}
|
||||||
if (FPaths::FileExists(Value)) {
|
if (FPaths::FileExists(Value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +192,7 @@ void UCarlaSettings::LoadSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UCarlaSettings::LogSettings()
|
void UCarlaSettings::LogSettings() const
|
||||||
{
|
{
|
||||||
UE_LOG(LogCarla, Log, TEXT("== CARLA Settings =============================================================="));
|
UE_LOG(LogCarla, Log, TEXT("== CARLA Settings =============================================================="));
|
||||||
UE_LOG(LogCarla, Log, TEXT("Settings file: %s"), *CurrentFileName);
|
UE_LOG(LogCarla, Log, TEXT("Settings file: %s"), *CurrentFileName);
|
||||||
|
@ -194,6 +203,7 @@ void UCarlaSettings::LogSettings()
|
||||||
UE_LOG(LogCarla, Log, TEXT("Read Port = %d"), ReadPort);
|
UE_LOG(LogCarla, Log, TEXT("Read Port = %d"), ReadPort);
|
||||||
UE_LOG(LogCarla, Log, TEXT("[%s]"), S_CARLA_SCENECAPTURE);
|
UE_LOG(LogCarla, Log, TEXT("[%s]"), S_CARLA_SCENECAPTURE);
|
||||||
UE_LOG(LogCarla, Log, TEXT("Added %d cameras."), CameraDescriptions.Num());
|
UE_LOG(LogCarla, Log, TEXT("Added %d cameras."), CameraDescriptions.Num());
|
||||||
|
UE_LOG(LogCarla, Log, TEXT("Semantic Segmentation = %s"), (bSemanticSegmentationEnabled ? TEXT("enabled") : TEXT("disabled")));
|
||||||
for (auto &Item : CameraDescriptions) {
|
for (auto &Item : CameraDescriptions) {
|
||||||
UE_LOG(LogCarla, Log, TEXT("[%s/%s]"), S_CARLA_SCENECAPTURE, *Item.Key);
|
UE_LOG(LogCarla, Log, TEXT("[%s/%s]"), S_CARLA_SCENECAPTURE, *Item.Key);
|
||||||
UE_LOG(LogCarla, Log, TEXT("Image Size = %dx%d"), Item.Value.ImageSizeX, Item.Value.ImageSizeY);
|
UE_LOG(LogCarla, Log, TEXT("Image Size = %dx%d"), Item.Value.ImageSizeX, Item.Value.ImageSizeY);
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
void LoadSettings();
|
void LoadSettings();
|
||||||
|
|
||||||
/** Log settings values. */
|
/** Log settings values. */
|
||||||
void LogSettings();
|
void LogSettings() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -59,5 +59,12 @@ public:
|
||||||
UPROPERTY(Category = "Scene Capture", EditDefaultsOnly)
|
UPROPERTY(Category = "Scene Capture", EditDefaultsOnly)
|
||||||
TMap<FString, FCameraDescription> CameraDescriptions;
|
TMap<FString, FCameraDescription> CameraDescriptions;
|
||||||
|
|
||||||
|
/** Whether semantic segmentation should be activated. The mechanisms for
|
||||||
|
* semantic segmentation impose some performance penalties even if it is not
|
||||||
|
* used, we only enable it if necessary.
|
||||||
|
*/
|
||||||
|
UPROPERTY(Category = "Scene Capture", EditDefaultsOnly)
|
||||||
|
bool bSemanticSegmentationEnabled = false;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
|
@ -251,12 +251,12 @@ void ACarlaVehicleController::ToggleManualMode()
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
void ACarlaVehicleController::OnCollisionEvent(
|
void ACarlaVehicleController::OnCollisionEvent(
|
||||||
AActor* /*Actor*/,
|
AActor* Actor,
|
||||||
AActor* OtherActor,
|
AActor* OtherActor,
|
||||||
FVector NormalImpulse,
|
FVector NormalImpulse,
|
||||||
const FHitResult& /*Hit*/)
|
const FHitResult& Hit)
|
||||||
{
|
{
|
||||||
CarlaPlayerState->RegisterCollision(OtherActor, NormalImpulse);
|
CarlaPlayerState->RegisterCollision(Actor, OtherActor, NormalImpulse, Hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
@ -20,6 +20,12 @@ enum class ECityMapMeshTag : uint8
|
||||||
Road90DegTurn_Lane1 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 1"),
|
Road90DegTurn_Lane1 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 1"),
|
||||||
Road90DegTurn_Lane2 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 2"),
|
Road90DegTurn_Lane2 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 2"),
|
||||||
Road90DegTurn_Lane3 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 3"),
|
Road90DegTurn_Lane3 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 3"),
|
||||||
|
Road90DegTurn_Lane4 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 4"),
|
||||||
|
Road90DegTurn_Lane5 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 5"),
|
||||||
|
Road90DegTurn_Lane6 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 6"),
|
||||||
|
Road90DegTurn_Lane7 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 7"),
|
||||||
|
Road90DegTurn_Lane8 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 8"),
|
||||||
|
Road90DegTurn_Lane9 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 9"),
|
||||||
Road90DegTurn_Sidewalk0 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 0"),
|
Road90DegTurn_Sidewalk0 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 0"),
|
||||||
Road90DegTurn_Sidewalk1 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 1"),
|
Road90DegTurn_Sidewalk1 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 1"),
|
||||||
Road90DegTurn_Sidewalk2 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 2"),
|
Road90DegTurn_Sidewalk2 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 2"),
|
||||||
|
@ -30,6 +36,12 @@ enum class ECityMapMeshTag : uint8
|
||||||
RoadTIntersection_Lane1 UMETA(DisplayName = "Road: T-Intersection - Lane 1"),
|
RoadTIntersection_Lane1 UMETA(DisplayName = "Road: T-Intersection - Lane 1"),
|
||||||
RoadTIntersection_Lane2 UMETA(DisplayName = "Road: T-Intersection - Lane 2"),
|
RoadTIntersection_Lane2 UMETA(DisplayName = "Road: T-Intersection - Lane 2"),
|
||||||
RoadTIntersection_Lane3 UMETA(DisplayName = "Road: T-Intersection - Lane 3"),
|
RoadTIntersection_Lane3 UMETA(DisplayName = "Road: T-Intersection - Lane 3"),
|
||||||
|
RoadTIntersection_Lane4 UMETA(DisplayName = "Road: T-Intersection - Lane 4"),
|
||||||
|
RoadTIntersection_Lane5 UMETA(DisplayName = "Road: T-Intersection - Lane 5"),
|
||||||
|
RoadTIntersection_Lane6 UMETA(DisplayName = "Road: T-Intersection - Lane 6"),
|
||||||
|
RoadTIntersection_Lane7 UMETA(DisplayName = "Road: T-Intersection - Lane 7"),
|
||||||
|
RoadTIntersection_Lane8 UMETA(DisplayName = "Road: T-Intersection - Lane 8"),
|
||||||
|
RoadTIntersection_Lane9 UMETA(DisplayName = "Road: T-Intersection - Lane 9"),
|
||||||
RoadTIntersection_Sidewalk0 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 0"),
|
RoadTIntersection_Sidewalk0 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 0"),
|
||||||
RoadTIntersection_Sidewalk1 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 1"),
|
RoadTIntersection_Sidewalk1 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 1"),
|
||||||
RoadTIntersection_Sidewalk2 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 2"),
|
RoadTIntersection_Sidewalk2 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 2"),
|
||||||
|
@ -40,6 +52,12 @@ enum class ECityMapMeshTag : uint8
|
||||||
RoadXIntersection_Lane1 UMETA(DisplayName = "Road: X-Intersection - Lane 1"),
|
RoadXIntersection_Lane1 UMETA(DisplayName = "Road: X-Intersection - Lane 1"),
|
||||||
RoadXIntersection_Lane2 UMETA(DisplayName = "Road: X-Intersection - Lane 2"),
|
RoadXIntersection_Lane2 UMETA(DisplayName = "Road: X-Intersection - Lane 2"),
|
||||||
RoadXIntersection_Lane3 UMETA(DisplayName = "Road: X-Intersection - Lane 3"),
|
RoadXIntersection_Lane3 UMETA(DisplayName = "Road: X-Intersection - Lane 3"),
|
||||||
|
RoadXIntersection_Lane4 UMETA(DisplayName = "Road: X-Intersection - Lane 4"),
|
||||||
|
RoadXIntersection_Lane5 UMETA(DisplayName = "Road: X-Intersection - Lane 5"),
|
||||||
|
RoadXIntersection_Lane6 UMETA(DisplayName = "Road: X-Intersection - Lane 6"),
|
||||||
|
RoadXIntersection_Lane7 UMETA(DisplayName = "Road: X-Intersection - Lane 7"),
|
||||||
|
RoadXIntersection_Lane8 UMETA(DisplayName = "Road: X-Intersection - Lane 8"),
|
||||||
|
RoadXIntersection_Lane9 UMETA(DisplayName = "Road: X-Intersection - Lane 9"),
|
||||||
RoadXIntersection_Sidewalk0 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 0"),
|
RoadXIntersection_Sidewalk0 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 0"),
|
||||||
RoadXIntersection_Sidewalk1 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 1"),
|
RoadXIntersection_Sidewalk1 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 1"),
|
||||||
RoadXIntersection_Sidewalk2 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 2"),
|
RoadXIntersection_Sidewalk2 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 2"),
|
||||||
|
|
|
@ -3,22 +3,190 @@
|
||||||
#include "Carla.h"
|
#include "Carla.h"
|
||||||
#include "RoadMap.h"
|
#include "RoadMap.h"
|
||||||
|
|
||||||
#include "DrawDebugHelpers.h"
|
|
||||||
#include "HighResScreenshot.h"
|
#include "HighResScreenshot.h"
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
#include "DrawDebugHelpers.h"
|
||||||
|
#endif // WITH_EDITOR
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
/// ============================================================================
|
||||||
|
/// -- Static local methods ----------------------------------------------------
|
||||||
|
/// ============================================================================
|
||||||
|
|
||||||
static uint32 ClampFloatToUInt(const float Value, int32 Min, int32 Max)
|
static uint32 ClampFloatToUInt(const float Value, int32 Min, int32 Max)
|
||||||
{
|
{
|
||||||
return FMath::Clamp(FMath::FloorToInt(Value), Min, Max);
|
return FMath::Clamp(FMath::FloorToInt(Value), Min, Max);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a valid empty map (every point is off-road).
|
// Return the azimuth angle (in spherical coordinates) rotated by PI so it lies
|
||||||
|
// in the range [0, 2*PI].
|
||||||
|
static float GetRotatedAzimuthAngle(const FVector &Direction)
|
||||||
|
{
|
||||||
|
const FVector2D SphericalCoords = Direction.UnitCartesianToSpherical();
|
||||||
|
return SphericalCoords.Y + PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ============================================================================
|
||||||
|
/// -- FRoadMapPixelData -------------------------------------------------------
|
||||||
|
/// ============================================================================
|
||||||
|
|
||||||
|
uint16 FRoadMapPixelData::Encode(bool IsRoad, bool HasDirection, const FVector &Direction)
|
||||||
|
{
|
||||||
|
const uint16 AngleAsUInt = MaximumEncodedAngle * GetRotatedAzimuthAngle(Direction) / (2.0f * PI);
|
||||||
|
check(!(AngleAsUInt & (1 << IsRoadRow)));
|
||||||
|
check(!(AngleAsUInt & (1 << HasDirectionRow)));
|
||||||
|
return (IsRoad << IsRoadRow) | (HasDirection << HasDirectionRow) | (AngleAsUInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
FColor FRoadMapPixelData::EncodeAsColor() const
|
||||||
|
{
|
||||||
|
if (!IsRoad()) {
|
||||||
|
return FColor(0u, 0u, 0u, 255u);
|
||||||
|
} else if (!HasDirection()) {
|
||||||
|
return FColor(255u, 255u, 255u, 255u);
|
||||||
|
} else {
|
||||||
|
auto ToColor = [](float X){
|
||||||
|
return FMath::FloorToInt(256.0 * (X + PI) / (2.0f * PI)) % 256;
|
||||||
|
};
|
||||||
|
const float Azimuth = GetDirectionAzimuthalAngle();
|
||||||
|
return FColor(0u, 255u, ToColor(Azimuth), 255u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ============================================================================
|
||||||
|
/// -- URoadMap ----------------------------------------------------------------
|
||||||
|
/// ============================================================================
|
||||||
|
|
||||||
URoadMap::URoadMap(const FObjectInitializer& ObjectInitializer) :
|
URoadMap::URoadMap(const FObjectInitializer& ObjectInitializer) :
|
||||||
Super(ObjectInitializer),
|
Super(ObjectInitializer),
|
||||||
PixelsPerCentimeter(1.0f),
|
PixelsPerCentimeter(1.0f),
|
||||||
Width(1u),
|
Width(1u),
|
||||||
Height(1u)
|
Height(1u)
|
||||||
{
|
{
|
||||||
AppendEmptyPixel();
|
RoadMapData.Add(0u);
|
||||||
|
static_assert(
|
||||||
|
std::is_same<decltype(FRoadMapPixelData::Value), typename decltype(RoadMapData)::ElementType>::value,
|
||||||
|
"Declaration map of FRoadMapPixelData's value does not match current serialization type");
|
||||||
|
}
|
||||||
|
|
||||||
|
void URoadMap::Reset(
|
||||||
|
const uint32 inWidth,
|
||||||
|
const uint32 inHeight,
|
||||||
|
const float inPixelsPerCentimeter,
|
||||||
|
const FTransform &inWorldToMap,
|
||||||
|
const FVector &inMapOffset)
|
||||||
|
{
|
||||||
|
RoadMapData.Init(0u, inWidth * inHeight);
|
||||||
|
Width = inWidth;
|
||||||
|
Height = inHeight;
|
||||||
|
PixelsPerCentimeter = inPixelsPerCentimeter;
|
||||||
|
WorldToMap = inWorldToMap;
|
||||||
|
MapOffset = inMapOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void URoadMap::SetPixelAt(
|
||||||
|
const uint32 PixelX,
|
||||||
|
const uint32 PixelY,
|
||||||
|
const ECityMapMeshTag Tag,
|
||||||
|
const FTransform &Transform,
|
||||||
|
const bool bInvertDirection)
|
||||||
|
{
|
||||||
|
bool bIsRoad = false;
|
||||||
|
bool bHasDirection = false;
|
||||||
|
FVector Direction(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
auto Rotator = Transform.GetRotation().Rotator();
|
||||||
|
|
||||||
|
switch (Tag) {
|
||||||
|
default:
|
||||||
|
// It's not road.
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::RoadTwoLanes_LaneRight:
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane1:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane1:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane9:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane1:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane9:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 180.0f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::RoadTwoLanes_LaneLeft:
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane0:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane0:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane2:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane5:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane8:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane0:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane8:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane9:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane7:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane7:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane5:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 90.0f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane7:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 90.0f + 22.5f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane5:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 90.0f + 45.0f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane3:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 90.0f + 45.0f + 22.5f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane8:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane4:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane2:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane4:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 270.0f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane6:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 270.0f + 22.5f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane4:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 270.0f + 45.0f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::Road90DegTurn_Lane2:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = true;
|
||||||
|
Rotator.Yaw += 270.0f + 45.0f + 22.5f;
|
||||||
|
break;
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane3:
|
||||||
|
case ECityMapMeshTag::RoadTIntersection_Lane6:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane3:
|
||||||
|
case ECityMapMeshTag::RoadXIntersection_Lane6:
|
||||||
|
bIsRoad = true;
|
||||||
|
bHasDirection = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (bHasDirection) {
|
||||||
|
FQuat Rotation(Rotator);
|
||||||
|
Direction = Rotation.GetForwardVector();
|
||||||
|
if (bInvertDirection) {
|
||||||
|
Direction *= -1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto Value = FRoadMapPixelData::Encode(bIsRoad, bHasDirection, Direction);
|
||||||
|
RoadMapData[GetIndex(PixelX, PixelY)] = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector URoadMap::GetWorldLocation(uint32 PixelX, uint32 PixelY) const
|
FVector URoadMap::GetWorldLocation(uint32 PixelX, uint32 PixelY) const
|
||||||
|
@ -30,7 +198,7 @@ FVector URoadMap::GetWorldLocation(uint32 PixelX, uint32 PixelY) const
|
||||||
return WorldToMap.InverseTransformPosition(RelativePosition + MapOffset);
|
return WorldToMap.InverseTransformPosition(RelativePosition + MapOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FRoadMapPixelData &URoadMap::GetDataAt(const FVector &WorldLocation) const
|
FRoadMapPixelData URoadMap::GetDataAt(const FVector &WorldLocation) const
|
||||||
{
|
{
|
||||||
check(IsValid());
|
check(IsValid());
|
||||||
const FVector Location = WorldToMap.TransformPosition(WorldLocation) - MapOffset;
|
const FVector Location = WorldToMap.TransformPosition(WorldLocation) - MapOffset;
|
||||||
|
@ -44,7 +212,8 @@ FRoadMapIntersectionResult URoadMap::Intersect(
|
||||||
const FVector &BoxExtent,
|
const FVector &BoxExtent,
|
||||||
float ChecksPerCentimeter) const
|
float ChecksPerCentimeter) const
|
||||||
{
|
{
|
||||||
const auto &DirectionOfMovement = BoxTransform.GetRotation().GetForwardVector();
|
auto DirectionOfMovement = BoxTransform.GetRotation().GetForwardVector();
|
||||||
|
DirectionOfMovement.Z = 0.0f; // Project to XY plane (won't be normalized anymore).
|
||||||
uint32 CheckCount = 0u;
|
uint32 CheckCount = 0u;
|
||||||
FRoadMapIntersectionResult Result = {0.0f, 0.0f};
|
FRoadMapIntersectionResult Result = {0.0f, 0.0f};
|
||||||
const float Step = 1.0f / ChecksPerCentimeter;
|
const float Step = 1.0f / ChecksPerCentimeter;
|
||||||
|
@ -52,11 +221,11 @@ FRoadMapIntersectionResult URoadMap::Intersect(
|
||||||
for (float Y = -BoxExtent.Y; Y < BoxExtent.Y; Y += Step) {
|
for (float Y = -BoxExtent.Y; Y < BoxExtent.Y; Y += Step) {
|
||||||
++CheckCount;
|
++CheckCount;
|
||||||
auto Location = BoxTransform.TransformPosition(FVector(X, Y, 0.0f));
|
auto Location = BoxTransform.TransformPosition(FVector(X, Y, 0.0f));
|
||||||
auto &Data = GetDataAt(Location);
|
const auto &Data = GetDataAt(Location);
|
||||||
if (Data.bIsOffRoad) {
|
if (!Data.IsRoad()) {
|
||||||
Result.OffRoad += 1.0f;
|
Result.OffRoad += 1.0f;
|
||||||
} else if (Data.bHasDirection &&
|
} else if (Data.HasDirection() &&
|
||||||
0.0f < FVector::DotProduct(Data.Direction, DirectionOfMovement)) {
|
0.0f > FVector::DotProduct(Data.GetDirection(), DirectionOfMovement)) {
|
||||||
Result.OppositeLane += 1.0f;
|
Result.OppositeLane += 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,21 +239,6 @@ FRoadMapIntersectionResult URoadMap::Intersect(
|
||||||
return Result;
|
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
|
bool URoadMap::SaveAsPNG(const FString &Path) const
|
||||||
{
|
{
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
|
@ -93,80 +247,61 @@ bool URoadMap::SaveAsPNG(const FString &Path) const
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<FColor> BitMap;
|
TArray<FColor> BitMap;
|
||||||
for (auto &Data : RoadMap) {
|
for (auto Value : RoadMapData) {
|
||||||
BitMap.Emplace(Encode(Data));
|
BitMap.Emplace(FRoadMapPixelData(Value).EncodeAsColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
FIntPoint DestSize(Width, Height);
|
FIntPoint DestSize(Width, Height);
|
||||||
FString ResultPath;
|
FString ResultPath;
|
||||||
FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
|
FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
|
||||||
|
HighResScreenshotConfig.SetHDRCapture(false);
|
||||||
HighResScreenshotConfig.SaveImage(Path, BitMap, DestSize, &ResultPath);
|
HighResScreenshotConfig.SaveImage(Path, BitMap, DestSize, &ResultPath);
|
||||||
|
|
||||||
UE_LOG(LogCarla, Log, TEXT("Saved road map to \"%s\""), *ResultPath);
|
UE_LOG(LogCarla, Log, TEXT("Saved road map to \"%s\""), *ResultPath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
|
||||||
|
void URoadMap::Log() const
|
||||||
|
{
|
||||||
|
const float MapSizeInMB = // Only map data, not the class itself.
|
||||||
|
static_cast<float>(sizeof(decltype(RoadMapData)::ElementType) * RoadMapData.Num()) /
|
||||||
|
(1024.0f * 1024.0f);
|
||||||
|
UE_LOG(
|
||||||
|
LogCarla,
|
||||||
|
Log,
|
||||||
|
TEXT("Generated road map %dx%d (%.2fMB) with %.2f cm/pixel"),
|
||||||
|
GetWidth(),
|
||||||
|
GetHeight(),
|
||||||
|
MapSizeInMB,
|
||||||
|
1.0f / PixelsPerCentimeter);
|
||||||
|
|
||||||
|
if (!IsValid()) {
|
||||||
|
UE_LOG(LogCarla, Error, TEXT("Error generating road map"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void URoadMap::DrawDebugPixelsToLevel(UWorld *World, const bool bJustFlushDoNotDraw) const
|
void URoadMap::DrawDebugPixelsToLevel(UWorld *World, const bool bJustFlushDoNotDraw) const
|
||||||
{
|
{
|
||||||
|
const FVector ZOffset(0.0f, 0.0f, 50.0f);
|
||||||
FlushPersistentDebugLines(World);
|
FlushPersistentDebugLines(World);
|
||||||
if (!bJustFlushDoNotDraw) {
|
if (!bJustFlushDoNotDraw) {
|
||||||
for (auto X = 0u; X < Width; ++X) {
|
for (auto X = 0u; X < Width; ++X) {
|
||||||
for (auto Y = 0u; Y < Height; ++Y) {
|
for (auto Y = 0u; Y < Height; ++Y) {
|
||||||
auto Location = GetWorldLocation(X, Y);
|
auto Location = GetWorldLocation(X, Y) + ZOffset;
|
||||||
auto Color = Encode(GetDataAt(X, Y));
|
const auto &Data = GetDataAt(X, Y);
|
||||||
DrawDebugPoint(World, Location, 20.0f, Color, true);
|
auto Color = Data.EncodeAsColor();
|
||||||
|
if (Data.HasDirection()) {
|
||||||
|
const FVector ArrowEnd = Location + 50.0f * Data.GetDirection();
|
||||||
|
DrawDebugDirectionalArrow(World, Location, ArrowEnd, 60.0f, Color, true);
|
||||||
|
} else {
|
||||||
|
DrawDebugPoint(World, Location, 6.0f, Color, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void URoadMap::AppendPixel(
|
#endif // WITH_EDITOR
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,33 +5,78 @@
|
||||||
#include "UObject/NoExportTypes.h"
|
#include "UObject/NoExportTypes.h"
|
||||||
#include "RoadMap.generated.h"
|
#include "RoadMap.generated.h"
|
||||||
|
|
||||||
|
/// Road map intersection result. See URoadMap.
|
||||||
USTRUCT()
|
USTRUCT()
|
||||||
struct FRoadMapIntersectionResult
|
struct FRoadMapIntersectionResult
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
/** Percentage of the box lying off-road */
|
/// Percentage of the box lying off-road.
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||||
float OffRoad;
|
float OffRoad;
|
||||||
|
|
||||||
/** Percentage of the box invading opposite lane (wrong direction) */
|
/// Percentage of the box invading opposite lane (wrong direction).
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||||
float OppositeLane;
|
float OppositeLane;
|
||||||
};
|
};
|
||||||
|
|
||||||
USTRUCT()
|
/// Data stored in a road map pixel. See URoadMap.
|
||||||
struct FRoadMapPixelData
|
struct FRoadMapPixelData
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
friend class URoadMap;
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
constexpr static int IsRoadRow = 15;
|
||||||
bool bIsOffRoad = true;
|
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
constexpr static int HasDirectionRow = 14;
|
||||||
bool bHasDirection = false;
|
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
constexpr static uint16 MaximumEncodedAngle = (1 << 14) - 1;
|
||||||
FVector Direction;
|
|
||||||
|
constexpr static uint16 AngleMask = (0xFFFF >> 2);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit FRoadMapPixelData(uint16 inValue) : Value(inValue) {}
|
||||||
|
|
||||||
|
/// Whether this pixel lies in-road.
|
||||||
|
bool IsRoad() const
|
||||||
|
{
|
||||||
|
return (Value & (1 << IsRoadRow)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this pixel has a direction defined (e.g. road intersections are
|
||||||
|
/// not off-road but neither have defined direction).
|
||||||
|
bool HasDirection() const
|
||||||
|
{
|
||||||
|
return (Value & (1 << HasDirectionRow)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the azimuth angle [-PI, PI] of the road direction (in spherical
|
||||||
|
/// coordinates) at this pixel.
|
||||||
|
///
|
||||||
|
/// Undefined if !HasDirection().
|
||||||
|
float GetDirectionAzimuthalAngle() const
|
||||||
|
{
|
||||||
|
const float Angle = AngleMask & Value;
|
||||||
|
// Internally the angle is rotated by PI.
|
||||||
|
return (Angle * 2.0f * PI / MaximumEncodedAngle) - PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the road direction at this pixel.
|
||||||
|
///
|
||||||
|
/// Undefined if !HasDirection().
|
||||||
|
FVector GetDirection() const
|
||||||
|
{
|
||||||
|
const FVector2D SphericalCoords(HALF_PI, GetDirectionAzimuthalAngle());
|
||||||
|
return SphericalCoords.SphericalToUnitCartesian();
|
||||||
|
}
|
||||||
|
|
||||||
|
FColor EncodeAsColor() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static uint16 Encode(bool IsRoad, bool HasDirection, const FVector &Direction);
|
||||||
|
|
||||||
|
uint16 Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Road map of the level. Contains information in 2D of which areas are road
|
/// Road map of the level. Contains information in 2D of which areas are road
|
||||||
|
@ -43,13 +88,23 @@ class CARLA_API URoadMap : public UObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Creates a valid empty map (every point is off-road).
|
||||||
URoadMap(const FObjectInitializer& ObjectInitializer);
|
URoadMap(const FObjectInitializer& ObjectInitializer);
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable)
|
/// Resets current map an initializes an empty map of the given size.
|
||||||
bool IsValid() const
|
void Reset(
|
||||||
{
|
uint32 Width,
|
||||||
return ((RoadMap.Num() > 0) && (RoadMap.Num() == Height * Width));
|
uint32 Height,
|
||||||
}
|
float PixelsPerCentimeter,
|
||||||
|
const FTransform &WorldToMap,
|
||||||
|
const FVector &MapOffset);
|
||||||
|
|
||||||
|
void SetPixelAt(
|
||||||
|
uint32 PixelX,
|
||||||
|
uint32 PixelY,
|
||||||
|
ECityMapMeshTag Tag,
|
||||||
|
const FTransform &Transform,
|
||||||
|
bool bInvertDirection = false);
|
||||||
|
|
||||||
uint32 GetWidth() const
|
uint32 GetWidth() const
|
||||||
{
|
{
|
||||||
|
@ -61,74 +116,73 @@ public:
|
||||||
return Height;
|
return Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the world location of a given pixel.
|
||||||
FVector GetWorldLocation(uint32 PixelX, uint32 PixelY) const;
|
FVector GetWorldLocation(uint32 PixelX, uint32 PixelY) const;
|
||||||
|
|
||||||
const FRoadMapPixelData &GetDataAt(uint32 PixelX, uint32 PixelY) const
|
/// Retrieve the data stored at a given pixel.
|
||||||
|
FRoadMapPixelData GetDataAt(uint32 PixelX, uint32 PixelY) const
|
||||||
{
|
{
|
||||||
check(IsValid());
|
check(IsValid());
|
||||||
return RoadMap[PixelX + Width * PixelY];
|
return FRoadMapPixelData(RoadMapData[GetIndex(PixelX, PixelY)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clamps value if lies outside map limits */
|
/// Clamps value if lies outside map limits.
|
||||||
UFUNCTION(BlueprintCallable)
|
FRoadMapPixelData GetDataAt(const FVector &WorldLocation) const;
|
||||||
const FRoadMapPixelData &GetDataAt(const FVector &WorldLocation) const;
|
|
||||||
|
|
||||||
/** Intersect actor bounds with map.
|
/// Intersect actor bounds with map.
|
||||||
*
|
///
|
||||||
* Bounds box is projected to the map and checked against it for possible
|
/// Bounds box is projected to the map and checked against it for possible
|
||||||
* intersections with off-road areas and opposite lanes.
|
/// intersections with off-road areas and opposite lanes.
|
||||||
*/
|
|
||||||
UFUNCTION(BlueprintCallable)
|
|
||||||
FRoadMapIntersectionResult Intersect(
|
FRoadMapIntersectionResult Intersect(
|
||||||
const FTransform &BoxTransform,
|
const FTransform &BoxTransform,
|
||||||
const FVector &BoxExtent,
|
const FVector &BoxExtent,
|
||||||
float ChecksPerCentimeter) const;
|
float ChecksPerCentimeter) const;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable)
|
/// Save the current map as PNG with the pixel data encoded as color.
|
||||||
bool SaveAsPNG(const FString &Path) const;
|
bool SaveAsPNG(const FString &Path) const;
|
||||||
|
|
||||||
/** Draw every pixel of the image as debug point */
|
#ifdef WITH_EDITOR
|
||||||
UFUNCTION(BlueprintCallable)
|
|
||||||
|
/// Log status of the map to the console.
|
||||||
|
void Log() const;
|
||||||
|
|
||||||
|
/// Draw every pixel of the image as debug point.
|
||||||
void DrawDebugPixelsToLevel(UWorld *World, bool bJustFlushDoNotDraw = false) const;
|
void DrawDebugPixelsToLevel(UWorld *World, bool bJustFlushDoNotDraw = false) const;
|
||||||
|
|
||||||
|
#endif // WITH_EDITOR
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class ACityMapGenerator;
|
int32 GetIndex(uint32 PixelX, uint32 PixelY) const
|
||||||
|
|
||||||
void AppendEmptyPixel()
|
|
||||||
{
|
{
|
||||||
RoadMap.AddDefaulted(1);
|
return PixelX + Width * PixelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendPixel(
|
bool IsValid() const
|
||||||
ECityMapMeshTag Tag,
|
{
|
||||||
const FTransform &Transform,
|
return ((RoadMapData.Num() > 0) && (RoadMapData.Num() == Height * Width));
|
||||||
bool bInvertDirection);
|
}
|
||||||
|
|
||||||
void Set(
|
|
||||||
uint32 Width,
|
|
||||||
uint32 Height,
|
|
||||||
float PixelsPerCentimeter,
|
|
||||||
const FTransform &WorldToMap,
|
|
||||||
const FVector &MapOffset);
|
|
||||||
|
|
||||||
|
/// World-to-map transform.
|
||||||
UPROPERTY(VisibleAnywhere)
|
UPROPERTY(VisibleAnywhere)
|
||||||
FTransform WorldToMap;
|
FTransform WorldToMap;
|
||||||
|
|
||||||
|
/// Offset of the map in map coordinates.
|
||||||
UPROPERTY(VisibleAnywhere)
|
UPROPERTY(VisibleAnywhere)
|
||||||
FVector MapOffset;
|
FVector MapOffset;
|
||||||
|
|
||||||
|
/// Number of pixels per centimeter.
|
||||||
UPROPERTY(VisibleAnywhere)
|
UPROPERTY(VisibleAnywhere)
|
||||||
float PixelsPerCentimeter;
|
float PixelsPerCentimeter;
|
||||||
|
|
||||||
/** Width of the map in pixels */
|
/// Width of the map in pixels.
|
||||||
UPROPERTY(VisibleAnywhere)
|
UPROPERTY(VisibleAnywhere)
|
||||||
uint32 Width;
|
uint32 Width;
|
||||||
|
|
||||||
/** Height of the map in pixels */
|
/// Height of the map in pixels.
|
||||||
UPROPERTY(VisibleAnywhere)
|
UPROPERTY(VisibleAnywhere)
|
||||||
uint32 Height;
|
uint32 Height;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<FRoadMapPixelData> RoadMap;
|
TArray<uint16> RoadMapData;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
#include "PhysicsEngine/PhysicsAsset.h"
|
#include "PhysicsEngine/PhysicsAsset.h"
|
||||||
|
|
||||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||||
static FString GetLabelAsString(const CityObjectLabel Label)
|
static FString GetLabelAsString(const ECityObjectLabel Label)
|
||||||
{
|
{
|
||||||
switch (Label) {
|
switch (Label) {
|
||||||
#define CARLA_GET_LABEL_STR(lbl) case CityObjectLabel:: lbl : return #lbl;
|
#define CARLA_GET_LABEL_STR(lbl) case ECityObjectLabel:: lbl : return #lbl;
|
||||||
default:
|
default:
|
||||||
CARLA_GET_LABEL_STR(None)
|
CARLA_GET_LABEL_STR(None)
|
||||||
CARLA_GET_LABEL_STR(Buildings)
|
CARLA_GET_LABEL_STR(Buildings)
|
||||||
|
@ -38,42 +38,45 @@ static auto CastEnum(T label)
|
||||||
return static_cast<typename std::underlying_type<T>::type>(label);
|
return static_cast<typename std::underlying_type<T>::type>(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CityObjectLabel GetLabelByFolderName(const FString &String) {
|
static ECityObjectLabel GetLabelByFolderName(const FString &String) {
|
||||||
if (String == "Buildings") return CityObjectLabel::Buildings;
|
if (String == "Buildings") return ECityObjectLabel::Buildings;
|
||||||
else if (String == "Fences") return CityObjectLabel::Fences;
|
else if (String == "Fences") return ECityObjectLabel::Fences;
|
||||||
else if (String == "Pedestrians") return CityObjectLabel::Pedestrians;
|
else if (String == "Pedestrians") return ECityObjectLabel::Pedestrians;
|
||||||
else if (String == "Pole") return CityObjectLabel::Poles;
|
else if (String == "Pole") return ECityObjectLabel::Poles;
|
||||||
else if (String == "Props") return CityObjectLabel::Other;
|
else if (String == "Props") return ECityObjectLabel::Other;
|
||||||
else if (String == "Road") return CityObjectLabel::Roads;
|
else if (String == "Road") return ECityObjectLabel::Roads;
|
||||||
else if (String == "RoadLines") return CityObjectLabel::RoadLines;
|
else if (String == "RoadLines") return ECityObjectLabel::RoadLines;
|
||||||
else if (String == "SideWalk") return CityObjectLabel::Sidewalks;
|
else if (String == "SideWalk") return ECityObjectLabel::Sidewalks;
|
||||||
else if (String == "Vegetation") return CityObjectLabel::Vegetation;
|
else if (String == "Vegetation") return ECityObjectLabel::Vegetation;
|
||||||
else if (String == "Vehicles") return CityObjectLabel::Vehicles;
|
else if (String == "Vehicles") return ECityObjectLabel::Vehicles;
|
||||||
else if (String == "Walls") return CityObjectLabel::Walls;
|
else if (String == "Walls") return ECityObjectLabel::Walls;
|
||||||
else return CityObjectLabel::None;
|
else return ECityObjectLabel::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static CityObjectLabel GetLabelByPath(const T *Object)
|
static ECityObjectLabel GetLabelByPath(const T *Object)
|
||||||
{
|
{
|
||||||
const FString Path = Object->GetPathName();
|
const FString Path = Object->GetPathName();
|
||||||
TArray<FString> StringArray;
|
TArray<FString> StringArray;
|
||||||
Path.ParseIntoArray(StringArray, TEXT("/"), false);
|
Path.ParseIntoArray(StringArray, TEXT("/"), false);
|
||||||
return (StringArray.Num() > 3 ? GetLabelByFolderName(StringArray[3]) : CityObjectLabel::None);
|
return (StringArray.Num() > 3 ? GetLabelByFolderName(StringArray[3]) : ECityObjectLabel::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetStencilValue(UPrimitiveComponent *comp, const CityObjectLabel &Label) {
|
static void SetStencilValue(
|
||||||
if (Label != CityObjectLabel::None) {
|
UPrimitiveComponent &Component,
|
||||||
comp->SetRenderCustomDepth(true);
|
const ECityObjectLabel &Label,
|
||||||
comp->SetCustomDepthStencilValue(CastEnum(Label));
|
const bool bSetRenderCustomDepth) {
|
||||||
}
|
Component.SetRenderCustomDepth(
|
||||||
|
bSetRenderCustomDepth &&
|
||||||
|
!ATagger::MatchComponent(Component, ECityObjectLabel::None));
|
||||||
|
Component.SetCustomDepthStencilValue(CastEnum(Label));
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// -- static ATagger functions -------------------------------------------------
|
// -- static ATagger functions -------------------------------------------------
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
void ATagger::TagActor(const AActor &Actor)
|
void ATagger::TagActor(const AActor &Actor, bool bTagForSemanticSegmentation)
|
||||||
{
|
{
|
||||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||||
UE_LOG(LogCarla, Log, TEXT("Actor: %s"), *Actor.GetName());
|
UE_LOG(LogCarla, Log, TEXT("Actor: %s"), *Actor.GetName());
|
||||||
|
@ -84,7 +87,7 @@ void ATagger::TagActor(const AActor &Actor)
|
||||||
Actor.GetComponents<UStaticMeshComponent>(StaticMeshComponents);
|
Actor.GetComponents<UStaticMeshComponent>(StaticMeshComponents);
|
||||||
for (UStaticMeshComponent *Component : StaticMeshComponents) {
|
for (UStaticMeshComponent *Component : StaticMeshComponents) {
|
||||||
const auto Label = GetLabelByPath(Component->GetStaticMesh());
|
const auto Label = GetLabelByPath(Component->GetStaticMesh());
|
||||||
SetStencilValue(Component, Label);
|
SetStencilValue(*Component, Label, bTagForSemanticSegmentation);
|
||||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||||
UE_LOG(LogCarla, Log, TEXT(" + StaticMeshComponent: %s"), *Component->GetName());
|
UE_LOG(LogCarla, Log, TEXT(" + StaticMeshComponent: %s"), *Component->GetName());
|
||||||
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
||||||
|
@ -96,7 +99,7 @@ void ATagger::TagActor(const AActor &Actor)
|
||||||
Actor.GetComponents<USkeletalMeshComponent>(SkeletalMeshComponents);
|
Actor.GetComponents<USkeletalMeshComponent>(SkeletalMeshComponents);
|
||||||
for (USkeletalMeshComponent *Component : SkeletalMeshComponents) {
|
for (USkeletalMeshComponent *Component : SkeletalMeshComponents) {
|
||||||
const auto Label = GetLabelByPath(Component->GetPhysicsAsset());
|
const auto Label = GetLabelByPath(Component->GetPhysicsAsset());
|
||||||
SetStencilValue(Component, Label);
|
SetStencilValue(*Component, Label, bTagForSemanticSegmentation);
|
||||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||||
UE_LOG(LogCarla, Log, TEXT(" + SkeletalMeshComponent: %s"), *Component->GetName());
|
UE_LOG(LogCarla, Log, TEXT(" + SkeletalMeshComponent: %s"), *Component->GetName());
|
||||||
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
|
||||||
|
@ -104,10 +107,24 @@ void ATagger::TagActor(const AActor &Actor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATagger::TagActorsInLevel(UWorld &World)
|
void ATagger::TagActorsInLevel(UWorld &World, bool bTagForSemanticSegmentation)
|
||||||
{
|
{
|
||||||
for (TActorIterator<AActor> it(&World); it; ++it) {
|
for (TActorIterator<AActor> it(&World); it; ++it) {
|
||||||
TagActor(**it);
|
TagActor(**it, bTagForSemanticSegmentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATagger::GetTagsOfTaggedActor(const AActor &Actor, TArray<ECityObjectLabel> &Tags)
|
||||||
|
{
|
||||||
|
TArray<UPrimitiveComponent *> Components;
|
||||||
|
Actor.GetComponents<UPrimitiveComponent>(Components);
|
||||||
|
for (auto *Component : Components) {
|
||||||
|
if (Component != nullptr) {
|
||||||
|
const auto Tag = GetTagOfTaggedComponent(*Component);
|
||||||
|
if (Tag != ECityObjectLabel::None) {
|
||||||
|
Tags.Add(Tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +143,7 @@ void ATagger::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent
|
||||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||||
if (PropertyChangedEvent.Property) {
|
if (PropertyChangedEvent.Property) {
|
||||||
if (bTriggerTagObjects && (GetWorld() != nullptr)) {
|
if (bTriggerTagObjects && (GetWorld() != nullptr)) {
|
||||||
TagActorsInLevel(*GetWorld());
|
TagActorsInLevel(*GetWorld(), bTagForSemanticSegmentation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bTriggerTagObjects = false;
|
bTriggerTagObjects = false;
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "Components/PrimitiveComponent.h"
|
||||||
#include "Tagger.generated.h"
|
#include "Tagger.generated.h"
|
||||||
|
|
||||||
enum class CityObjectLabel : uint8
|
enum class ECityObjectLabel : uint8
|
||||||
{
|
{
|
||||||
None = 0u,
|
None = 0u,
|
||||||
Buildings = 1u,
|
Buildings = 1u,
|
||||||
|
@ -33,9 +34,37 @@ class CARLA_API ATagger : public AActor
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void TagActor(const AActor &Actor);
|
/// Set the tag of an actor.
|
||||||
|
///
|
||||||
|
/// If bTagForSemanticSegmentation true, activate the custom depth pass. This
|
||||||
|
/// pass is necessary for rendering the semantic segmentation. However, it may
|
||||||
|
/// add a performance penalty since occlusion doesn't seem to be applied to
|
||||||
|
/// objects having this value active.
|
||||||
|
static void TagActor(const AActor &Actor, bool bTagForSemanticSegmentation);
|
||||||
|
|
||||||
static void TagActorsInLevel(UWorld &World);
|
/// Set the tag of every actor in level.
|
||||||
|
///
|
||||||
|
/// If bTagForSemanticSegmentation true, activate the custom depth pass. This
|
||||||
|
/// pass is necessary for rendering the semantic segmentation. However, it may
|
||||||
|
/// add a performance penalty since occlusion doesn't seem to be applied to
|
||||||
|
/// objects having this value active.
|
||||||
|
static void TagActorsInLevel(UWorld &World, bool bTagForSemanticSegmentation);
|
||||||
|
|
||||||
|
/// Retrieve the tag of an already tagged component.
|
||||||
|
static ECityObjectLabel GetTagOfTaggedComponent(const UPrimitiveComponent &Component)
|
||||||
|
{
|
||||||
|
return static_cast<ECityObjectLabel>(Component.CustomDepthStencilValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the tags of an already tagged actor. ECityObjectLabel::None is
|
||||||
|
/// not added to the array.
|
||||||
|
static void GetTagsOfTaggedActor(const AActor &Actor, TArray<ECityObjectLabel> &Tags);
|
||||||
|
|
||||||
|
/// Return true if @a Component has been tagged with the given @a Tag.
|
||||||
|
static bool MatchComponent(const UPrimitiveComponent &Component, ECityObjectLabel Tag)
|
||||||
|
{
|
||||||
|
return (Tag == GetTagOfTaggedComponent(Component));
|
||||||
|
}
|
||||||
|
|
||||||
ATagger();
|
ATagger();
|
||||||
|
|
||||||
|
@ -49,4 +78,7 @@ private:
|
||||||
|
|
||||||
UPROPERTY(Category = "Tagger", EditAnywhere)
|
UPROPERTY(Category = "Tagger", EditAnywhere)
|
||||||
bool bTriggerTagObjects = false;
|
bool bTriggerTagObjects = false;
|
||||||
|
|
||||||
|
UPROPERTY(Category = "Tagger", EditAnywhere)
|
||||||
|
bool bTagForSemanticSegmentation = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WeatherDescription.generated.h"
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EPrecipitationType : uint8
|
||||||
|
{
|
||||||
|
Rain UMETA(DisplayName = "Rain"),
|
||||||
|
};
|
||||||
|
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FWeatherDescription
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
/// @name Weather
|
||||||
|
// ===========================================================================
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/** Display name of the current weather. */
|
||||||
|
UPROPERTY(Category = "Weather", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FString Name;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
// ===========================================================================
|
||||||
|
/// @name Weather - Sun
|
||||||
|
// ===========================================================================
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/** Polar angle of the Sun in degrees, with 0.0 at zenith, 90.0 at equator. */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "0.0", ClampMax = "180.0"))
|
||||||
|
float SunPolarAngle = 45.0f;
|
||||||
|
|
||||||
|
/** Azimuth angle of the Sun in degrees. */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "-180.0", ClampMax = "180.0"))
|
||||||
|
float SunAzimuthAngle = 0.0f;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float SunBrightness;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float SunDirectionalLightIntensity;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor SunDirectionalLightColor;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sun", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float SunIndirectLightIntensity;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
// ===========================================================================
|
||||||
|
/// @name Weather - Sky
|
||||||
|
// ===========================================================================
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float CloudOpacity;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float HorizontFalloff;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor ZenithColor;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor HorizonColor;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor CloudColor;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor OverallSkyColor;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite, meta=(ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float SkyLightIntensity;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Sky", EditAnywhere, BlueprintReadWrite)
|
||||||
|
FLinearColor SkyLightColor;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
// ===========================================================================
|
||||||
|
/// @name Weather - Precipitation
|
||||||
|
// ===========================================================================
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Precipitation", EditAnywhere, BlueprintReadWrite)
|
||||||
|
bool bPrecipitation = false;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Precipitation", EditAnywhere, BlueprintReadWrite, meta=(EditCondition="bPrecipitation"))
|
||||||
|
EPrecipitationType PrecipitationType = EPrecipitationType::Rain;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Precipitation", EditAnywhere, BlueprintReadWrite, meta=(EditCondition="bPrecipitation", ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float PrecipitationAmount = 0.0f;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
UPROPERTY(Category = "Weather|Precipitation", EditAnywhere, BlueprintReadWrite, meta=(EditCondition="bPrecipitation", ClampMin = "0.0", ClampMax = "100.0"))
|
||||||
|
float PrecipitationAccumulation = 0.0f;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
Loading…
Reference in New Issue