14#include <util/ue-header-guard-begin.h>
15#include "Async/ParallelFor.h"
16#include "Engine/AssetManager.h"
17#include "Engine/CollisionProfile.h"
18#include "Engine/StaticMeshActor.h"
19#include "Engine/StreamableManager.h"
20#include "UObject/SoftObjectPath.h"
21#include "StaticMeshResources.h"
22#include "CollisionQueryParams.h"
24#include "LandscapeHeightfieldCollisionComponent.h"
25#include "LandscapeComponent.h"
26#include "RHICommandList.h"
27#include "TextureResource.h"
28#include "GenericPlatform/GenericPlatformProcess.h"
29#include "Materials/MaterialParameterCollection.h"
30#include "Materials/MaterialParameterCollectionInstance.h"
31#include "Materials/MaterialInterface.h"
32#include "Materials/MaterialInstance.h"
33#include "Components/SkinnedMeshComponent.h"
34#include "Async/Async.h"
35#include "Async/Future.h"
36#include "LandscapeProxy.h"
37#include "UObject/SavePackage.h"
38#include "HAL/PlatformFileManager.h"
39#include "HAL/RunnableThread.h"
40#include "Misc/Paths.h"
41#include "Engine/World.h"
42#include "Math/UnrealMathUtility.h"
43#include "GenericPlatform/GenericPlatformFile.h"
44#include "Engine/Texture2D.h"
45#include "Engine/Texture.h"
46#include "Rendering/Texture2DResource.h"
47#include "Engine/TextureRenderTarget2D.h"
48#include "Components/PrimitiveComponent.h"
49#include "DrawDebugHelpers.h"
50#include "Kismet/KismetSystemLibrary.h"
51#include "Misc/CommandLine.h"
52#include "Components/LineBatchComponent.h"
53#include "Math/OrientedBox.h"
54#include "Misc/DateTime.h"
55#include "EngineUtils.h"
56#include <util/ue-header-guard-end.h>
71namespace fs = std::filesystem;
81 TEXT(
"carla.Terrain.AsyncHeightmapLoad"),
83 TEXT(
"When non-zero (default), CustomTerrainPhysicsComponent loads heightmap ")
84 TEXT(
"data assets asynchronously on tile crossings instead of issuing a ")
85 TEXT(
"blocking StaticLoadObject on the game thread. Set to 0 to force the ")
86 TEXT(
"legacy synchronous path (for rollback/debugging)."),
90 constexpr char OverridePathEV[] =
"CARLA_CACHE_DIR";
91 constexpr char HomePathEV[] =
97 const char* override_path = std::getenv(OverridePathEV);
98 if (override_path != NULL)
99 return fs::path(override_path).string();
100 fs::path path = std::getenv(HomePathEV);
101 path /=
"carlaCache";
102 return fs::absolute(path).string();
107 return MToCM * FVector(In.X, -In.Y, In.Z);
112 return FVector(In.X, -In.Y, In.Z);
117 return CMToM*FVector(In.X, -In.Y, In.Z);
122 return FVector(In.X, -In.Y, In.Z);
148 Coord_X = std::min(Coord_X,
Size_X-1);
149 Coord_Y = std::min(Coord_Y,
Size_Y-1);
211 std::string FileName = std::string(TCHAR_TO_UTF8(*(InSavePath + TileOrigin.
ToString() +
".tile" ) ) );
214 if( FPaths::FileExists(FString(FileName.c_str())) )
217 TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::Read);
218 std::ifstream ReadStream(FileName);
219 FVector VectorToRead;
222 ReadStdVector<FParticle> (ReadStream,
Particles);
227 TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::Create);
230 uint32_t NumParticles_X = (TileEnd.
X - TileOrigin.
X) / ParticleSize;
231 uint32_t NumParticles_Y = FMath::Abs(TileEnd.
Y - TileOrigin.
Y) / ParticleSize;
232 uint32_t NumParticles_Z = (Depth) / ParticleSize;
233 Particles = std::vector<FParticle>(NumParticles_X*NumParticles_Y*NumParticles_Z);
238 for(uint32_t i = 0; i < NumParticles_X; i++)
240 for(uint32_t j = 0; j < NumParticles_Y; j++)
242 FDVector ParticleLocalPosition =
FDVector(i*ParticleSize, j*ParticleSize, 0.0f);
243 FDVector ParticlePosition = TileOrigin + ParticleLocalPosition;
244 float Height = HeightMap.
GetHeight(ParticlePosition);
245 for(uint32_t k = 0; k < NumParticles_Z; k++)
247 ParticlePosition.
Z = TileOrigin.
Z + Height - k*ParticleSize;
248 Particles[k*NumParticles_X*NumParticles_Y + j*NumParticles_X + i] =
249 {ParticlePosition, FVector(0), ParticleSize/2.f};
271 TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::ParticlesZOrdered);
274 float InverseTileSize = 1.f/
TileSize;
277 for (
size_t i = 0; i <
Particles.size(); i++)
282 FIntVector HeightMapCoords = FIntVector(
283 ParticleLocalPosition.
X * Transformation,
284 ParticleLocalPosition.
Y * Transformation, 0);
304 if((particle.Position -
Position).SizeSquared() < Radius*Radius)
306 ParticlesInRadius.emplace_back(&particle);
314 std::vector<FParticle*> ParticlesInRadius;
317 if((particle.Position -
Position).SizeSquared() < Radius*Radius)
319 ParticlesInRadius.emplace_back(&particle);
322 return ParticlesInRadius;
326 const FOrientedBox& OBox, std::vector<FParticle*> &ParticlesInRadius)
331 FVector PToCenter =
SIToUEFrame(Particle.Position.ToFVector()) - OBox.Center;
332 if((FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisX)) < OBox.ExtentX) &&
333 (FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisY)) < OBox.ExtentY) &&
334 (FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisZ)) < OBox.ExtentZ))
336 ParticlesInRadius.emplace_back(&Particle);
345 ParticlesInRadius.emplace_back(&Particle);
371 uint32_t Tile_X = (uint32_t)(TileId >> 32);
372 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
376 std::vector<FParticle*> ParticlesInRadius;
388 return ParticlesInRadius;
397 uint32_t Tile_X = (uint32_t)(TileId >> 32);
398 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
400 uint32_t RadiusInTiles = (Radius/
TileSize);
401 uint32_t MinX,MinY,MaxX,MaxY = 0;
403 if( Tile_X < RadiusInTiles){
406 MinX = Tile_X - RadiusInTiles;
409 if( Tile_Y < RadiusInTiles){
412 MinY = Tile_Y - RadiusInTiles;
418 MaxX = Tile_X + RadiusInTiles;
424 MaxY = Tile_Y + RadiusInTiles;
439 std::vector<FParticle*> ParticlesInRadius;
440 for( uint32_t X = MinX; X <= MaxX; ++X )
442 for( uint32_t Y = MinY; Y <= MaxY; ++Y )
445 if(
Map.count(CurrentTileId) )
451 return ParticlesInRadius;
460 std::vector<FParticle*> ParticlesInRadius;
461 for(uint64_t TileId : TilesToCheck)
465 return ParticlesInRadius;
469 const FOrientedBox& OBox)
472 std::vector<uint64_t> IntersectingTiles;
476 float ExtentXSqr = ExtentX*ExtentX;
479 float ExtentYSqr = ExtentY*ExtentY;
482 uint64_t CenterTileId =
GetTileId(BoxCenter);
483 uint32_t CenterTile_X = (uint32_t)(CenterTileId >> 32);
484 uint32_t CenterTile_Y = (uint32_t)(CenterTileId & (uint32_t)(~0));
485 uint32_t TileRange = 1;
486 IntersectingTiles.emplace_back(CenterTileId);
487 FVector2D BoxVert0 = FVector2D(BoxCenter - AxisX*ExtentX - AxisY*ExtentY);
488 FVector2D BoxVert1 = FVector2D(BoxCenter + AxisX*ExtentX - AxisY*ExtentY);
489 FVector2D BoxVert2 = FVector2D(BoxCenter + AxisX*ExtentX + AxisY*ExtentY);
490 FVector2D BoxVert3 = FVector2D(BoxCenter - AxisX*ExtentX + AxisY*ExtentY);
495 FVector2D V1, V2, V3, V4;
496 std::vector<FVector2D> ComputeNormals()
const
498 FVector2D V12 = (V2 - V1).GetSafeNormal();
499 FVector2D V23 = (V3 - V2).GetSafeNormal();
500 return {FVector2D(-V12.Y, V12.X), FVector2D(-V23.Y, V23.X)};
503 auto SATtest = [&](
const FVector2D& Axis,
const F2DRectangle &Shape,
504 float &MinAlong,
float &MaxAlong)
506 for (
const FVector2D& Vert : {Shape.V1, Shape.V2, Shape.V3, Shape.V4})
508 float DotVal = FVector2D::DotProduct(Vert, Axis);
509 if( DotVal < MinAlong )
511 if( DotVal > MaxAlong )
515 auto IsBetweenOrdered = [&](
float Val,
float LowerBound,
float UpperBound ) ->
bool
517 return LowerBound <= Val && Val <= UpperBound ;
519 auto Overlaps = [&](
float Min1,
float Max1,
float Min2,
float Max2 ) ->
bool
521 return IsBetweenOrdered( Min2, Min1, Max1 ) || IsBetweenOrdered( Min1, Min2, Max2 ) ;
523 auto RectangleIntersect = [&](
524 const F2DRectangle& Rectangle1,
525 const F2DRectangle& Rectangle2) ->
bool
527 for (
const FVector2D& Normal : Rectangle1.ComputeNormals())
529 constexpr float LargeNumber = 10000000;
530 float Shape1Min = LargeNumber, Shape1Max = -LargeNumber;
531 float Shape2Min = LargeNumber, Shape2Max = -LargeNumber;
532 SATtest(Normal, Rectangle1, Shape1Min, Shape1Max);
533 SATtest(Normal, Rectangle2, Shape2Min, Shape2Max);
534 if (!Overlaps(Shape1Min, Shape1Max, Shape2Min, Shape2Max))
539 for (
const FVector2D& Normal : Rectangle2.ComputeNormals())
541 constexpr float LargeNumber = 10000000;
542 float Shape1Min = LargeNumber, Shape1Max = -LargeNumber;
543 float Shape2Min = LargeNumber, Shape2Max = -LargeNumber;
544 SATtest(Normal, Rectangle1, Shape1Min, Shape1Max);
545 SATtest(Normal, Rectangle2, Shape2Min, Shape2Max);
546 if (!Overlaps(Shape1Min, Shape1Max, Shape2Min, Shape2Max))
554 std::vector<std::pair<uint32_t, uint32_t>> TilesToCheck = {
555 {CenterTile_X-1, CenterTile_Y-1}, {CenterTile_X, CenterTile_Y-1},
556 {CenterTile_X+1, CenterTile_Y-1}, {CenterTile_X-1, CenterTile_Y},
557 {CenterTile_X+1, CenterTile_Y}, {CenterTile_X-1, CenterTile_Y+1},
558 {CenterTile_X, CenterTile_Y+1}, {CenterTile_X+1, CenterTile_Y+1}};
559 for (
auto& TileIdPair : TilesToCheck)
561 uint32_t &Tile_X = TileIdPair.first;
562 uint32_t &Tile_Y = TileIdPair.second;
564 FVector2D V2 = FVector2D(
GetTilePosition(Tile_X+1, Tile_Y).ToFVector());
565 FVector2D V3 = FVector2D(
GetTilePosition(Tile_X+1, Tile_Y+1).ToFVector());
566 FVector2D V4 = FVector2D(
GetTilePosition(Tile_X, Tile_Y+1).ToFVector());
567 if (RectangleIntersect(
568 F2DRectangle{BoxVert0,BoxVert1,BoxVert2,BoxVert3},
569 F2DRectangle{V1,V2,V3,V4}))
571 IntersectingTiles.emplace_back(
GetTileId(Tile_X, Tile_Y));
575 return IntersectingTiles;
583 uint32_t Tile_X = (uint32_t)(TileId >> 32);
584 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
586 uint32_t RadiusInTiles = (Radius/
TileSize);
587 uint32_t MinX = 0,MinY = 0,MaxX = 0,MaxY = 0;
589 TRACE_CPUPROFILER_EVENT_SCOPE(Comparisons);
590 if( Tile_X < RadiusInTiles){
593 MinX = Tile_X - RadiusInTiles;
596 if( Tile_Y < RadiusInTiles){
599 MinY = Tile_Y - RadiusInTiles;
602 MaxX = Tile_X + RadiusInTiles;
603 MaxY = Tile_Y + RadiusInTiles;
606 std::vector<uint64_t> LoadedTiles;
608 TRACE_CPUPROFILER_EVENT_SCOPE(Looping);
609 for( uint32_t X = MinX; X < MaxX; ++X )
611 for( uint32_t Y = MinY; Y < MaxY; ++Y )
614 if(
Map.find(CurrentTileId) !=
Map.end() )
616 LoadedTiles.emplace_back(CurrentTileId);
626 return (uint64_t) Tile_X << 32 | Tile_Y;
639 uint32_t Tile_X = (uint32_t)(TileId >> 32);
640 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
659 uint64_t TileId =
GetTileId(Tile_X, Tile_Y);
664 auto Iterator =
Map.find(TileId);
665 if (Iterator ==
Map.end())
673 auto CacheIterator =
CacheMap.find(TileId);
674 if (CacheIterator !=
CacheMap.end())
676 Map.emplace(TileId, std::move(CacheIterator->second));
688 return Iterator->second;
695 return FIntVector(Tile_X, Tile_Y, 0);
699 uint32_t Tile_X = (uint32_t)(TileId >> 32);
700 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
701 return FIntVector(Tile_X, Tile_Y, 0);
706 uint64_t TileId =
GetTileId(Tile_X, Tile_Y);
749 UE_LOG(LogCarla, Log,
750 TEXT(
"Sparse Map initialized"));
751 UE_LOG(LogCarla, Log,
752 TEXT(
"Map Extension %f %f %f"), MapSize.
X, MapSize.
Y, MapSize.
Z );
763 UE_LOG(LogCarla, Log,
764 TEXT(
"Height map updated"));
773 FDVector Position,
float RadiusX,
float RadiusY,
float CacheRadiusX,
float CacheRadiusY)
789 auto IsInCacheRange = [&](int32_t Tile_X, int32_t Tile_Y) ->
bool
791 return Tile_X >= CacheMinVector.X && Tile_X <= CacheMaxVector.X &&
792 Tile_Y >= CacheMinVector.Y && Tile_Y <= CacheMaxVector.Y;
794 auto IsInMapRange = [&](int32_t Tile_X, int32_t Tile_Y) ->
bool
796 return Tile_X >= MinVector.X && Tile_X <= MaxVector.X &&
797 Tile_Y >= MinVector.Y && Tile_Y <= MaxVector.Y;
802 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateMap);
804 std::vector<uint64_t> TilesToErase;
805 for (
auto &Element :
Map)
807 uint64_t TileId = Element.first;
809 if (!IsInMapRange(VectorTileId.X, VectorTileId.Y))
811 CacheMap.emplace(TileId, std::move(Element.second));
812 TilesToErase.emplace_back(TileId);
815 for (uint64_t TileId : TilesToErase)
822 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateCache);
825 std::vector<uint64_t> TilesToErase;
827 TRACE_CPUPROFILER_EVENT_SCOPE(GetTilesToErase);
830 uint64_t TileId = Element.first;
832 if (!IsInCacheRange(VectorTileId.X, VectorTileId.Y))
834 TilesToErase.emplace_back(TileId);
840 TRACE_CPUPROFILER_EVENT_SCOPE(EraseTiles);
841 ParallelFor(TilesToErase.size(), [&](int32 Idx)
843 TRACE_CPUPROFILER_EVENT_SCOPE(SaveData);
844 uint64_t TileId = TilesToErase[Idx];
845 auto& Tile = CacheMap[TileId];
846 std::string FileToSavePath = std::string(
847 TCHAR_TO_UTF8(*( SavePath + Tile.TilePosition.ToString() +
".tile")));
848 std::ofstream OutputStream(FileToSavePath.c_str());
849 WriteFVector(OutputStream, Tile.TilePosition.ToFVector());
850 WriteStdVector<FParticle> (OutputStream, Tile.Particles);
851 OutputStream.close();
854 TRACE_CPUPROFILER_EVENT_SCOPE(
CacheMap.erase);
855 for (uint64_t TileId : TilesToErase)
867 FVector PositionTranslated;
873 auto MinX = std::min(std::max(PositionTranslated.X - RadiusX, 0.0), (
Extension.
X - 1.0));
874 auto MinY = std::min(std::max(PositionTranslated.Y - RadiusY, 0.0), (-
Extension.
Y + 1.0));
875 auto MaxX = std::min(std::max(PositionTranslated.X + RadiusX, 0.0), (
Extension.
X - 1.0));
876 auto MaxY = std::min(std::max(PositionTranslated.Y + RadiusY, 0.0), (-
Extension.
Y + 1.0));
882 TRACE_CPUPROFILER_EVENT_SCOPE(TEXT(
"FSparseHighDetailMap::WaitUntilProperTilesAreLoaded"));
883 for(int32_t X = MinVector.X; X < MaxVector.X; X++ )
885 for(int32_t Y = MinVector.Y; Y < MaxVector.Y; Y++ )
887 bool ConditionToStopWaiting =
true;
891 while(ConditionToStopWaiting)
895 TRACE_CPUPROFILER_EVENT_SCOPE(TEXT(
"FSparseHighDetailMap::WaitUntilProperTilesAreLoaded::TimeLocked"));
896 ConditionToStopWaiting =
Map.find(CurrentTileID) ==
Map.end();
908 UE_LOG(LogCarla, Warning, TEXT(
"Save directory %s"), *
SavePath );
910 ParallelFor(
Map.size(), [
this](int32 Idx)
912 std::pair<uint64_t, FDenseTile> it = *(std::next(this->Map.begin(), Idx) );
913 std::string FileToSavePath = std::string(TCHAR_TO_UTF8(*( this->SavePath + it.second.TilePosition.ToString() +
".tile")));
914 std::ofstream OutputStream(FileToSavePath.c_str());
915 WriteFVector(OutputStream, it.second.TilePosition.ToFVector());
916 WriteStdVector<FParticle> (OutputStream, it.second.Particles);
917 OutputStream.close();
920 ParallelFor(
CacheMap.size(), [
this](int32 Idx)
922 std::pair<uint64_t, FDenseTile> it = *(std::next(this->CacheMap.begin(), Idx) );
923 std::string FileToSavePath = std::string(TCHAR_TO_UTF8(*( this->SavePath + it.second.TilePosition.ToString() +
".tile")));
924 std::ofstream OutputStream(FileToSavePath.c_str());
925 WriteFVector(OutputStream, it.second.TilePosition.ToFVector());
926 WriteStdVector<FParticle> (OutputStream, it.second.Particles);
927 OutputStream.close();
932void UCustomTerrainPhysicsComponent::UpdateTexture()
934 UpdateLoadedTextureDataRegions();
936 ENQUEUE_RENDER_COMMAND(UpdateDynamicTextureCode)
938 [NewData=Data, Texture=TextureToUpdate](
auto &InRHICmdList)
mutable
940 TRACE_CPUPROFILER_EVENT_SCOPE(TEXT(
"UCustomTerrainPhysicsComponent::TickComponent Renderthread"));
941 FUpdateTextureRegion2D region;
946 region.Width = Texture->GetSizeX();
947 region.Height = Texture->GetSizeY();
949 FTexture2DResource* resource = (FTexture2DResource*)Texture->GetResource();
951 resource->GetTexture2DRHI(), 0, region, region.Width *
sizeof(uint8_t), &NewData[0]);
955void UCustomTerrainPhysicsComponent::InitTexture(){
956 if( Data.Num() == 0 && TextureToUpdate ){
957 float LimitX = TextureToUpdate->GetSizeX();
958 float LimitY = TextureToUpdate->GetSizeY();
959 Data.Init(128, LimitX * LimitY);
962 if( LargeData.Num() == 0 && LargeTextureToUpdate ){
963 float LimitX = LargeTextureToUpdate->GetSizeX();
964 float LimitY = LargeTextureToUpdate->GetSizeY();
965 LargeData.Init(128, LimitX * LimitY);
969void UCustomTerrainPhysicsComponent::UpdateLoadedTextureDataRegions()
971 TRACE_CPUPROFILER_EVENT_SCOPE(
"UCustomTerrainPhysicsComponent::UpdateLoadedTextureDataRegions");
972 const int32_t TextureSizeX = TextureToUpdate->GetSizeX();
973 if ( TextureSizeX == 0)
return;
978 std::vector<uint64_t> LoadedTiles =
979 SparseMap.GetLoadedTilesInRange(TextureCenterPosition, TextureRadius );
980 FDVector TextureOrigin = TextureCenterPosition -
FDVector(TextureRadius, TextureRadius, 0);
981 float GlobalTexelSize = (2.0f * TextureRadius) / TextureSizeX;
982 int32_t PartialHeightMapSize = std::floor( SparseMap.GetTileSize() * TextureSizeX / (2*TextureRadius) );
984 float LocalTexelSize = SparseMap.GetTileSize() / PartialHeightMapSize;
985 LocalTexelSize = std::floor( LocalTexelSize * 1000.0f ) / 1000.0f;
987 Data.Init( 128, Data.Num() );
988 float DisplacementRange = MaxDisplacement - MinDisplacement;
989 float InverseDisplacementRange = 1.0f / DisplacementRange;
991 for (uint64_t TileId : LoadedTiles)
993 FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
1001 for (int32_t Local_Y = 0; Local_Y < PartialHeightMapSize; ++Local_Y)
1003 for (int32_t Local_X = 0; Local_X < PartialHeightMapSize; ++Local_X)
1005 int32_t LocalIndex = Local_Y * PartialHeightMapSize + Local_X;
1008 TilePosition +
FDVector(Local_X*LocalTexelSize, Local_Y*LocalTexelSize, 0);
1009 int32_t Coord_X = std::floor( (LocalTexelPosition.
X - TextureOrigin.
X ) / GlobalTexelSize );
1010 int32_t Coord_Y = std::floor( (LocalTexelPosition.
Y - TextureOrigin.
Y ) / GlobalTexelSize );
1012 if ( Coord_X >= 0 && Coord_X < TextureSizeX &&
1013 Coord_Y >= 0 && Coord_Y < TextureToUpdate->GetSizeY() )
1015 float OriginalHeight = SparseMap.GetHeight(LocalTexelPosition);
1016 float Displacement = Height - OriginalHeight;
1017 float Fraction = (Displacement - MinDisplacement) * InverseDisplacementRange;
1018 Fraction = FMath::Clamp(Fraction, 0.f, 1.f) * 255;
1019 Data[Coord_X * TextureToUpdate->GetSizeY() + Coord_Y] =
static_cast<uint8_t
>(Fraction );
1026void UCustomTerrainPhysicsComponent::UpdateLargeTexture()
1028 UpdateLargeTextureData();
1030 ENQUEUE_RENDER_COMMAND(UpdateDynamicTextureCode)
1032 [NewData=LargeData, Texture=LargeTextureToUpdate](
auto &InRHICmdList)
mutable
1034 TRACE_CPUPROFILER_EVENT_SCOPE(TEXT(
"UCustomTerrainPhysicsComponent::TickComponent Renderthread"));
1035 FUpdateTextureRegion2D region;
1040 region.Width = Texture->GetSizeX();
1041 region.Height = Texture->GetSizeY();
1043 FTexture2DResource* resource = (FTexture2DResource*)Texture->GetResource();
1045 resource->GetTexture2DRHI(), 0, region, region.Width *
sizeof(uint8_t), &NewData[0]);
1049void UCustomTerrainPhysicsComponent::UpdateLargeTextureData()
1051 uint32_t NumberOfParticlesIn1AxisInLocalHeightmap = TextureToUpdate->GetSizeX() / (TextureRadius * 2) / TileSize;
1052 uint32_t NumberOfParticlesIn1AxisInLargeHeightmap = LargeTextureToUpdate->GetSizeX() / (CacheRadius.X * 2) / TileSize;
1054 std::vector<float> ParticlesPositions;
1056 TRACE_CPUPROFILER_EVENT_SCOPE(TEXT(
"UCustomTerrainPhysicsComponent::UpdateLargeTextureData::GettingHeightMaps"));
1057 FVector OriginPosition;
1058 OriginPosition.X = CachePosition.X + (WorldSize.X * 0.5f);
1059 OriginPosition.Y = -CachePosition.Y - (WorldSize.Y * 0.5f);
1064 int32_t OffsetX = 0;
1065 int32_t OffsetY = 0;
1066 float* Ptr = &ParticlesPositions[0];
1067 while( OffsetY < LargeTextureToUpdate->GetSizeY() )
1069 for(uint32_t
y = 0;
y < NumberOfParticlesIn1AxisInLocalHeightmap;
y++)
1071 float LocalYTransformed = std::floor(
y / NumberOfParticlesIn1AxisInLocalHeightmap * NumberOfParticlesIn1AxisInLargeHeightmap);
1072 for(uint32_t
x = 0;
x < NumberOfParticlesIn1AxisInLocalHeightmap;
x++)
1074 uint32_t LocalIndex =
x +
y * NumberOfParticlesIn1AxisInLocalHeightmap;
1075 float LocalXTransformed = std::floor(
x / NumberOfParticlesIn1AxisInLocalHeightmap * NumberOfParticlesIn1AxisInLargeHeightmap);
1081 Ptr += (NumberOfParticlesIn1AxisInLocalHeightmap* NumberOfParticlesIn1AxisInLocalHeightmap);
1083 OffsetX += NumberOfParticlesIn1AxisInLargeHeightmap;
1084 if( OffsetX >= LargeTextureToUpdate->GetSizeX() )
1087 OffsetY += NumberOfParticlesIn1AxisInLargeHeightmap;
1093UCustomTerrainPhysicsComponent::UCustomTerrainPhysicsComponent()
1096 PrimaryComponentTick.bCanEverTick =
true;
1099void UCustomTerrainPhysicsComponent::BeginPlay()
1101 TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::BeginPlay);
1106 RootComponent = Cast<UPrimitiveComponent>(GetOwner()->GetRootComponent());
1109 UE_LOG(LogCarla, Error,
1110 TEXT(
"UCustomTerrainPhysicsComponent: Root component is not a UPrimitiveComponent"));
1113 bUpdateParticles =
true;
1114 DrawDebugInfo =
false;
1115 bUseDynamicModel =
false;
1116 bDisableVehicleGravity =
false;
1118 bUseImpulse =
false;
1119 bUseMeanAcceleration =
false;
1122 bDrawHeightMap =
false;
1123 ForceMulFactor = 1.f;
1124 ParticleForceMulFactor = 1.f;
1126 bDrawLoadedTiles =
false;
1127 bUseSoilType =
true;
1128 EffectMultiplayer = 200.0f;
1129 MinDisplacement = -10.0f;
1130 MaxDisplacement = 10.0f;
1131 bRemoveLandscapeColliders =
false;
1135 if (FParse::Value(FCommandLine::Get(), TEXT(
"-cuda-device="), IntValue))
1137 CUDADevice = IntValue;
1139 if (FParse::Value(FCommandLine::Get(), TEXT(
"-max-particles-per-wheel="), IntValue))
1141 MaxParticlesPerWheel = IntValue;
1144 if (FParse::Value(FCommandLine::Get(), TEXT(
"-particle-size="), Value))
1146 ParticleDiameter =
MToCM*Value;
1148 if (FParse::Value(FCommandLine::Get(), TEXT(
"-terrain-depth="), Value))
1150 TerrainDepth =
MToCM*Value;
1152 if (FParse::Value(FCommandLine::Get(), TEXT(
"-search-radius="), Value))
1154 SearchRadius =
MToCM*Value;
1156 if (FParse::Value(FCommandLine::Get(), TEXT(
"-box-search-forward="), Value))
1158 BoxSearchForwardDistance =
MToCM*Value;
1160 if (FParse::Value(FCommandLine::Get(), TEXT(
"-box-search-lateral="), Value))
1162 BoxSearchLateralDistance =
MToCM*Value;
1164 if (FParse::Value(FCommandLine::Get(), TEXT(
"-box-search-depth="), Value))
1166 BoxSearchDepthDistance =
MToCM*Value;
1168 if (FParse::Value(FCommandLine::Get(), TEXT(
"-force-mul-factor="), Value))
1170 ForceMulFactor = Value;
1172 if (FParse::Value(FCommandLine::Get(), TEXT(
"-defor-mul="), Value))
1174 EffectMultiplayer = Value;
1176 if (FParse::Value(FCommandLine::Get(), TEXT(
"-defor-res="), Value))
1180 if (FParse::Value(FCommandLine::Get(), TEXT(
"-min-displacement="), Value))
1182 MinDisplacement = Value;
1184 if (FParse::Value(FCommandLine::Get(), TEXT(
"-max-displacement="), Value))
1186 MaxDisplacement = Value;
1188 if (FParse::Value(FCommandLine::Get(), TEXT(
"-particle-force-mul-factor="), Value))
1190 ParticleForceMulFactor = Value;
1192 if (FParse::Value(FCommandLine::Get(), TEXT(
"-max-force="), Value))
1194 MaxForceMagnitude =
MToCM*Value;
1196 if (FParse::Value(FCommandLine::Get(), TEXT(
"-floor-height="), Value))
1198 FloorHeight =
MToCM*Value;
1200 if (FParse::Value(FCommandLine::Get(), TEXT(
"-tile-size="), Value))
1204 if (FParse::Value(FCommandLine::Get(), TEXT(
"-tile-radius="), Value))
1206 TileRadius =
MToCM*FVector(Value, Value, 0.f);
1208 if (FParse::Value(FCommandLine::Get(), TEXT(
"-cache-radius="), Value))
1210 CacheRadius =
MToCM*FVector(Value, Value, 0.f);
1212 if (FParse::Param(FCommandLine::Get(), TEXT(
"-update-particles")))
1214 bUpdateParticles =
true;
1216 if (FParse::Param(FCommandLine::Get(), TEXT(
"-draw-debug-info")))
1218 DrawDebugInfo =
true;
1220 if (FParse::Param(FCommandLine::Get(), TEXT(
"-use-local-frame")))
1222 bUseLocalFrame =
true;
1225 if (FParse::Value(FCommandLine::Get(), TEXT(
"-network-path="), Path))
1227 NeuralModelFile =
Path;
1235 if (FParse::Param(FCommandLine::Get(), TEXT(
"-dynamic-model")))
1237 bUseDynamicModel =
true;
1239 if (FParse::Param(FCommandLine::Get(), TEXT(
"-disable-gravity")))
1241 bDisableVehicleGravity =
true;
1243 if (FParse::Param(FCommandLine::Get(), TEXT(
"-disable-nn-verbose")))
1247 if (FParse::Param(FCommandLine::Get(), TEXT(
"-use-terrain-type")))
1249 bUseSoilType =
true;
1251 if (FParse::Param(FCommandLine::Get(), TEXT(
"-use-impulse")))
1255 if (FParse::Param(FCommandLine::Get(), TEXT(
"-use-mean-acceleration")))
1257 bUseMeanAcceleration =
true;
1259 if (FParse::Param(FCommandLine::Get(), TEXT(
"-hide-debug-forces")))
1261 bShowForces =
false;
1263 if (FParse::Param(FCommandLine::Get(), TEXT(
"-benchmark")))
1267 if (FParse::Param(FCommandLine::Get(), TEXT(
"-draw-loaded-tiles")))
1269 bDrawLoadedTiles =
true;
1271 if (FParse::Param(FCommandLine::Get(), TEXT(
"-remove-colliders")))
1273 bRemoveLandscapeColliders =
true;
1275 if (FParse::Param(FCommandLine::Get(), TEXT(
"-disable-terramechanics")))
1277 SetComponentTickEnabled(
false);
1281 if(bRemoveLandscapeColliders)
1283 FWorldDelegates::LevelAddedToWorld.AddUObject(
1284 this, &UCustomTerrainPhysicsComponent::OnLevelAddedToWorld);
1288 if( TexturesRes.Contains(ChosenRes) ){
1289 TextureToUpdate = TexturesRes[ChosenRes];
1293 TRACE_CPUPROFILER_EVENT_SCOPE(InitializeDenseMap);
1295 UE_LOG(LogCarla, Warning,
1296 TEXT(
"ParticleDiameter %f"), ParticleDiameter);
1298 SparseMap.Init(TextureToUpdate->GetSizeX(), TextureRadius, ParticleDiameter *
CMToM, TerrainDepth *
CMToM, FloorHeight *
CMToM );
1299 RootComponent = Cast<UPrimitiveComponent>(GetOwner()->GetRootComponent());
1302 FIntVector NumTiles = LargeMapManager->GetNumTilesInXY();
1312 TileSize, HeightMapScaleFactor.Z);
1317 TRACE_CPUPROFILER_EVENT_SCOPE(LoadNNModel);
1319 TerramechanicsModel.LoadModel(TCHAR_TO_ANSI(*NeuralModelFile), CUDADevice);
1323 FString LevelName = GetWorld()->GetMapName();
1324 LevelName.RemoveFromStart(GetWorld()->StreamingLevelsPrefix);
1326 SavePath = FString(
CachePath.c_str()) + LevelName +
"_Terrain/";
1327 SparseMap.SavePath = SavePath;
1329 IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
1330 if( FileManager.CreateDirectory(*SavePath)){
1331 UE_LOG(LogCarla, Warning,
1332 TEXT(
"Folder was created at %s"), *SavePath);
1334 UE_LOG(LogCarla, Error,
1335 TEXT(
"Folder was not created at %s"), *SavePath);
1338 if(bUseDeformationPlane){
1339 DeformationPlaneActor = GetWorld()->SpawnActor<AStaticMeshActor>();
1341 if( DeformationPlaneActor )
1343 DeformationPlaneActor->GetStaticMeshComponent()->SetStaticMesh( DeformationPlaneMesh );
1344 DeformationPlaneActor->GetStaticMeshComponent()->SetMaterial( 0, DeformationPlaneMaterial );
1345 DeformationPlaneActor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
1351 UE_LOG(LogCarla, Log, TEXT(
"MainThread Data ArraySize %d "), Data.Num());
1352 UE_LOG(LogCarla, Log, TEXT(
"Map Size %d "), SparseMap.Map.size() );
1354 if (TilesWorker ==
nullptr)
1356 TilesWorker =
new FTilesWorker(
this, GetOwner()->GetActorLocation(), TileRadius.X, TileRadius.Y);
1357 Thread = FRunnableThread::Create(TilesWorker, TEXT(
"TilesWorker"));
1362void UCustomTerrainPhysicsComponent::BuildLandscapeHeightMapDataAasset(ALandscapeProxy* Landscape,
1363 int Resolution, FVector MapSize, FString AssetPath, FString AssetName)
1365 TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::BuildLandscapeHeightMapTexture);
1366 TArray<float> HeightMap;
1367 HeightMap.Reserve(Resolution*Resolution);
1368 FVector Origin = Landscape->GetActorLocation();
1369 float DeltaX = MapSize.X / Resolution;
1370 float DeltaY = MapSize.Y / Resolution;
1371 for (
size_t i = 0; i < Resolution; ++i)
1373 float PosX = Origin.X + i*DeltaX;
1374 for (
size_t j = 0; j < Resolution; ++j)
1376 float PosY = Origin.Y + j*DeltaY;
1377 FVector
Location = FVector(PosX, PosY, 0);
1378 float Height = Landscape->GetHeightAtLocation(Location).Get(-1);
1379 HeightMap.Emplace(Height);
1382 int TextureWidth = Resolution;
1383 int TextureHeight = Resolution;
1384 FString PackageName = AssetPath;
1385 PackageName += AssetName;
1386 UPackage* Package = CreatePackage(*PackageName);
1387 Package->FullyLoad();
1389 UHeightMapDataAsset* HeightMapAsset = NewObject<UHeightMapDataAsset>(Package, *AssetName, RF_Public | RF_Standalone | RF_MarkAsRootSet);
1390 HeightMapAsset->AddToRoot();
1391 HeightMapAsset->
SizeX = TextureWidth;
1392 HeightMapAsset->
SizeY = TextureHeight;
1395 Package->MarkPackageDirty();
1398 FSavePackageArgs SaveArgs;
1399 SaveArgs.TopLevelFlags =
1400 EObjectFlags::RF_Public |
1401 EObjectFlags::RF_Standalone;
1402 SaveArgs.Error = GError;
1403 SaveArgs.bForceByteSwapping =
true;
1404 SaveArgs.bWarnOfLongFilename =
true;
1405 SaveArgs.SaveFlags = SAVE_NoError;
1407 FString PackageFileName = FPackageName::LongPackageNameToFilename(
1409 FPackageName::GetAssetPackageExtension());
1411 bool bSaved = UPackage::SavePackage(
1419float UCustomTerrainPhysicsComponent::GetHeightAtLocation(ALandscapeProxy * Landscape, FVector Location)
1421 TOptional<float> OptionalHeight = Landscape->GetHeightAtLocation(Location);
1422 if(OptionalHeight.IsSet())
1423 return OptionalHeight.GetValue();
1427void UCustomTerrainPhysicsComponent::EndPlay(
const EEndPlayReason::Type EndPlayReason){
1428 Super::EndPlay(EndPlayReason);
1429 if( Thread && TilesWorker){
1430 TilesWorker->bShouldContinue =
false;
1431 Thread->WaitForCompletion();
1432 Thread->Kill(
false);
1434 TilesWorker =
nullptr;
1437 if (PendingHeightMapHandle.IsValid())
1439 PendingHeightMapHandle->CancelHandle();
1440 PendingHeightMapHandle.Reset();
1444 SparseMap.SaveMap();
1447void UCustomTerrainPhysicsComponent::OnHeightMapLoaded()
1449 if (!PendingHeightMapHandle.IsValid())
1453 UObject* LoadedObject = PendingHeightMapHandle->GetLoadedAsset();
1454 const FIntVector TargetTileId = PendingHeightMapTileId;
1455 PendingHeightMapHandle.Reset();
1458 if (HeightMapDataAsset ==
nullptr || LargeMapManager ==
nullptr)
1460 UE_LOG(LogCarla, Warning,
1461 TEXT(
"UCustomTerrainPhysicsComponent::OnHeightMapLoaded: async load for tile %s resolved but asset is unusable"),
1462 *TargetTileId.ToString());
1466 ActiveHeightMap = HeightMapDataAsset;
1467 FVector TilePosition =
1469 + LargeMapManager->GetTileLocation(TargetTileId)
1470 - 0.5f * FVector(LargeMapManager->GetTileSize(), -LargeMapManager->GetTileSize(), 0);
1471 UE_LOG(LogCarla, Log,
1472 TEXT(
"Async height map loaded for tile %s at location %s"),
1473 *TargetTileId.ToString(), *TilePosition.ToString());
1475 SparseMap.UpdateHeightMap(
1479 LargeMapManager->GetTileSize(),
1480 -LargeMapManager->GetTileSize(),
1483 HeightMapScaleFactor.Z);
1486void UCustomTerrainPhysicsComponent::TickComponent(
float DeltaTime,
1487 ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
1489 TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::TickComponent);
1490 Super::TickComponent(DeltaTime,TickType,ThisTickFunction);
1492 TArray<AActor*> VehiclesActors;
1493 UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACarlaWheeledVehicle::StaticClass(), VehiclesActors);
1495 for (
AActor* VehicleActor : VehiclesActors)
1513 FVector GlobalLocation =
Vehicle->GetActorLocation();
1516 GlobalLocation = LargeMapManager->LocalToGlobalLocation(
Vehicle->GetActorLocation());
1518 uint64_t TileId = LargeMapManager->GetTileID(GlobalLocation);
1519 FIntVector CurrentTileId =
1520 LargeMapManager->GetTileVectorID(GlobalLocation);
1521 if(CurrentLargeMapTileId != CurrentTileId)
1524 FCarlaMapTile* LargeMapTile = LargeMapManager->GetCarlaMapTile(TileId);
1527 CurrentLargeMapTileId = CurrentTileId;
1528 FString FullTileNamePath = LargeMapTile->
Name;
1529 FString TileDirectory;
1532 FPaths::Split(FullTileNamePath, TileDirectory, TileName, Extension);
1533 FString AssetPath = TileDirectory +
"/HeightMaps/" + TileName +
"." + TileName;
1534 UE_LOG(LogCarla, Log, TEXT(
"Enter tile %s, %s \n %s \n %s \n %s"), *CurrentTileId.ToString(),
1535 *FullTileNamePath, *TileDirectory, *TileName, *Extension);
1543 if (PendingHeightMapHandle.IsValid())
1545 PendingHeightMapHandle->CancelHandle();
1546 PendingHeightMapHandle.Reset();
1548 PendingHeightMapTileId = CurrentTileId;
1549 FSoftObjectPath HeightMapSoftPath(AssetPath);
1550 FStreamableManager& Streamable = UAssetManager::GetStreamableManager();
1551 PendingHeightMapHandle = Streamable.RequestAsyncLoad(
1553 FStreamableDelegate::CreateUObject(
1555 &UCustomTerrainPhysicsComponent::OnHeightMapLoaded));
1559 UObject* DataAssetObject = StaticLoadObject(UHeightMapDataAsset::StaticClass(),
nullptr, *(AssetPath));
1563 if (HeightMapDataAsset !=
nullptr)
1565 FVector TilePosition = HeightMapOffset + LargeMapManager->GetTileLocation(CurrentLargeMapTileId) - 0.5f*FVector(LargeMapManager->GetTileSize(), -LargeMapManager->GetTileSize(), 0);
1566 UE_LOG(LogCarla, Log, TEXT(
"Updating height map to location %s in tile location %s"),
1567 *TilePosition.ToString(), *LargeMapManager->GetTileLocation(CurrentLargeMapTileId).ToString());
1569 ActiveHeightMap = HeightMapDataAsset;
1570 SparseMap.UpdateHeightMap(
1572 LargeMapManager->GetTileSize(),-LargeMapManager->GetTileSize(), 0)),
1573 1.f, HeightMapScaleFactor.Z);
1587 SparseMap.LockMutex();
1588 RunNNPhysicsSimulation(
Vehicle, DeltaTime);
1589 LastUpdatedPosition = GlobalLocation;
1590 SparseMap.UnLockMutex();
1592 if (bDrawLoadedTiles)
1594 DrawTiles(GetWorld(), SparseMap.GetTileIdInMap(), GlobalLocation.Z + 300, FLinearColor(0.0,0.0,1.0,0.0));
1595 DrawTiles(GetWorld(), SparseMap.GetTileIdInCache(), GlobalLocation.Z + 300, FLinearColor(1.0,0.0,0.0,0.0));
1598 if( MPCInstance ==
nullptr )
1601 MPCInstance = GetWorld()->GetParameterCollectionInstance( MPC );
1606 MPCInstance->SetVectorParameterValue(
"PositionToUpdate", GetTileCenter(LastUpdatedPosition));
1608 MPCInstance->SetScalarParameterValue(
"TextureRadius", TextureRadius * 100);
1609 MPCInstance->SetScalarParameterValue(
"LargeTextureRadius", TextureRadius * 100);
1610 MPCInstance->SetScalarParameterValue(
"EffectMultiplayer", EffectMultiplayer);
1611 MPCInstance->SetScalarParameterValue(
"MinDisplacement", MinDisplacement);
1612 MPCInstance->SetScalarParameterValue(
"MaxDisplacement", MinDisplacement);
1613 if(TextureToUpdate){
1614 MPCInstance->SetScalarParameterValue(
"TexSizeX", TextureToUpdate->GetSizeX());
1618 if(bUseDeformationPlane){
1619 if( DeformationPlaneActor ){
1620 DeformationPlaneActor->SetActorLocation(LastUpdatedPosition,
false,
nullptr);
1622 DeformationPlaneActor = GetWorld()->SpawnActor<AStaticMeshActor>();
1624 if( DeformationPlaneActor )
1626 DeformationPlaneActor->GetStaticMeshComponent()->SetStaticMesh( DeformationPlaneMesh );
1627 DeformationPlaneActor->GetStaticMeshComponent()->SetMaterial( 0, DeformationPlaneMaterial );
1628 DeformationPlaneActor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
1636 TRACE_CPUPROFILER_EVENT_SCOPE(DrawHeightMap);
1637 float LifeTime = 0.3f;
1638 bool bPersistentLines =
false;
1639 bool bDepthIsForeground = (0 == SDPG_Foreground);
1640 UWorld* World = GetWorld();
1641 ULineBatchComponent* LineBatcher =
1642 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
1643 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
1646 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
1649 float DrawPos_X = DrawStart.X;
1650 float DrawPos_Y = DrawStart.Y;
1651 for (DrawPos_X = DrawStart.X; DrawPos_X < DrawEnd.X; DrawPos_X += DrawInterval.X)
1653 for (DrawPos_Y = DrawStart.Y; DrawPos_Y < DrawEnd.Y; DrawPos_Y += DrawInterval.Y)
1655 float Height = SparseMap.GetHeight(
UEFrameToSI(FVector(DrawPos_X, DrawPos_Y, 0)));
1659 Point = LargeMapManager->GlobalToLocalLocation(Point);
1661 LineBatcher->DrawPoint(Point,
1662 FLinearColor(1.f, 0.f, 0.f), 10.0, 0, LifeTime);
1669void UCustomTerrainPhysicsComponent::DrawParticles(UWorld* World, std::vector<FParticle*>& Particles,
1672 float LifeTime = 0.3f;
1673 bool bPersistentLines =
false;
1674 bool bDepthIsForeground = (0 == SDPG_Foreground);
1675 ULineBatchComponent* LineBatcher =
1676 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
1677 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
1680 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
1689 Point = LargeMapManager->GlobalToLocalLocation(Point);
1691 LineBatcher->DrawPoint(Point,
1692 Color, 1.0, 0, LifeTime);
1696void UCustomTerrainPhysicsComponent::DrawParticlesArray(UWorld* World, TArray<float>& ParticlesArray,
1699 float LifeTime = 0.3f;
1700 bool bPersistentLines =
false;
1701 bool bDepthIsForeground = (0 == SDPG_Foreground);
1702 ULineBatchComponent* LineBatcher =
1703 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
1704 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
1707 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
1709 for(
int i = 0; i < ParticlesArray.Num(); i+=3)
1711 FVector
Position = FVector(ParticlesArray[i+0], ParticlesArray[i+1], ParticlesArray[i+2]);
1715 LineBatcher->DrawPoint(Point,
1716 Color, 1.0, 0, LifeTime);
1720void UCustomTerrainPhysicsComponent::DrawOrientedBox(UWorld* World,
const TArray<FOrientedBox>& Boxes)
1722 float LifeTime = 0.3f;
1723 bool bPersistentLines =
false;
1724 bool bDepthIsForeground = (0 == SDPG_Foreground);
1725 float Thickness = 2.0f;
1726 ULineBatchComponent* LineBatcher =
1727 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
1728 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
1731 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
1733 for (
const FOrientedBox& OBox : Boxes)
1735 TArray<FVector> Vertices;
1737 OBox.CalcVertices(&Vertices[0]);
1740 for(FVector& Point : Vertices)
1742 Point = LargeMapManager->GlobalToLocalLocation(Point);
1746 FBatchedLine BatchedLines[] =
1748 FBatchedLine(Vertices[0], Vertices[1],
1749 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1750 FBatchedLine(Vertices[0], Vertices[2],
1751 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1752 FBatchedLine(Vertices[2], Vertices[3],
1753 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1754 FBatchedLine(Vertices[3], Vertices[1],
1755 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1757 FBatchedLine(Vertices[4], Vertices[5],
1758 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1759 FBatchedLine(Vertices[4], Vertices[6],
1760 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1761 FBatchedLine(Vertices[6], Vertices[7],
1762 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1763 FBatchedLine(Vertices[7], Vertices[5],
1764 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1766 FBatchedLine(Vertices[0], Vertices[4],
1767 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1768 FBatchedLine(Vertices[1], Vertices[5],
1769 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1770 FBatchedLine(Vertices[2], Vertices[6],
1771 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1772 FBatchedLine(Vertices[3], Vertices[7],
1773 FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0)
1776 LineBatcher->DrawLines(TArrayView<FBatchedLine>(BatchedLines, 12));
1780void UCustomTerrainPhysicsComponent::DrawTiles(UWorld* World,
const std::vector<uint64_t>& TilesIds,
float Height,
1783 float LifeTime = 0.3f;
1784 bool bPersistentLines =
false;
1785 bool bDepthIsForeground = (0 == SDPG_Foreground);
1786 float Thickness = 2.0f;
1787 ULineBatchComponent* LineBatcher =
1788 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
1789 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
1792 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
1795 for (
const uint64_t& TileId : TilesIds)
1797 FVector TileCenter = SparseMap.GetTilePosition(TileId).ToFVector();
1799 FVector V2 =
SIToUEFrame(TileCenter + FVector(SparseMap.GetTileSize(),0,0));
1800 FVector V3 =
SIToUEFrame(TileCenter + FVector(0,SparseMap.GetTileSize(),0));
1801 FVector V4 =
SIToUEFrame(TileCenter + FVector(SparseMap.GetTileSize(),SparseMap.GetTileSize(),0));
1804 V1 = LargeMapManager->GlobalToLocalLocation(V1);
1805 V2 = LargeMapManager->GlobalToLocalLocation(V2);
1806 V3 = LargeMapManager->GlobalToLocalLocation(V3);
1807 V4 = LargeMapManager->GlobalToLocalLocation(V4);
1813 FBatchedLine BatchedLines[] =
1815 FBatchedLine(V1, V2,
1816 Color, LifeTime, Thickness, 0),
1817 FBatchedLine(V2, V4,
1818 Color, LifeTime, Thickness, 0),
1819 FBatchedLine(V1, V3,
1820 Color, LifeTime, Thickness, 0),
1821 FBatchedLine(V3, V4,
1822 Color, LifeTime, Thickness, 0)
1825 LineBatcher->DrawLines(TArrayView<FBatchedLine>(BatchedLines, 4));
1831void UCustomTerrainPhysicsComponent::LimitParticlesPerWheel(std::vector<FParticle*> &Particles)
1833 TRACE_CPUPROFILER_EVENT_SCOPE(LimitParticlesPerWheel);
1834 if (
Particles.size() < MaxParticlesPerWheel)
1840 return P1->Position.Z > P2->Position.Z;
1845void UCustomTerrainPhysicsComponent::GenerateBenchmarkParticles(std::vector<FParticle>& BenchParticles,
1846 std::vector<FParticle*> &ParticlesWheel0, std::vector<FParticle*> &ParticlesWheel1,
1847 std::vector<FParticle*> &ParticlesWheel2, std::vector<FParticle*> &ParticlesWheel3,
1848 FOrientedBox &BboxWheel0, FOrientedBox &BboxWheel1,
1849 FOrientedBox &BboxWheel2, FOrientedBox &BboxWheel3)
1851 TRACE_CPUPROFILER_EVENT_SCOPE(GenerateBenchmarkParticles);
1852 BenchParticles.reserve(100000);
1853 auto GenerateBoxParticles = [&](FOrientedBox &BboxWheel, std::vector<FParticle*> &ParticlesWheel)
1855 ParticlesWheel.clear();
1856 FVector TileOrigin = FVector(0,0,0);
1857 FVector BoxSize = FVector(2*BboxWheel.ExtentX, 2*BboxWheel.ExtentY, BboxWheel.ExtentZ);
1858 uint32_t NumParticles_X = BoxSize.X / ParticleDiameter;
1859 uint32_t NumParticles_Y = BoxSize.Y / ParticleDiameter;
1860 uint32_t NumParticles_Z = BoxSize.Z / ParticleDiameter;
1861 UE_LOG(LogCarla, Log, TEXT(
"Generating (%d,%d,%d) particles"),
1862 NumParticles_X,NumParticles_Y,NumParticles_Z);
1863 for(uint32_t i = 0; i < NumParticles_X; i++)
1865 float XPos = i*ParticleDiameter;
1866 for(uint32_t j = 0; j < NumParticles_Y; j++)
1868 float YPos = j*ParticleDiameter;
1869 for(uint32_t k = 0; k < NumParticles_Z; k++)
1871 float ZPos = k*ParticleDiameter;
1872 FVector ParticlePosition = TileOrigin + FVector(XPos, YPos, ZPos);
1873 ParticlePosition = (ParticlePosition.X - BboxWheel.ExtentX) * BboxWheel0.AxisX +
1874 (ParticlePosition.Y - BboxWheel.ExtentY) * BboxWheel0.AxisY +
1875 (ParticlePosition.Z - BboxWheel.ExtentZ) * BboxWheel0.AxisZ + BboxWheel.Center;
1877 BenchParticles.emplace_back(
FParticle{ParticlePosition, FVector(0), ParticleDiameter/2.f});
1878 ParticlesWheel.emplace_back(&BenchParticles.back());
1883 GenerateBoxParticles(BboxWheel0, ParticlesWheel0);
1884 GenerateBoxParticles(BboxWheel1, ParticlesWheel1);
1885 GenerateBoxParticles(BboxWheel2, ParticlesWheel2);
1886 GenerateBoxParticles(BboxWheel3, ParticlesWheel3);
1888 UE_LOG(LogCarla, Log, TEXT(
"Generated %d particles"), BenchParticles.size());
1891void UCustomTerrainPhysicsComponent::RunNNPhysicsSimulation(
1894 TRACE_CPUPROFILER_EVENT_SCOPE(RunNNPhysicsSimulation);
1896 FTransform VehicleTransform =
Vehicle->GetTransform();
1897 FTransform WheelTransform0 = VehicleTransform;
1898 FTransform WheelTransform1 = VehicleTransform;
1899 FTransform WheelTransform2 = VehicleTransform;
1900 FTransform WheelTransform3 = VehicleTransform;
1901 FVector WheelPosition0 = VehicleTransform.TransformPosition(FVector(140, -70, 40));
1902 FVector WheelPosition1 = VehicleTransform.TransformPosition(FVector(140, 70, 40));
1903 FVector WheelPosition2 = VehicleTransform.TransformPosition(FVector(-140, -70, 40));
1904 FVector WheelPosition3 = VehicleTransform.TransformPosition(FVector(-140, 70, 40));
1905 WheelTransform0.SetLocation(WheelPosition0);
1906 WheelTransform1.SetLocation(WheelPosition1);
1907 WheelTransform2.SetLocation(WheelPosition2);
1908 WheelTransform3.SetLocation(WheelPosition3);
1911 WheelPosition0 = LargeMapManager->LocalToGlobalLocation(WheelPosition0);
1912 WheelPosition1 = LargeMapManager->LocalToGlobalLocation(WheelPosition1);
1913 WheelPosition2 = LargeMapManager->LocalToGlobalLocation(WheelPosition2);
1914 WheelPosition3 = LargeMapManager->LocalToGlobalLocation(WheelPosition3);
1916 FOrientedBox BboxWheel0;
1917 BboxWheel0.AxisX = VehicleTransform.GetUnitAxis(EAxis::X);
1918 BboxWheel0.AxisY = VehicleTransform.GetUnitAxis(EAxis::Y);
1919 BboxWheel0.AxisZ = VehicleTransform.GetUnitAxis(EAxis::Z);
1920 BboxWheel0.Center = WheelPosition0 + FVector(0,0,-TireRadius);
1921 BboxWheel0.ExtentX = BoxSearchForwardDistance;
1922 BboxWheel0.ExtentY = BoxSearchLateralDistance;
1923 BboxWheel0.ExtentZ = BoxSearchDepthDistance;
1924 FOrientedBox BboxWheel1 = BboxWheel0;
1925 BboxWheel1.Center = WheelPosition1 + FVector(0,0,-TireRadius);
1926 FOrientedBox BboxWheel2 = BboxWheel0;
1927 BboxWheel2.Center = WheelPosition2 + FVector(0,0,-TireRadius);
1928 FOrientedBox BboxWheel3 = BboxWheel0;
1929 BboxWheel3.Center = WheelPosition3 + FVector(0,0,-TireRadius);
1932 DrawOrientedBox(GetWorld(), {BboxWheel0, BboxWheel1, BboxWheel2, BboxWheel3});
1935 std::vector<FParticle*> ParticlesWheel0, ParticlesWheel1, ParticlesWheel2, ParticlesWheel3;
1937 TRACE_CPUPROFILER_EVENT_SCOPE(ParticleSearch);
1938 auto GetAndFilterParticlesInBox =
1939 [&] (FOrientedBox& OBox) -> std::vector<FParticle*>
1942 Particles = SparseMap.GetParticlesInBox(OBox);
1943 LimitParticlesPerWheel(Particles);
1946 auto FutureParticles0 = Async(EAsyncExecution::ThreadPool,
1947 [&]() {
return GetAndFilterParticlesInBox(BboxWheel0);});
1948 auto FutureParticles2 = Async(EAsyncExecution::ThreadPool,
1949 [&]() {
return GetAndFilterParticlesInBox(BboxWheel2);});
1950 auto FutureParticles1 = Async(EAsyncExecution::ThreadPool,
1951 [&]() {
return GetAndFilterParticlesInBox(BboxWheel1);});
1952 auto FutureParticles3 = Async(EAsyncExecution::ThreadPool,
1953 [&]() {
return GetAndFilterParticlesInBox(BboxWheel3);});
1954 ParticlesWheel0 = FutureParticles0.Get();
1955 ParticlesWheel2 = FutureParticles2.Get();
1956 ParticlesWheel1 = FutureParticles1.Get();
1957 ParticlesWheel3 = FutureParticles3.Get();
1960 std::vector<FParticle> BenchParticles;
1963 GenerateBenchmarkParticles(BenchParticles,
1964 ParticlesWheel0, ParticlesWheel1, ParticlesWheel2, ParticlesWheel3,
1965 BboxWheel0, BboxWheel1, BboxWheel2, BboxWheel3);
1966 UE_LOG(LogCarla, Log, TEXT(
"Generated %d particles"), BenchParticles.size());
1971 DrawParticles(GetWorld(), ParticlesWheel0);
1972 DrawParticles(GetWorld(), ParticlesWheel1);
1973 DrawParticles(GetWorld(), ParticlesWheel2);
1974 DrawParticles(GetWorld(), ParticlesWheel3);
1975 DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel0), BboxWheel0.Center.Z);
1976 DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel1), BboxWheel1.Center.Z);
1977 DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel2), BboxWheel2.Center.Z);
1978 DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel3), BboxWheel3.Center.Z);
1981 TArray<float> ParticlePos0, ParticleVel0, ParticlePos1, ParticleVel1,
1982 ParticlePos2, ParticleVel2, ParticlePos3, ParticleVel3;
1983 TArray<float> WheelPos0, WheelOrient0, WheelLinVel0, WheelAngVel0;
1984 TArray<float> WheelPos1, WheelOrient1, WheelLinVel1, WheelAngVel1;
1985 TArray<float> WheelPos2, WheelOrient2, WheelLinVel2, WheelAngVel2;
1986 TArray<float> WheelPos3, WheelOrient3, WheelLinVel3, WheelAngVel3;
1988 TRACE_CPUPROFILER_EVENT_SCOPE(SetUpArrays);
1989 SetUpParticleArrays(ParticlesWheel0, ParticlePos0, ParticleVel0, WheelTransform0);
1990 SetUpParticleArrays(ParticlesWheel1, ParticlePos1, ParticleVel1, WheelTransform1);
1991 SetUpParticleArrays(ParticlesWheel2, ParticlePos2, ParticleVel2, WheelTransform2);
1992 SetUpParticleArrays(ParticlesWheel3, ParticlePos3, ParticleVel3, WheelTransform3);
1994 SetUpWheelArrays(
Vehicle, 0, WheelPos0, WheelOrient0, WheelLinVel0, WheelAngVel0);
1995 SetUpWheelArrays(
Vehicle, 1, WheelPos1, WheelOrient1, WheelLinVel1, WheelAngVel1);
1996 SetUpWheelArrays(
Vehicle, 2, WheelPos2, WheelOrient2, WheelLinVel2, WheelAngVel2);
1997 SetUpWheelArrays(
Vehicle, 3, WheelPos3, WheelOrient3, WheelLinVel3, WheelAngVel3);
2001 static_cast<int>(ParticlesWheel0.size()),
2002 ParticlePos0.GetData(), ParticleVel0.GetData(),
2003 WheelPos0.GetData(), WheelOrient0.GetData(),
2004 WheelLinVel0.GetData(), WheelAngVel0.GetData()};
2006 static_cast<int>(ParticlesWheel1.size()),
2007 ParticlePos1.GetData(), ParticleVel1.GetData(),
2008 WheelPos1.GetData(), WheelOrient1.GetData(),
2009 WheelLinVel1.GetData(), WheelAngVel1.GetData()};
2011 static_cast<int>(ParticlesWheel2.size()),
2012 ParticlePos2.GetData(), ParticleVel2.GetData(),
2013 WheelPos2.GetData(), WheelOrient2.GetData(),
2014 WheelLinVel2.GetData(), WheelAngVel2.GetData()};
2016 static_cast<int>(ParticlesWheel3.size()),
2017 ParticlePos3.GetData(), ParticleVel3.GetData(),
2018 WheelPos3.GetData(), WheelOrient3.GetData(),
2019 WheelLinVel3.GetData(), WheelAngVel3.GetData()};
2022 ASoilTypeManager* SoilTypeManagerActor = Cast<ASoilTypeManager>(UGameplayStatics::GetActorOfClass(GetWorld(), ASoilTypeManager::StaticClass()));
2023 if(SoilTypeManagerActor)
2042 SoilType, NNVerbose};
2045 NNInput.terrain_type = -1;
2049 NNInput.throttle *= -1;
2051 TerramechanicsModel.SetInputs(NNInput);
2053 TRACE_CPUPROFILER_EVENT_SCOPE(RunModel);
2056 TerramechanicsModel.ForwardCUDATensors();
2058 else if(bUseDynamicModel)
2060 TerramechanicsModel.ForwardDynamic();
2064 TerramechanicsModel.Forward();
2069 if(bUpdateParticles)
2072 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
2073 FScopeLock ScopeLock(&SparseMap.Lock_Particles);
2074 auto UpdateFutureParticles =
2075 [&] (std::vector<FParticle*>&
Particles, std::vector<float>& Forces,
float DeltaTime,
2076 const FTransform& WheelTransform)
2078 UpdateParticles( Particles, Forces, DeltaTime, WheelTransform );
2080 UpdateFutureParticles(
2082 UpdateFutureParticles(
2084 UpdateFutureParticles(
2086 UpdateFutureParticles(
2091 FLinearColor
Color(1.0,0.0,1.0,1.0);
2092 DrawParticles(GetWorld(), ParticlesWheel0, Color);
2093 DrawParticles(GetWorld(), ParticlesWheel1, Color);
2094 DrawParticles(GetWorld(), ParticlesWheel2, Color);
2095 DrawParticles(GetWorld(), ParticlesWheel3, Color);
2099 if(bUseMeanAcceleration)
2101 ApplyMeanAccelerationToVehicle(
Vehicle,
2158void UCustomTerrainPhysicsComponent::UpdateParticles(
2159 std::vector<FParticle*> Particles, std::vector<float> Forces,
2160 float DeltaTime,
const FTransform& WheelTransform)
2162 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
2166 for (
size_t i = 0; i <
Particles.size(); i++)
2168 FVector Force = FVector(Forces[3*i + 0], Forces[3*i + 1], Forces[3*i + 2]) * ParticleForceMulFactor;
2169 FVector LocalAcceleration = Force;
2170 FVector UELocalAcceleration =
SIToUEFrame(LocalAcceleration);
2171 FVector UEGlobalAcceleration = WheelTransform.TransformVector(UELocalAcceleration);
2172 FVector Acceleration =
UEFrameToSI(UEGlobalAcceleration);
2180 for (
size_t i = 0; i <
Particles.size(); i++)
2182 FVector Force = FVector(Forces[3*i + 0], Forces[3*i + 1], Forces[3*i + 2]) * ParticleForceMulFactor;
2184 FVector Acceleration = Force;
2191void UCustomTerrainPhysicsComponent::UpdateParticlesDebug( std::vector<FParticle*> Particles)
2193 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
2194 float DeltaTime = GetWorld()->GetDeltaSeconds();
2195 for (
size_t i = 0; i <
Particles.size(); i++)
2197 FVector Force = FVector( 0, 0, FMath::RandRange(-1.0f, 1.0f));
2199 FVector Acceleration = Force;
2205void UCustomTerrainPhysicsComponent::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
2207 if( bRemoveLandscapeColliders )
2209 for(
auto CurrentActor : InLevel->Actors)
2211 if( ALandscape* CurrentLandscape = Cast<ALandscape>( CurrentActor ) )
2213 CurrentLandscape->BodyInstance.ReplaceResponseToChannels( ECollisionResponse::ECR_Block, ECollisionResponse::ECR_Ignore );
2214 CurrentLandscape->BodyInstance.ReplaceResponseToChannels( ECollisionResponse::ECR_Overlap, ECollisionResponse::ECR_Ignore );
2215 CurrentLandscape->BodyInstance.SetCollisionEnabled( ECollisionEnabled::Type::NoCollision,
true);
2217 for(
auto CurrentCollision : CurrentLandscape->CollisionComponents){
2218 CurrentCollision->SetCollisionResponseToAllChannels( ECollisionResponse::ECR_Ignore );
2219 CurrentCollision->SetCollisionEnabled( ECollisionEnabled::Type::NoCollision );
2223 for(
auto CurrentComponent : CurrentLandscape->LandscapeComponents){
2224 CurrentComponent->SetCollisionResponseToAllChannels( ECollisionResponse::ECR_Ignore );
2225 CurrentComponent->SetCollisionEnabled( ECollisionEnabled::Type::NoCollision );
2233void UCustomTerrainPhysicsComponent::UpdateTilesHeightMaps(
2234 const std::vector<FParticle*>& Particles)
2236 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateTilesHeightMaps);
2238 uint32_t PartialHeightMapSize =
2239 SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2240 float InverseTileSize = 1.f/SparseMap.GetTileSize();
2241 float Transformation = InverseTileSize * PartialHeightMapSize;
2242 float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2243 for (
size_t i = 0; i <
Particles.size(); i++)
2246 uint64_t TileId = SparseMap.GetTileId(P->
Position);
2247 FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2250 FIntVector HeightMapCoords = FIntVector(
2251 ParticleLocalPosition.
X * Transformation,
2252 ParticleLocalPosition.
Y * Transformation, 0);
2254 HeightMapCoords.X = std::min( std::max( HeightMapCoords.X, 0) ,
static_cast<int>(PartialHeightMapSize-1));
2255 HeightMapCoords.Y = std::min( std::max( HeightMapCoords.Y, 0) ,
static_cast<int>(PartialHeightMapSize-1));
2256 uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2263void UCustomTerrainPhysicsComponent::RemoveParticlesFromOrderedContainer(
2264 const std::vector<FParticle*>& Particles)
2266 TRACE_CPUPROFILER_EVENT_SCOPE(RemoveParticlesFromOrderedContainer);
2268 uint32_t PartialHeightMapSize =
2269 SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2270 float InverseTileSize = 1.f/SparseMap.GetTileSize();
2271 float Transformation = InverseTileSize * PartialHeightMapSize;
2272 float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2273 for (
size_t i = 0; i <
Particles.size(); i++)
2276 uint64_t TileId = SparseMap.GetTileId(P->
Position);
2277 FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2281 FIntVector HeightMapCoords = FIntVector(
2282 ParticleLocalPosition.
X * Transformation,
2283 ParticleLocalPosition.
Y * Transformation, 0);
2285 HeightMapCoords.X = std::min( std::max( HeightMapCoords.X, 0) ,
static_cast<int>(PartialHeightMapSize-1));
2286 HeightMapCoords.Y = std::min( std::max( HeightMapCoords.Y, 0) ,
static_cast<int>(PartialHeightMapSize-1));
2288 uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2306 UE_LOG(LogCarla, Error, TEXT(
"Cannot Remove more from %d, currentsize %d Tile : %s"), Index,CurrentTile.
ParticlesZOrdered[Index].size(), *(TilePosition.
ToString()) );
2311 UE_LOG(LogCarla, Error, TEXT(
"RemoveParticlesFromOrderedContainer Invalid Index %d ZOrderedSize %d Tile: %s"), Index,CurrentTile.
ParticlesZOrdered.size(), *(TilePosition.
ToString()) );
2316void UCustomTerrainPhysicsComponent::AddParticlesToOrderedContainer(
2317 const std::vector<FParticle*>& Particles)
2319 TRACE_CPUPROFILER_EVENT_SCOPE(AddParticlesToOrderedContainer);
2321 uint32_t PartialHeightMapSize =
2322 SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2323 float InverseTileSize = 1.f/SparseMap.GetTileSize();
2324 float Transformation = InverseTileSize * PartialHeightMapSize;
2325 float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2326 for (
size_t i = 0; i <
Particles.size(); i++)
2329 uint64_t TileId = SparseMap.GetTileId(P->
Position);
2330 FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2334 FIntVector HeightMapCoords = FIntVector(
2335 std::floor(ParticleLocalPosition.
X * Transformation),
2336 std::floor(ParticleLocalPosition.
Y * Transformation), 0);
2339 uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2348 UE_LOG(LogCarla, Error, TEXT(
"RemoveParticlesFromOrderedContainer Invalid Index %d ZOrderedSize %d Tile: %s"), Index,CurrentTile.
ParticlesZOrdered.size(), *(TilePosition.
ToString()) );
2354void UCustomTerrainPhysicsComponent::FlagTilesToRedoOrderedContainer(
2355 const std::vector<FParticle*>& Particles)
2357 TRACE_CPUPROFILER_EVENT_SCOPE(AddParticlesToOrderedContainer);
2359 uint32_t PartialHeightMapSize =
2360 SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2361 float InverseTileSize = 1.f/SparseMap.GetTileSize();
2362 float Transformation = InverseTileSize * PartialHeightMapSize;
2363 float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2364 for (
size_t i = 0; i <
Particles.size(); i++)
2367 uint64_t TileId = SparseMap.GetTileId(P->
Position);
2368 FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2375void UCustomTerrainPhysicsComponent::UpdateTilesHeightMapsInRadius(
FDVector Position, uint32 Rad )
2377 TRACE_CPUPROFILER_EVENT_SCOPE(UpdateTilesHeightMapsInRadius);
2380 uint32_t Tile_X = (uint32_t)(TileId >> 32);
2381 uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
2382 uint32_t RadiusInTiles = (Rad/TileSize);
2385 uint32_t MinX = Tile_X - RadiusInTiles;
2386 uint32_t MinY = Tile_Y - RadiusInTiles;
2387 uint32_t MaxX = Tile_X + RadiusInTiles;
2388 uint32_t MaxY = Tile_Y + RadiusInTiles;
2390 for( uint32_t X = MinX; X <= MaxX; ++X )
2392 for( uint32_t Y = MinY; Y <= MaxY; ++Y )
2394 uint64_t CurrentTileId = SparseMap.GetTileId(X,Y);
2395 if( SparseMap.Map.count(CurrentTileId) )
2397 SparseMap.GetTile(X, Y).UpdateLocalHeightmap();
2403void UCustomTerrainPhysicsComponent::AddForceToSingleWheel( USkeletalMeshComponent* SkeletalMeshComponent, FVector WheelPosition, FVector WheelNormalForce )
2405 FVector WheelBottomLocation = WheelPosition - FVector(0,0, 0.337);
2406 float OriginalHeight = SparseMap.GetHeight(WheelPosition);
2407 float NewFloorHeight = OriginalHeight -
UEFrameToSI(TerrainDepth);
2409 if( WheelNormalForce.Size() == 0 ){
2410 WheelNormalForce = FVector::UpVector;
2413 float ForceFactor = ( WheelBottomLocation.Z - OriginalHeight ) / ( NewFloorHeight - OriginalHeight );
2414 if( ForceFactor < 0){
2418 SkeletalMeshComponent->AddForceAtLocationLocal(WheelPosition,
SIToUEFrame(WheelNormalForce) * ( ForceFactor * NormalForceIntensity) );
2421void UCustomTerrainPhysicsComponent::ApplyForcesToVehicle(
2423 FVector ForceWheel0, FVector ForceWheel1, FVector ForceWheel2, FVector ForceWheel3,
2424 FVector TorqueWheel0, FVector TorqueWheel1, FVector TorqueWheel2, FVector TorqueWheel3)
2426 TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::ApplyForcesToVehicle);
2428 FTransform VehicleTransform =
Vehicle->GetTransform();
2429 FVector WheelPosition0 = VehicleTransform.TransformPosition(FVector(140, -70, 40));
2430 FVector WheelPosition1 = VehicleTransform.TransformPosition(FVector(140, 70, 40));
2431 FVector WheelPosition2 = VehicleTransform.TransformPosition(FVector(-140, -70, 40));
2432 FVector WheelPosition3 = VehicleTransform.TransformPosition(FVector(-140, 70, 40));
2433 UPrimitiveComponent* PrimitiveComponent =
2434 Cast<UPrimitiveComponent>(
Vehicle->GetRootComponent());
2435 if(!PrimitiveComponent)
2437 UE_LOG(LogCarla, Error, TEXT(
"ApplyForcesToVehicle Vehicle does not contain UPrimitiveComponent"));
2440 if(bDisableVehicleGravity && PrimitiveComponent->IsGravityEnabled())
2442 PrimitiveComponent->SetEnableGravity(
false);
2446 ForceWheel0 = VehicleTransform.TransformVector(ForceWheel0);
2447 ForceWheel1 = VehicleTransform.TransformVector(ForceWheel1);
2448 ForceWheel2 = VehicleTransform.TransformVector(ForceWheel2);
2449 ForceWheel3 = VehicleTransform.TransformVector(ForceWheel3);
2451 ForceWheel0 = ForceWheel0.GetClampedToMaxSize(MaxForceMagnitude);
2452 ForceWheel1 = ForceWheel1.GetClampedToMaxSize(MaxForceMagnitude);
2453 ForceWheel2 = ForceWheel2.GetClampedToMaxSize(MaxForceMagnitude);
2454 ForceWheel3 = ForceWheel3.GetClampedToMaxSize(MaxForceMagnitude);
2458 PrimitiveComponent->AddImpulseAtLocation(ForceWheel0, WheelPosition0);
2459 PrimitiveComponent->AddImpulseAtLocation(ForceWheel1, WheelPosition1);
2460 PrimitiveComponent->AddImpulseAtLocation(ForceWheel2, WheelPosition2);
2461 PrimitiveComponent->AddImpulseAtLocation(ForceWheel3, WheelPosition3);
2465 PrimitiveComponent->AddForceAtLocationLocal(ForceWheel0, FVector(140, -70, 40));
2466 PrimitiveComponent->AddForceAtLocationLocal(ForceWheel1, FVector(140, 70, 40));
2467 PrimitiveComponent->AddForceAtLocationLocal(ForceWheel2, FVector(-140, -70, 40));
2468 PrimitiveComponent->AddForceAtLocationLocal(ForceWheel3, FVector(-140, 70, 40));
2471 PrimitiveComponent->AddTorqueInRadians(TorqueWheel0);
2472 PrimitiveComponent->AddTorqueInRadians(TorqueWheel1);
2473 PrimitiveComponent->AddTorqueInRadians(TorqueWheel2);
2474 PrimitiveComponent->AddTorqueInRadians(TorqueWheel3);
2475 if (DrawDebugInfo && bShowForces)
2477 float LifeTime = 0.3f;
2478 bool bPersistentLines =
false;
2479 bool bDepthIsForeground = (0 == SDPG_Foreground);
2480 UWorld * World = GetWorld();
2481 ULineBatchComponent* LineBatcher =
2482 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
2483 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
2486 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
2488 LineBatcher->DrawLine(WheelPosition0 + FVector(0,0,50),
2489 WheelPosition0 + FVector(0,0,50)+ ForceWheel0.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel0.Size()),
2490 FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2491 LineBatcher->DrawLine(WheelPosition1 + FVector(0,0,50),
2492 WheelPosition1 + FVector(0,0,50)+ ForceWheel1.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel1.Size()),
2493 FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2494 LineBatcher->DrawLine(WheelPosition2 + FVector(0,0,50),
2495 WheelPosition2 + FVector(0,0,50)+ ForceWheel2.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel2.Size()),
2496 FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2497 LineBatcher->DrawLine(WheelPosition3 + FVector(0,0,50),
2498 WheelPosition3 + FVector(0,0,50)+ ForceWheel3.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel3.Size()),
2499 FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2503void UCustomTerrainPhysicsComponent::ApplyMeanAccelerationToVehicle(
2505 FVector ForceWheel0, FVector ForceWheel1, FVector ForceWheel2, FVector ForceWheel3)
2507 TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::ApplyForcesToVehicle);
2508 FVector MeanAcceleration = (ForceWheel0 + ForceWheel1 + ForceWheel2 + ForceWheel3)/4.f;
2509 UPrimitiveComponent* PrimitiveComponent =
2510 Cast<UPrimitiveComponent>(
Vehicle->GetRootComponent());
2511 if (!PrimitiveComponent)
2513 UE_LOG(LogCarla, Error, TEXT(
"ApplyMeanAccelerationToVehicle Vehicle does not contain UPrimitiveComponent"));
2516 if(bDisableVehicleGravity && PrimitiveComponent->IsGravityEnabled())
2518 PrimitiveComponent->SetEnableGravity(
false);
2522 FTransform VehicleTransform =
Vehicle->GetTransform();
2523 MeanAcceleration = VehicleTransform.TransformVector(MeanAcceleration);
2525 PrimitiveComponent->AddForce(MeanAcceleration, FName(
""),
true);
2527 if (DrawDebugInfo && bShowForces)
2529 float LifeTime = 0.3f;
2530 bool bPersistentLines =
false;
2531 bool bDepthIsForeground = (0 == SDPG_Foreground);
2532 UWorld * World = GetWorld();
2533 ULineBatchComponent* LineBatcher =
2534 (World ? World->GetLineBatcher(bDepthIsForeground ? UWorld::ELineBatcherType::Foreground :
2535 (( bPersistentLines || (LifeTime > 0.f) ) ? UWorld::ELineBatcherType::WorldPersistent : UWorld::ELineBatcherType::World)) : nullptr);
2538 UE_LOG(LogCarla, Error, TEXT(
"Missing linebatcher"));
2540 LineBatcher->DrawLine(PrimitiveComponent->GetComponentLocation() + FVector(0,0,200),
2541 PrimitiveComponent->GetComponentLocation() + FVector(0,0,200)+ MeanAcceleration.GetSafeNormal()*(1 + MeanAcceleration.Size()),
2542 FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2546TArray<FVector> UCustomTerrainPhysicsComponent::GetParticlesInRadius(FVector
Position,
float InRadius)
2549 TArray<FVector> ParticlePositions;
2552 ParticlePositions.Add(
SIToUEFrame(Particle->Position.ToFVector()));
2554 return ParticlePositions;
2557TArray<FVector> UCustomTerrainPhysicsComponent::GetParticlesInTileRadius(FVector
Position,
float InRadius)
2560 TArray<FVector> ParticlePositions;
2563 ParticlePositions.Add(
SIToUEFrame(Particle->Position.ToFVector()));
2565 return ParticlePositions;
2569FVector UCustomTerrainPhysicsComponent::GetTileCenter(FVector
Position)
2572 SparseMap.GetTilePosition(
2573 SparseMap.GetTileId(
2577void UCustomTerrainPhysicsComponent::SetUpParticleArrays(std::vector<FParticle*>& ParticlesIn,
2578 TArray<float>& ParticlePosOut,
2579 TArray<float>& ParticleVelOut,
2580 const FTransform &WheelTransform)
2582 ParticlePosOut.Empty();
2583 ParticleVelOut.Empty();
2584 ParticlePosOut.Reserve(ParticlesIn.size()*3);
2585 ParticleVelOut.Reserve(ParticlesIn.size()*3);
2588 const FTransform InverseTransform = WheelTransform.Inverse();
2591 FVector UEPosition =
SIToUEFrame(Particle->Position.ToFVector());
2592 FVector UELocalPosition = InverseTransform.TransformPosition(UEPosition);
2594 ParticlePosOut.Add(
static_cast<float>(
Position.X));
2595 ParticlePosOut.Add(
static_cast<float>(
Position.Y));
2596 ParticlePosOut.Add(
static_cast<float>(
Position.Z));
2597 ParticleVelOut.Add(Particle->Velocity.X);
2598 ParticleVelOut.Add(Particle->Velocity.Y);
2599 ParticleVelOut.Add(Particle->Velocity.Z);
2601 if(ParticlesIn.size() < MaxParticlesPerWheel)
2603 for (
int i = 0; i < (MaxParticlesPerWheel - ParticlesIn.size()); ++i)
2605 ParticlePosOut.Add(0.f);
2606 ParticlePosOut.Add(0.f);
2607 ParticlePosOut.Add(0.f);
2608 ParticleVelOut.Add(0.f);
2609 ParticleVelOut.Add(0.f);
2610 ParticleVelOut.Add(0.f);
2618 ParticlePosOut.Add(
static_cast<float>(Particle->Position.X));
2619 ParticlePosOut.Add(
static_cast<float>(Particle->Position.Y));
2620 ParticlePosOut.Add(
static_cast<float>(Particle->Position.Z));
2621 ParticleVelOut.Add(Particle->Velocity.X);
2622 ParticleVelOut.Add(Particle->Velocity.Y);
2623 ParticleVelOut.Add(Particle->Velocity.Z);
2625 if(ParticlesIn.size() < MaxParticlesPerWheel)
2627 FVector WheelPosition =
UEFrameToSI(WheelTransform.GetLocation());
2628 for (
int i = 0; i < (MaxParticlesPerWheel - ParticlesIn.size()); ++i)
2630 ParticlePosOut.Add(WheelPosition.X);
2631 ParticlePosOut.Add(WheelPosition.Y);
2632 ParticlePosOut.Add(WheelPosition.Z);
2633 ParticleVelOut.Add(0.f);
2634 ParticleVelOut.Add(0.f);
2635 ParticleVelOut.Add(0.f);
2642 TArray<float>& WheelPos,
2643 TArray<float>& WheelOrientation,
2644 TArray<float>& WheelLinearVelocity,
2645 TArray<float>& WheelAngularVelocity)
2647 FTransform VehicleTransform =
Vehicle->GetTransform();
2666 FVector PhysAngularVelocity =
Vehicle->GetMesh()->GetPhysicsAngularVelocityInRadians();
2670 FTransform InverseTransform = VehicleTransform.Inverse();
2673 InverseTransform.TransformVector(
Vehicle->GetVelocity()));
2681 WheelOrientation = {1.f, 0.f, 0.f, 0.f};
2682 WheelLinearVelocity =
2688 FVector LocalAngularVelocity = InverseTransform.TransformVector(PhysAngularVelocity);
2690 float ForwardSpeed = Velocity.X;
2691 float AngularSpeed = (ForwardSpeed/(
CMToM*TireRadius));
2692 WheelAngularVelocity =
2694 (float)(LocalAngularVelocity.X),
2695 (float)(AngularSpeed + LocalAngularVelocity.Y),
2696 (float)(-LocalAngularVelocity.Z)
2707 float ForwardSpeed = FVector::DotProduct(
2708 Vehicle->GetVelocity(),VehicleTransform.GetRotation().GetForwardVector());
2716 FQuat Quat = VehicleTransform.GetRotation();
2726 WheelLinearVelocity =
2732 float AngularSpeed = (ForwardSpeed)/(TireRadius);
2733 FVector GlobalAngulaSpeed = VehicleTransform.TransformVector(FVector(0, AngularSpeed, 0));
2734 PhysAngularVelocity = PhysAngularVelocity + GlobalAngulaSpeed;
2735 WheelAngularVelocity =
2737 (float)PhysAngularVelocity.X,
2738 (
float)PhysAngularVelocity.Y,
2739 (float)-PhysAngularVelocity.Z
2745void UCustomTerrainPhysicsComponent::AddForces(
2746 const TArray<FForceAtLocation> &Forces)
2750 ForcesToApply.Add(Force);
2754void UCustomTerrainPhysicsComponent::ApplyForces()
2758 RootComponent->AddForceAtLocationLocal(Force.Force, Force.Location);
2760 ForcesToApply.Empty();
2763void UCustomTerrainPhysicsComponent::UpdateMaps(
2764 FVector
Position,
float RadiusX,
float RadiusY,
float CacheRadiusX,
float CacheRadiusY)
2786 FDateTime CacheCurrentTime = FDateTime::Now();
2787 FDateTime LoadTilesCurrentTime = FDateTime::Now();
2788 FDateTime UnloadTilesCurrentTime = FDateTime::Now();
void ReadFVector(std::istream &InFile, FVector &OutObj)
static TAutoConsoleVariable< int32 > CVarAsyncHeightmapLoad(TEXT("carla.Terrain.AsyncHeightmapLoad"), 1, TEXT("legacy synchronous path (for rollback/debugging)."), ECVF_Default)
static std::string CachePath
FVector UEFrameToSI(const FVector &In)
const int CacheExtraRadius
FVector SIToUEFrame(const FVector &In)
FVector UEFrameToSIDirection(const FVector &In)
FVector SIToUEFrameDirection(const FVector &In)
Base class for CARLA wheeled vehicles.
FSoilTerramechanicsProperties GetTerrainPropertiesAtGlobalLocation(FVector VehicleLocation)
A view over an actor and its properties.
const FActorInfo * GetActorInfo() const
FCriticalSection Lock_GetTile
FIntVector GetVectorTileId(FDVector Position)
FDenseTile & GetTile(uint32_t Tile_X, uint32_t Tile_Y)
FDenseTile & InitializeRegionInCache(uint64_t TileId)
FDenseTile & InitializeRegion(uint32_t Tile_X, uint32_t Tile_Y)
std::vector< FParticle * > GetParticlesInTileRadius(FDVector Position, float Radius)
FCriticalSection Lock_CacheMap
void InitializeMap(UHeightMapDataAsset *DataAsset, FDVector Origin, FDVector MapSize, float Size, float ScaleZ)
FCriticalSection Lock_Map
std::vector< uint64_t > GetIntersectingTiles(const FOrientedBox &OBox)
void UpdateMaps(FDVector Position, float RadiusX, float RadiusY, float CacheRadiusX, float CacheRadiusY)
std::vector< uint64_t > GetLoadedTilesInRange(FDVector Position, float Radius)
std::unordered_map< uint64_t, FDenseTile > CacheMap
FDVector GetTilePosition(uint64_t TileId)
std::vector< FParticle * > GetParticlesInBox(const FOrientedBox &OBox)
uint64_t GetTileId(uint32_t Tile_X, uint32_t Tile_Y)
void Update(FVector Position, float RadiusX, float RadiusY)
std::vector< FParticle * > GetParticlesInRadius(FDVector Position, float Radius)
void UpdateHeightMap(UHeightMapDataAsset *DataAsset, FDVector Origin, FDVector MapSize, float Size, float ScaleZ)
std::unordered_map< uint64_t, FDenseTile > Map
static bool ActorAttributeToBool(const FActorAttribute &ActorAttribute, bool Default)
============================================================================
FCarlaActor * FindCarlaActor(FCarlaActor::IdType ActorId)
Find a Carla actor by id.
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
static UCarlaEpisode * GetCurrentEpisode(const UObject *WorldContextObject)
TArray< float > HeightValues
sensor::data::Color Color
std::vector< cg::Location > Path
bg::model::d2::point_xy< double > Point
An actor attribute, may be an intrinsic (non-modifiable) attribute of the actor or an user-defined ac...
A description of a Carla Actor with all its variation.
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
A view over an actor and its properties.
FActorDescription Description
void GetParticlesInBox(const FOrientedBox &OBox, std::vector< FParticle * > &ParticlesInRadius)
std::vector< float > ParticlesHeightMap
bool bParticlesZOrderedInitialized
std::vector< std::multiset< float, std::greater< float > > > ParticlesZOrdered
std::vector< FParticle > Particles
void InitializeDataStructure()
void UpdateLocalHeightmap()
void InitializeTile(uint32_t TextureSize, float AffectedRadius, float ParticleSize, float Depth, FDVector TileOrigin, FDVector TileEnd, const FString &SavePath, const FHeightMapData &HeightMap)
void GetAllParticles(std::vector< FParticle * > &ParticlesInRadius)
std::vector< FParticle * > GetParticlesInRadius(FDVector Position, float Radius)
uint32_t PartialHeightMapSize
FDenseTile & operator=(FDenseTile &&Origin)
bool bHeightmapNeedToUpdate
float GetHeight(FDVector Position) const
void InitializeHeightmap(UHeightMapDataAsset *DataAsset, FDVector Size, FDVector Origin, FDVector Tile0, float ScaleZ)
std::vector< float > Pixels
TEnumAsByte< ESoilTerramechanicsType > TerrainType
virtual ~FTilesWorker() override
class UCustomTerrainPhysicsComponent * CustomTerrainComp
virtual uint32 Run() override
FTilesWorker(class UCustomTerrainPhysicsComponent *TerrainComp, FVector NewPosition, float NewRadiusX, float NewRadiusY)
volatile bool bShouldContinue
std::vector< float > _particle_forces