17#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
18#include "NiagaraDataInterfaceArrayFunctionLibrary.h"
19#include "Math/UnrealMathUtility.h"
20#include "NiagaraFunctionLibrary.h"
21#include <Misc/FileHelper.h>
22#include "NiagaraComponent.h"
23#include "Components/PrimitiveComponent.h"
25#include "Async/ParallelFor.h"
26#include "Engine/GameViewportClient.h"
27#include "Engine/Engine.h"
31ALidar::ALidar(
const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
34 PrimaryActorTick.bCanEverTick =
false;
54 PointCloudMessage->fields[0].datatype = ROSMessages::sensor_msgs::PointCloud2::PointField::FLOAT32;
59 PointCloudMessage->fields[1].datatype = ROSMessages::sensor_msgs::PointCloud2::PointField::FLOAT32;
64 PointCloudMessage->fields[2].datatype = ROSMessages::sensor_msgs::PointCloud2::PointField::FLOAT32;
69 PointCloudMessage->fields[3].datatype = ROSMessages::sensor_msgs::PointCloud2::PointField::UINT32;
85 for (
const auto& ColorEntry : Colors)
87 FName SemanticName = FName(*ColorEntry.Key);
94 CachedNoneColor = (NoneColor.R << 16) | (NoneColor.G << 8) | (NoneColor.B << 0);
95 CachedSnowflakeColor = (SnowflakeColor.R << 16) | (SnowflakeColor.G << 8) | (SnowflakeColor.B << 0);
112 UNiagaraSystem* NS = LoadObject<UNiagaraSystem>(
nullptr, TEXT(
"/Game/Agrarsense/Particles/PointCloud/NS_PointCloudSemanticFast"),
nullptr, LOAD_None,
nullptr);
130 UE_LOG(LogTemp, Warning, TEXT(
"Lidar.cpp: Couldn't find Niagara particle system."));
137 Super::EndPlay(EndPlayReason);
185 const float Amount = 0.1f;
201 Points.resize(NumberOfLasers);
207 for (int32 i = 0u; i < NumberOfLasers; ++i)
220 SimulatorLog::Log(
"Lidar sensor: It's highly advisable to turn off VisualizePointcloud when PointsPerSecond exceed 1 million.");
225 SimulatorLog::Log(
"Lidar sensor: VisualizePointcloud has been set to false due PointsPerSecond exceeding 2 million.");
245 TArray<FVector> EmptyHitpoints;
246 TArray<FLinearColor> EmptyColors;
269 NiagaraComponent->SetVariableFloat(FName(
"User.LifeTime"), ParticleLifeTime);
277 std::vector<FPointData> HitPoints;
285 const FTransform actorTransform = GetTransform();
286 const FVector LidarBodyLocation = actorTransform.GetLocation();
287 const FRotator LidarBodyRotation = actorTransform.Rotator();
288 const FQuat LidarBodyQuat = FQuat(LidarBodyRotation);
295 const float AngleDistanceOfLaserMeasure = AngleDistanceOfTick / PointsToScanWithOneChannel;
298 const FColor Color = FColor(255, 255, 255);
299 const int32 RgbDefault = (Color.R << 16) | (Color.G << 8) | (Color.B << 0);
301 FCollisionQueryParams TraceParams = FCollisionQueryParams(FName(TEXT(
"Laser_Trace")),
true,
this);
302 TraceParams.bReturnPhysicalMaterial =
false;
320 const float HorizontalFOVHalf = HorizontalFOV / 2;
325 ParallelFor(ChannelCount, [&](int32 Channel)
328 int32 RGB = RgbDefault;
330 FRotator LaserRotation;
331 FHitResult HitResult;
335 bool UseHorizontalNoise = FMath::RandBool();
338 std::vector<FPointData>& ChannelPoints =
Points[Channel];
341 for (int32 i = 0; i < PointsToScanWithOneChannel; i++)
343 const float LaserHorizontalAngle = std::fmod(HorizontalAngle + AngleDistanceOfLaserMeasure * i, HorizontalFOV) - HorizontalFOVHalf;
348 LaserRotation = FRotator(VerticalAngle, LaserHorizontalAngle, 0);
349 FQuat LaserQuat = FQuat(LaserRotation);
350 FQuat ResultQuat = LaserQuat * LidarBodyQuat;
351 EndTrace = Range * ResultQuat.Vector() + LidarBodyLocation;
353 if (
ShootLaser(HitResult, EndTrace, TraceParams, LidarBodyLocation, Channel, Semantic, RgbDefault))
363 const FVector& HitPoint = HitResult.ImpactPoint;
364 ChannelPoints.emplace_back(HitPoint.X, HitPoint.Y, HitPoint.Z, RGB);
367 }, EParallelForFlags::Unbalanced);
400 float NoiseValue = Distribution(
Generator);
401 const FVector DirectionToSensor = ((LidarBodyLocation * 1e-2) - HitResult.ImpactPoint).GetSafeNormal();
402 const FVector Noise = DirectionToSensor * NoiseValue;
403 HitResult.ImpactPoint += Noise;
411 const FVector ForwardVector = (HitResult.ImpactPoint - LidarBodyLocation).GetSafeNormal();
412 const FVector RightVector = FVector::CrossProduct(ForwardVector, FVector::UpVector).GetSafeNormal();
414 FVector ChosenDirection;
415 if (UseHorizontalNoise)
417 ChosenDirection = RightVector;
421 FVector UpVector = FVector::CrossProduct(ForwardVector, RightVector).GetSafeNormal();
422 ChosenDirection = UpVector;
426 const float NoiseValue = Distribution(
Generator);
428 HitResult.ImpactPoint += ChosenDirection * NoiseValue;
436 bool HitTerrain =
false;
437 AActor* HitActor = HitResult.GetActor();
440 if (HitActor && HitActor->Tags.Contains(
"Terrain"))
455 FVector NewHitPoint = FMath::Lerp(HitResult.ImpactPoint, (LidarBodyLocation * 1e-2),
SnowHeightOffset);
456 HitResult.ImpactPoint = NewHitPoint;
471 && GEngine->GameViewport
472 && GEngine->GameViewport->bDisableWorldRendering)
479 if (NumberOfHits != 0)
485 TArray<FVector> HitLocations;
486 HitLocations.SetNumUninitialized(NumberOfHits);
489 TArray<FLinearColor> Colors;
490 Colors.Init(FLinearColor::Green, NumberOfHits);
493 FVector* HitLocationPtr = HitLocations.GetData();
494 FLinearColor* ColorsPtr = Colors.GetData();
498 for (int32 i = 0; i < NumberOfHits; ++i)
502 HitLocationPtr[i] = FVector(point.
X, (point.
Y * -1), point.
Z);
507 uint8 R = (point.
RGB >> 16) & 0xFF;
508 uint8 G = (point.
RGB >> 8) & 0xFF;
509 uint8 B = point.
RGB & 0xFF;
510 ColorsPtr[i] = FLinearColor(R / 255.0f, G / 255.0f, B / 255.0f);
525 size_t totalSize = 0;
526 for (
const auto& vec :
Points)
528 totalSize += vec.size();
534 for (int32 idxChannel = 0; idxChannel < channelCount; ++idxChannel)
590 auto* HitComponent = HitResult.Component.Get();
594 if (!HitComponent->ComponentTags.IsEmpty())
596 FName Tag = HitComponent->ComponentTags[0];
598 return (Color.R << 16) | (Color.G << 8) | (Color.B << 0);
611bool ALidar::ShootLaser(FHitResult& HitResult,
const FVector& EndTrace,
const FCollisionQueryParams& TraceParams,
612 const FVector& LidarBodyLocation,
const int32 Channel,
const bool Semantic,
const uint32 RGBDefault)
614#ifdef ParallelLineTraceSingleByChannel_EXISTS
617 World->ParallelLineTraceSingleByChannel(
621 ECC_GameTraceChannel3,
623 FCollisionResponseParams::DefaultResponseParam);
626 World->LineTraceSingleByChannel(
630 ECC_GameTraceChannel3,
632 FCollisionResponseParams::DefaultResponseParam);
636 HitResult.ImpactPoint *= 1e-2;
639 HitResult.ImpactPoint.Y *= -1;
644 FHitResult OriginalHitResultCopy = HitResult;
645 uint32 RGB = RGBDefault;
651 const FVector& HitPoint = OriginalHitResultCopy.ImpactPoint;
652 FPointData point = { HitPoint.
X, HitPoint.Y, HitPoint.Z, RGB };
656 bool BlockingHit =
false;
661 BlockingHit = HitResult.bBlockingHit || HitSnowFlake;
665 BlockingHit = HitResult.IsValidBlockingHit();
692 impactPoints.clear();
693 impactPoints.reserve(MaxPointsPerChannel);
699 for (
auto& impactPoints :
Points)
701 impactPoints.clear();
702 impactPoints.reserve(MaxPointsPerChannel);
719 const int pointSize = points.size();
720 size_t dataSize = pointSize *
sizeof(
FPointData);
743 std::vector<FPointData> PointsWithOutNoiseModel;
744 size_t totalSize = 0;
746 for (int32 i = 0; i < ChannelCount; ++i)
750 PointsWithOutNoiseModel.reserve(totalSize);
752 for (int32 i = 0; i < ChannelCount; ++i)
758 FString PreprocessedFilename = FString::Printf(TEXT(
"%sLidar_%d_without_noise_model.ply"), *
FileSavePath,
LidarSaves);
void AddRaycastLidar(ALidar *lidarPtr)
void RemoveRaycastLidar(ALidar *lidarPtr)
UNiagaraComponent * NiagaraComponent
TMap< FName, FColor > SemanticColors
bool ShootLaser(FHitResult &HitResult, const FVector &EndTrace, const FCollisionQueryParams &TraceParams, const FVector &LidarBodyLocation, const int32 Channel, const bool Semantic, const uint32 RGBDefault)
FWeatherParameters CurrentWeatherParameters
std::random_device RandomDevice
uint32 GetSemanticData(const FHitResult &HitResult) const
void Init(FLidarParameters parameters, bool SimulateSensor=true)
std::vector< uint32_t > PointsPerChannel
void SendData(const float DeltaTime)
void AddLateralNoise(FHitResult &HitResult, const FVector &LidarBodyLocation, const bool UseHorizontalNoise)
void ChangeLidarParameters(FLidarParameters newLidarParameters)
bool CanSendData(const float DeltaTime)
std::vector< std::vector< FPointData > > PreProcessedHitImpactPoints
void ResetRecordedHits(int32 MaxPointsPerChannel)
ALidar(const FObjectInitializer &ObjectInitializer)
uint32 CachedSnowflakeColor
std::vector< float > LaserAngles
void UpdateLidarParticles(int NumberOfHits, const TArray< FVector > &HitPoints, const TArray< FLinearColor > &Colors)
void SetParticleLifeTime(float ParticleLifeTime)
bool LidarParametersChanged
void AddProcessingToHitResult(FHitResult &HitResult, const FVector &LidarBodyLocation, const bool UseHorizontalNoise)
void OnWeatherChanged(FWeatherParameters WeatherParams)
virtual void BeginPlay() override
FLidarParameters TempLidarParameters
void AddDistanceNoise(FHitResult &HitResult, const FVector &LidarBodyLocation)
void SetNiagaraRendering(bool Enabled)
std::vector< std::vector< FPointData > > Points
std::vector< FPointData > SimulateRaycastLidar(const float DeltaTime)
void VisualizeLidarParticles()
bool NeedToSavePointCloudWithoutNoise
std::vector< FPointData > PointsFlattened
void SetVisualizeLidarParticles(bool Visualize)
TSharedPtr< ROSMessages::sensor_msgs::PointCloud2 > PointCloudMessage
void SendDataToTopic(const std::vector< FPointData > &points)
void AddSnowTerrainAdjustment(FHitResult &HitResult, const FVector &LidarBodyLocation)
FLidarParameters LidarParameters
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
float CurrentHorizontalAngle
static const FName NiagaraHitPoints
bool CanSimulateSensor() const
static void HideComponentForAllCameras(UPrimitiveComponent *PrimitiveComponent)
static const FName NiagaraPointsFloat
virtual void CreateDataSavePath()
void SetSimulateSensor(bool SimulateSensor)
UTopic * GetROSTopic() const
bool IsROSConnected() const
static const FName NiagaraHitColors
virtual void CreateROSTopic()
static const FName NiagaraPointsInt
static TMap< FString, FColor > GetSemanticColors()
const FWeatherParameters & GetCurrentWeather() const
FLevelEventDelegate_WeatherChanged OnWeatherChanged
static bool CheckSnowflakeHit(FHitResult &HitInfo, const FVector EndTrace, const FVector LidarLocation, const FWeatherParameters &WeatherParameters)
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static AWeather * GetWeatherActor(const UObject *WorldContextObject)
static ALidarManager * GetLidarManager(const UObject *WorldContextObject)
static void SaveVectorArrayAsPlyAsync(FString FullFileName, const std::vector< FPointData > points)
float DistanceNoiseStdDev
bool SendDataAtRotationFrequency
bool SendDataToCombinedROSTopic
bool SavePointcloudWithoutNoiseModel
bool UseComplexCollisionTrace
bool UseTerrainSnowHitAdjustment
bool IsWinterSnowCondition()
bool IsLidarNoiseModelCondition()