Merge remote-tracking branch 'origin/dev' into xisco

This commit is contained in:
Xisco Bosch 2017-05-12 10:01:46 +02:00
commit f9f2dbe1ff
18 changed files with 756 additions and 200 deletions

View File

@ -1,3 +1,7 @@
## CARLA 0.2.4
* Fixed serialization of road map resulting in a huge map size.
## CARLA 0.2.3
* Fixed rounding errors in HUD (100% was shown as 99%, 30 FPS as 29 FPS).

View File

@ -1,7 +1,7 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "0.2.3",
"VersionName": "0.2.4",
"FriendlyName": "CARLA",
"Description": "",
"Category": "Science",

View File

@ -162,6 +162,12 @@ void ACityMapGenerator::GenerateRoads()
AddInstance(tag ##_Lane1, x, y, angle); \
AddInstance(tag ##_Lane2, 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 ##_Sidewalk1, x, y, angle); \
AddInstance(tag ##_Sidewalk2, x, y, angle); \
@ -189,7 +195,7 @@ void ACityMapGenerator::GenerateRoads()
#undef ADD_INTERSECTION
}
// Find first component of type road (checking at its stencil value).
// Find first component of type road.
static bool LineTrace(
UWorld *World,
const FVector &Start,
@ -207,7 +213,7 @@ static bool LineTrace(
if (Success) {
for (FHitResult &Item : OutHits) {
if (Item.Component->CustomDepthStencilValue == static_cast<uint8>(CityObjectLabel::Roads)) {
if (ATagger::MatchComponent(*Item.Component, ECityObjectLabel::Roads)) {
HitResult = Item;
return true;
}
@ -224,7 +230,7 @@ void ACityMapGenerator::GenerateRoadMap()
check(GetWorld() != 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 uint32 Margin = IntersectionSize / 2u;
@ -237,7 +243,9 @@ void ACityMapGenerator::GenerateRoadMap()
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 PixelX = 0u; PixelX < SizeX; ++PixelX) {
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 End = ActorTransform.TransformPosition(FVector(X, Y, -50.0f));
bool Success = false;
// Do the ray tracing.
FHitResult Hit;
if (LineTrace(World, Start, End, Hit)) {
@ -258,39 +264,21 @@ void ACityMapGenerator::GenerateRoadMap()
if (!InstancedStaticMeshComponent->GetInstanceTransform(Hit.Item, InstanceTransform, true)) {
UE_LOG(LogCarla, Error, TEXT("Failed to get instance's transform"));
} else {
RoadMap->AppendPixel(
RoadMap->SetPixelAt(
PixelX,
PixelY,
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;
}
#ifdef WITH_EDITOR
RoadMap->Log();
#endif // WITH_EDITOR
if (bSaveRoadMapToDisk) {
const FString MapName = World->GetMapName() + TEXT(".png");
@ -298,5 +286,7 @@ void ACityMapGenerator::GenerateRoadMap()
RoadMap->SaveAsPNG(FilePath);
}
#ifdef WITH_EDITOR
RoadMap->DrawDebugPixelsToLevel(GetWorld(), !bDrawDebugPixelsToLevel);
#endif // WITH_EDITOR
}

View File

@ -152,6 +152,14 @@ private:
UPROPERTY(Category = "Road Map", EditAnywhere, AdvancedDisplay)
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()
URoadMap *RoadMap;

View File

@ -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);
}

View File

@ -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;
};

View File

@ -70,7 +70,9 @@ void ACarlaGameMode::RestartPlayer(AController* NewPlayer)
void ACarlaGameMode::BeginPlay()
{
Super::BeginPlay();
TagActorsForSemanticSegmentation();
if (GameInstance->GetCarlaSettings().bSemanticSegmentationEnabled) {
TagActorsForSemanticSegmentation();
}
GameController->BeginPlay();
}
@ -105,7 +107,7 @@ void ACarlaGameMode::AttachCaptureCamerasToPlayer(AController &Player)
void ACarlaGameMode::TagActorsForSemanticSegmentation()
{
check(GetWorld() != nullptr);
ATagger::TagActorsInLevel(*GetWorld());
ATagger::TagActorsInLevel(*GetWorld(), true);
}
APlayerStart *ACarlaGameMode::FindUnOccupiedStartPoints(

View File

@ -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)
{
CollisionIntensityOther += NormalImpulse.Size();
switch (ATagger::GetTagOfTaggedComponent(*Hit.Component)) {
case ECityObjectLabel::Vehicles:
CollisionIntensityCars += NormalImpulse.Size();
break;
case ECityObjectLabel::Pedestrians:
CollisionIntensityPedestrians += NormalImpulse.Size();
break;
default:
CollisionIntensityOther += NormalImpulse.Size();
break;
}
}
static int32 RoundToMilliseconds(float Seconds)

View File

@ -130,7 +130,11 @@ public:
// ===========================================================================
private:
void RegisterCollision(AActor *Actor, FVector NormalImpulse);
void RegisterCollision(
AActor *Actor,
AActor *OtherActor,
const FVector &NormalImpulse,
const FHitResult &Hit);
void UpdateTimeStamp(float DeltaSeconds);

View File

@ -112,6 +112,11 @@ static void ValidateCameraDescription(FCameraDescription &Camera)
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)
{
UE_LOG(LogCarla, Log, TEXT("Loading settings from \"%s\""), *FileName);
@ -141,6 +146,7 @@ static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settin
}
ValidateCameraDescription(Camera);
Settings.bSemanticSegmentationEnabled |= RequestedSemanticSegmentation(Camera);
}
}
@ -148,6 +154,9 @@ static bool GetSettingsFileName(FString &Value)
{
// Try to get it from the command-line arguments.
if (FParse::Value(FCommandLine::Get(), TEXT("-carla-settings="), Value)) {
if (FPaths::IsRelative(Value)) {
Value = FPaths::ConvertRelativePathToFull(FPaths::LaunchDir(), Value);
}
if (FPaths::FileExists(Value)) {
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("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("[%s]"), S_CARLA_SCENECAPTURE);
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) {
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);

View File

@ -18,7 +18,7 @@ public:
void LoadSettings();
/** Log settings values. */
void LogSettings();
void LogSettings() const;
private:
@ -59,5 +59,12 @@ public:
UPROPERTY(Category = "Scene Capture", EditDefaultsOnly)
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;
/// @}
};

View File

@ -251,12 +251,12 @@ void ACarlaVehicleController::ToggleManualMode()
// =============================================================================
void ACarlaVehicleController::OnCollisionEvent(
AActor* /*Actor*/,
AActor* Actor,
AActor* OtherActor,
FVector NormalImpulse,
const FHitResult& /*Hit*/)
const FHitResult& Hit)
{
CarlaPlayerState->RegisterCollision(OtherActor, NormalImpulse);
CarlaPlayerState->RegisterCollision(Actor, OtherActor, NormalImpulse, Hit);
}
// =============================================================================

View File

@ -20,6 +20,12 @@ enum class ECityMapMeshTag : uint8
Road90DegTurn_Lane1 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 1"),
Road90DegTurn_Lane2 UMETA(DisplayName = "Road: 90 Degree Turn - Lane 2"),
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_Sidewalk1 UMETA(DisplayName = "Road: 90 Degree Turn - Sidewalk 1"),
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_Lane2 UMETA(DisplayName = "Road: T-Intersection - Lane 2"),
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_Sidewalk1 UMETA(DisplayName = "Road: T-Intersection - Sidewalk 1"),
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_Lane2 UMETA(DisplayName = "Road: X-Intersection - Lane 2"),
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_Sidewalk1 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 1"),
RoadXIntersection_Sidewalk2 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 2"),

View File

@ -3,22 +3,190 @@
#include "Carla.h"
#include "RoadMap.h"
#include "DrawDebugHelpers.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)
{
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) :
Super(ObjectInitializer),
PixelsPerCentimeter(1.0f),
Width(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
@ -30,7 +198,7 @@ FVector URoadMap::GetWorldLocation(uint32 PixelX, uint32 PixelY) const
return WorldToMap.InverseTransformPosition(RelativePosition + MapOffset);
}
const FRoadMapPixelData &URoadMap::GetDataAt(const FVector &WorldLocation) const
FRoadMapPixelData URoadMap::GetDataAt(const FVector &WorldLocation) const
{
check(IsValid());
const FVector Location = WorldToMap.TransformPosition(WorldLocation) - MapOffset;
@ -44,7 +212,8 @@ FRoadMapIntersectionResult URoadMap::Intersect(
const FVector &BoxExtent,
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;
FRoadMapIntersectionResult Result = {0.0f, 0.0f};
const float Step = 1.0f / ChecksPerCentimeter;
@ -52,11 +221,11 @@ FRoadMapIntersectionResult URoadMap::Intersect(
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) {
const auto &Data = GetDataAt(Location);
if (!Data.IsRoad()) {
Result.OffRoad += 1.0f;
} else if (Data.bHasDirection &&
0.0f < FVector::DotProduct(Data.Direction, DirectionOfMovement)) {
} else if (Data.HasDirection() &&
0.0f > FVector::DotProduct(Data.GetDirection(), DirectionOfMovement)) {
Result.OppositeLane += 1.0f;
}
}
@ -70,21 +239,6 @@ FRoadMapIntersectionResult URoadMap::Intersect(
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()) {
@ -93,80 +247,61 @@ bool URoadMap::SaveAsPNG(const FString &Path) const
}
TArray<FColor> BitMap;
for (auto &Data : RoadMap) {
BitMap.Emplace(Encode(Data));
for (auto Value : RoadMapData) {
BitMap.Emplace(FRoadMapPixelData(Value).EncodeAsColor());
}
FIntPoint DestSize(Width, Height);
FString ResultPath;
FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
HighResScreenshotConfig.SetHDRCapture(false);
HighResScreenshotConfig.SaveImage(Path, BitMap, DestSize, &ResultPath);
UE_LOG(LogCarla, Log, TEXT("Saved road map to \"%s\""), *ResultPath);
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
{
const FVector ZOffset(0.0f, 0.0f, 50.0f);
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);
auto Location = GetWorldLocation(X, Y) + ZOffset;
const auto &Data = GetDataAt(X, Y);
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(
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;
}
#endif // WITH_EDITOR

View File

@ -5,33 +5,78 @@
#include "UObject/NoExportTypes.h"
#include "RoadMap.generated.h"
/// Road map intersection result. See URoadMap.
USTRUCT()
struct FRoadMapIntersectionResult
{
GENERATED_BODY()
/** Percentage of the box lying off-road */
/// Percentage of the box lying off-road.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
float OffRoad;
/** Percentage of the box invading opposite lane (wrong direction) */
/// Percentage of the box invading opposite lane (wrong direction).
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
float OppositeLane;
};
USTRUCT()
/// Data stored in a road map pixel. See URoadMap.
struct FRoadMapPixelData
{
GENERATED_BODY()
friend class URoadMap;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
bool bIsOffRoad = true;
constexpr static int IsRoadRow = 15;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
bool bHasDirection = false;
constexpr static int HasDirectionRow = 14;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
FVector Direction;
constexpr static uint16 MaximumEncodedAngle = (1 << 14) - 1;
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
@ -43,13 +88,23 @@ class CARLA_API URoadMap : public UObject
public:
/// Creates a valid empty map (every point is off-road).
URoadMap(const FObjectInitializer& ObjectInitializer);
UFUNCTION(BlueprintCallable)
bool IsValid() const
{
return ((RoadMap.Num() > 0) && (RoadMap.Num() == Height * Width));
}
/// Resets current map an initializes an empty map of the given size.
void Reset(
uint32 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
{
@ -61,74 +116,73 @@ public:
return Height;
}
/// Return the world location of a given pixel.
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());
return RoadMap[PixelX + Width * PixelY];
return FRoadMapPixelData(RoadMapData[GetIndex(PixelX, PixelY)]);
}
/** Clamps value if lies outside map limits */
UFUNCTION(BlueprintCallable)
const FRoadMapPixelData &GetDataAt(const FVector &WorldLocation) const;
/// Clamps value if lies outside map limits.
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)
/// 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.
FRoadMapIntersectionResult Intersect(
const FTransform &BoxTransform,
const FVector &BoxExtent,
float ChecksPerCentimeter) const;
UFUNCTION(BlueprintCallable)
/// Save the current map as PNG with the pixel data encoded as color.
bool SaveAsPNG(const FString &Path) const;
/** Draw every pixel of the image as debug point */
UFUNCTION(BlueprintCallable)
#ifdef WITH_EDITOR
/// 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;
#endif // WITH_EDITOR
private:
friend class ACityMapGenerator;
void AppendEmptyPixel()
int32 GetIndex(uint32 PixelX, uint32 PixelY) const
{
RoadMap.AddDefaulted(1);
return PixelX + Width * PixelY;
}
void AppendPixel(
ECityMapMeshTag Tag,
const FTransform &Transform,
bool bInvertDirection);
void Set(
uint32 Width,
uint32 Height,
float PixelsPerCentimeter,
const FTransform &WorldToMap,
const FVector &MapOffset);
bool IsValid() const
{
return ((RoadMapData.Num() > 0) && (RoadMapData.Num() == Height * Width));
}
/// World-to-map transform.
UPROPERTY(VisibleAnywhere)
FTransform WorldToMap;
/// Offset of the map in map coordinates.
UPROPERTY(VisibleAnywhere)
FVector MapOffset;
/// Number of pixels per centimeter.
UPROPERTY(VisibleAnywhere)
float PixelsPerCentimeter;
/** Width of the map in pixels */
/// Width of the map in pixels.
UPROPERTY(VisibleAnywhere)
uint32 Width;
/** Height of the map in pixels */
/// Height of the map in pixels.
UPROPERTY(VisibleAnywhere)
uint32 Height;
UPROPERTY()
TArray<FRoadMapPixelData> RoadMap;
TArray<uint16> RoadMapData;
};

View File

@ -10,10 +10,10 @@
#include "PhysicsEngine/PhysicsAsset.h"
#ifdef CARLA_TAGGER_EXTRA_LOG
static FString GetLabelAsString(const CityObjectLabel Label)
static FString GetLabelAsString(const ECityObjectLabel 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:
CARLA_GET_LABEL_STR(None)
CARLA_GET_LABEL_STR(Buildings)
@ -38,42 +38,45 @@ 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;
static ECityObjectLabel GetLabelByFolderName(const FString &String) {
if (String == "Buildings") return ECityObjectLabel::Buildings;
else if (String == "Fences") return ECityObjectLabel::Fences;
else if (String == "Pedestrians") return ECityObjectLabel::Pedestrians;
else if (String == "Pole") return ECityObjectLabel::Poles;
else if (String == "Props") return ECityObjectLabel::Other;
else if (String == "Road") return ECityObjectLabel::Roads;
else if (String == "RoadLines") return ECityObjectLabel::RoadLines;
else if (String == "SideWalk") return ECityObjectLabel::Sidewalks;
else if (String == "Vegetation") return ECityObjectLabel::Vegetation;
else if (String == "Vehicles") return ECityObjectLabel::Vehicles;
else if (String == "Walls") return ECityObjectLabel::Walls;
else return ECityObjectLabel::None;
}
template <typename T>
static CityObjectLabel GetLabelByPath(const T *Object)
static ECityObjectLabel 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);
return (StringArray.Num() > 3 ? GetLabelByFolderName(StringArray[3]) : ECityObjectLabel::None);
}
static void SetStencilValue(UPrimitiveComponent *comp, const CityObjectLabel &Label) {
if (Label != CityObjectLabel::None) {
comp->SetRenderCustomDepth(true);
comp->SetCustomDepthStencilValue(CastEnum(Label));
}
static void SetStencilValue(
UPrimitiveComponent &Component,
const ECityObjectLabel &Label,
const bool bSetRenderCustomDepth) {
Component.SetRenderCustomDepth(
bSetRenderCustomDepth &&
!ATagger::MatchComponent(Component, ECityObjectLabel::None));
Component.SetCustomDepthStencilValue(CastEnum(Label));
}
// =============================================================================
// -- static ATagger functions -------------------------------------------------
// =============================================================================
void ATagger::TagActor(const AActor &Actor)
void ATagger::TagActor(const AActor &Actor, bool bTagForSemanticSegmentation)
{
#ifdef CARLA_TAGGER_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT("Actor: %s"), *Actor.GetName());
@ -84,7 +87,7 @@ void ATagger::TagActor(const AActor &Actor)
Actor.GetComponents<UStaticMeshComponent>(StaticMeshComponents);
for (UStaticMeshComponent *Component : StaticMeshComponents) {
const auto Label = GetLabelByPath(Component->GetStaticMesh());
SetStencilValue(Component, Label);
SetStencilValue(*Component, Label, bTagForSemanticSegmentation);
#ifdef CARLA_TAGGER_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT(" + StaticMeshComponent: %s"), *Component->GetName());
UE_LOG(LogCarla, Log, TEXT(" - Label: \"%s\""), *GetLabelAsString(Label));
@ -96,7 +99,7 @@ void ATagger::TagActor(const AActor &Actor)
Actor.GetComponents<USkeletalMeshComponent>(SkeletalMeshComponents);
for (USkeletalMeshComponent *Component : SkeletalMeshComponents) {
const auto Label = GetLabelByPath(Component->GetPhysicsAsset());
SetStencilValue(Component, Label);
SetStencilValue(*Component, Label, bTagForSemanticSegmentation);
#ifdef CARLA_TAGGER_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT(" + SkeletalMeshComponent: %s"), *Component->GetName());
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) {
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);
if (PropertyChangedEvent.Property) {
if (bTriggerTagObjects && (GetWorld() != nullptr)) {
TagActorsInLevel(*GetWorld());
TagActorsInLevel(*GetWorld(), bTagForSemanticSegmentation);
}
}
bTriggerTagObjects = false;

View File

@ -3,9 +3,10 @@
#pragma once
#include "GameFramework/Actor.h"
#include "Components/PrimitiveComponent.h"
#include "Tagger.generated.h"
enum class CityObjectLabel : uint8
enum class ECityObjectLabel : uint8
{
None = 0u,
Buildings = 1u,
@ -33,9 +34,37 @@ class CARLA_API ATagger : public AActor
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();
@ -49,4 +78,7 @@ private:
UPROPERTY(Category = "Tagger", EditAnywhere)
bool bTriggerTagObjects = false;
UPROPERTY(Category = "Tagger", EditAnywhere)
bool bTagForSemanticSegmentation = false;
};

View File

@ -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;
/// @}
};