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
|
||||
|
||||
* Fixed rounding errors in HUD (100% was shown as 99%, 30 FPS as 29 FPS).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "0.2.3",
|
||||
"VersionName": "0.2.4",
|
||||
"FriendlyName": "CARLA",
|
||||
"Description": "",
|
||||
"Category": "Science",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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