CARLA
CustomTerrainPhysicsComponent.cpp
Go to the documentation of this file.
1 // Copyright (c) 2022 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #undef CreateDirectory
8 
10 #include "Runtime/Core/Public/Async/ParallelFor.h"
11 #include "Engine/CollisionProfile.h"
12 #include "Engine/StaticMeshActor.h"
13 #include "StaticMeshResources.h"
14 #include "CollisionQueryParams.h"
19 
20 #include "HAL/PlatformFilemanager.h"
21 #include "HAL/RunnableThread.h"
22 #include "Misc/Paths.h"
23 #include "Engine/World.h"
24 #include "Math/UnrealMathUtility.h"
25 #include "Engine/World.h"
26 #include "Landscape.h"
27 #include "LandscapeHeightfieldCollisionComponent.h"
28 #include "LandscapeComponent.h"
29 
30 #include "RHICommandList.h"
31 #include "TextureResource.h"
32 #include "Rendering/Texture2DResource.h"
33 #include "GenericPlatform/GenericPlatformProcess.h"
34 #include "Materials/MaterialParameterCollection.h"
35 #include "Materials/MaterialParameterCollectionInstance.h"
36 #include "Materials/MaterialInterface.h"
37 #include "Materials/MaterialInstance.h"
38 // #include <carla/pytorch/pytorch.h>
39 
40 #include "Components/SkinnedMeshComponent.h"
41 #include "GenericPlatform/GenericPlatformFile.h"
42 #include "Async/Async.h"
43 #include "Async/Future.h"
44 #include "LandscapeProxy.h"
45 
46 
48 #include "HAL/PlatformFilemanager.h"
49 #include "HAL/RunnableThread.h"
50 #include "Misc/Paths.h"
51 #include "Engine/World.h"
52 #include "Math/UnrealMathUtility.h"
53 #include "GenericPlatform/GenericPlatformFile.h"
54 #include "Engine/Texture2D.h"
55 #include "Engine/Texture.h"
56 #include "Rendering/Texture2DResource.h"
57 #include "Engine/TextureRenderTarget2D.h"
58 #include "Components/PrimitiveComponent.h"
59 #include "DrawDebugHelpers.h"
60 #include "Kismet/KismetSystemLibrary.h"
61 #include "CommandLine.h"
62 #include "Components/LineBatchComponent.h"
63 #include "Math/OrientedBox.h"
64 #include "Misc/DateTime.h"
65 #include "EngineUtils.h"
66 #include <algorithm>
67 #include <fstream>
68 
69 #include <thread>
70 #include <chrono>
71 
73 #include "carla/rpc/String.h"
75 
76 
77 constexpr float MToCM = 100.f;
78 constexpr float CMToM = 0.01f;
79 
80 const int CacheExtraRadius = 10;
81 
82 #ifdef _WIN32
83  std::string _filesBaseFolder = std::string(getenv("USERPROFILE")) + "/carlaCache/";
84 #else
85  std::string _filesBaseFolder = std::string(getenv("HOME")) + "/carlaCache/";
86 #endif
87 
88 FVector SIToUEFrame(const FVector& In)
89 {
90  return MToCM * FVector(In.X, -In.Y, In.Z);
91 }
92 float SIToUEFrame(const float& In) { return MToCM * In; }
93 FVector SIToUEFrameDirection(const FVector& In)
94 {
95  return FVector(In.X, -In.Y, In.Z);
96 }
97 
98 FVector UEFrameToSI(const FVector& In)
99 {
100  return CMToM*FVector(In.X, -In.Y, In.Z);
101 }
102 float UEFrameToSI(const float& In) { return CMToM * In; }
103 FVector UEFrameToSIDirection(const FVector& In)
104 {
105  return FVector(In.X, -In.Y, In.Z);
106 }
107 
109  UHeightMapDataAsset* DataAsset, FDVector Size, FDVector Origin,
110  FDVector Tile0, float ScaleZ)
111 {
112  Tile0Position = Tile0;
113  WorldSize = Size;
114  Offset = Origin;
115  Size_X = DataAsset->SizeX;
116  Size_Y = DataAsset->SizeY;
117  // Pixels = DataAsset->HeightValues;
118  Pixels.clear();
119  Pixels.reserve(DataAsset->HeightValues.Num());
120  for (float Height : DataAsset->HeightValues)
121  {
122  Pixels.emplace_back(UEFrameToSI(Height));
123  }
124 }
125 
127 {
128  Position = Position - Tile0Position;
129  uint32_t Coord_X = (Position.X / WorldSize.X) * Size_X;
130  uint32_t Coord_Y = (1.f - Position.Y / WorldSize.Y) * Size_Y;
131  Coord_X = std::min(Coord_X, Size_X-1);
132  Coord_Y = std::min(Coord_Y, Size_Y-1);
133  return Pixels[Coord_X*Size_Y + Coord_Y];
134 }
135 
137 {
138  Pixels.clear();
139 }
140 
142  Particles.clear();
143  ParticlesHeightMap.clear();
144  TilePosition = FDVector(0.0,0.0,0.0);
145  SavePath = FString("NotValidPath");
146  bHeightmapNeedToUpdate = false;
147 }
148 
150  Particles.clear();
151  ParticlesHeightMap.clear();
152  ParticlesZOrdered.clear();
153  TilePosition = FDVector(0.0,0.0,0.0);
154  SavePath = FString("NotValidPath");
155  bHeightmapNeedToUpdate = false;
156 }
157 
159  TilePosition = Origin.TilePosition;
160  SavePath = Origin.SavePath;
161  bHeightmapNeedToUpdate = false;
162  Particles = Origin.Particles;
163  ParticlesHeightMap = Origin.ParticlesHeightMap;
164  ParticlesZOrdered = Origin.ParticlesZOrdered;
165 }
166 
168  TilePosition = Origin.TilePosition;
169  SavePath = Origin.SavePath;
170  bHeightmapNeedToUpdate = false;
171  Particles = std::move(Origin.Particles);
172  ParticlesHeightMap = std::move(Origin.ParticlesHeightMap);
173  ParticlesZOrdered = std::move(Origin.ParticlesZOrdered);
174 }
175 
177 {
178  TilePosition = Origin.TilePosition;
179  SavePath = Origin.SavePath;
180  bHeightmapNeedToUpdate = false;
181  Particles = std::move(Origin.Particles);
182  ParticlesHeightMap = std::move(Origin.ParticlesHeightMap);
183  ParticlesZOrdered = std::move(Origin.ParticlesZOrdered);
184  return *this;
185  }
186 
187 void FDenseTile::InitializeTile(uint32_t TextureSize, float AffectedRadius, float ParticleSize, float Depth,
188  FDVector TileOrigin, FDVector TileEnd,
189  const FString& SavePath, const FHeightMapData &HeightMap)
190 {
191 
192  TileSize = (TileEnd.X - TileOrigin.X );
193  PartialHeightMapSize = TileSize * TextureSize / (2*AffectedRadius);
194  std::string FileName = std::string(TCHAR_TO_UTF8(*( SavePath + TileOrigin.ToString() + ".tile" ) ) );
195 
196  //UE_LOG(LogCarla, Log, TEXT("Tile origin %s"), *TileOrigin.ToString() );
197  if( FPaths::FileExists(FString(FileName.c_str())) )
198  {
199 
200  TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::Read);
201  std::ifstream ReadStream(FileName);
202  FVector VectorToRead;
203  ReadFVector(ReadStream, VectorToRead );
204  TilePosition = FDVector(VectorToRead);
205  ReadStdVector<FParticle> (ReadStream, Particles);
206  //UE_LOG(LogCarla, Log, TEXT("Reading data, got %d particles"), Particles.size());
207  }
208  else
209  {
210  TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::Create);
211 
212  TilePosition = TileOrigin;
213  uint32_t NumParticles_X = (TileEnd.X - TileOrigin.X) / ParticleSize;
214  uint32_t NumParticles_Y = FMath::Abs(TileEnd.Y - TileOrigin.Y) / ParticleSize;
215  uint32_t NumParticles_Z = (Depth) / ParticleSize;
216  Particles = std::vector<FParticle>(NumParticles_X*NumParticles_Y*NumParticles_Z);
217 
218  //UE_LOG(LogCarla, Log, TEXT("Initializing Tile with (%d,%d,%d) particles at location %s, size %f, depth %f, HeightMap at tile origin %f"),
219  // NumParticles_X,NumParticles_Y,NumParticles_Z, *TileOrigin.ToString(), ParticleSize, Depth, HeightMap.GetHeight(TileOrigin) );
220 
221  for(uint32_t i = 0; i < NumParticles_X; i++)
222  {
223  for(uint32_t j = 0; j < NumParticles_Y; j++)
224  {
225  FDVector ParticleLocalPosition = FDVector(i*ParticleSize, j*ParticleSize, 0.0f);
226  FDVector ParticlePosition = TileOrigin + ParticleLocalPosition;
227  float Height = HeightMap.GetHeight(ParticlePosition);
228  for(uint32_t k = 0; k < NumParticles_Z; k++)
229  {
230  ParticlePosition.Z = TileOrigin.Z + Height - k*ParticleSize;
231  Particles[k*NumParticles_X*NumParticles_Y + j*NumParticles_X + i] =
232  {ParticlePosition, FVector(0), ParticleSize/2.f};
233  }
234  }
235  }
236 
237  //UE_LOG(LogCarla, Log, TEXT("Building local heightMap of %d pixels"), PartialHeightMapSize);
238 
239  }
240  ParticlesZOrdered.resize( PartialHeightMapSize*PartialHeightMapSize );
241 
242  for(float& Height : ParticlesHeightMap)
243  {
244  Height = 0;
245  }
246 
247  bParticlesZOrderedInitialized = false;
248  bHeightmapNeedToUpdate = true;
249 }
250 
252 {
253  {
254  TRACE_CPUPROFILER_EVENT_SCOPE(DenseTile::InitializeTile::ParticlesZOrdered);
255  ParticlesHeightMap.clear();
256  ParticlesHeightMap.resize( PartialHeightMapSize*PartialHeightMapSize );
257  float InverseTileSize = 1.f/TileSize;
258  float Transformation = InverseTileSize * PartialHeightMapSize;
259 
260  for (size_t i = 0; i < Particles.size(); i++)
261  {
262  const FParticle& P = Particles[i];
263  FDVector ParticleLocalPosition = P.Position - TilePosition;
264  // Recalculate position to get it into heightmap coords
265  FIntVector HeightMapCoords = FIntVector(
266  ParticleLocalPosition.X * Transformation,
267  ParticleLocalPosition.Y * Transformation, 0);
268 
269  uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
270  // Compare to the current value, if higher replace
271  if(Index < ParticlesZOrdered.size() ){
272  ParticlesZOrdered[Index].insert(P.Position.Z);
273  }
274  }
275 
276  }
277  bParticlesZOrderedInitialized = true;
278  bHeightmapNeedToUpdate = true;
279 }
280 
281 // revise coordinates
282 void FDenseTile::GetParticlesInRadius(FDVector Position, float Radius, std::vector<FParticle*> &ParticlesInRadius)
283 {
284  TRACE_CPUPROFILER_EVENT_SCOPE(FDenseTile::GetParticlesInRadius);
285  for (FParticle& particle : Particles)
286  {
287  if((particle.Position - Position).SizeSquared() < Radius*Radius)
288  {
289  ParticlesInRadius.emplace_back(&particle);
290  }
291  }
292 }
293 // revise coordinates
294 std::vector<FParticle*> FDenseTile::GetParticlesInRadius(FDVector Position, float Radius)
295 {
296  TRACE_CPUPROFILER_EVENT_SCOPE(FDenseTile::GetParticlesInRadius);
297  std::vector<FParticle*> ParticlesInRadius;
298  for (FParticle& particle : Particles)
299  {
300  if((particle.Position - Position).SizeSquared() < Radius*Radius)
301  {
302  ParticlesInRadius.emplace_back(&particle);
303  }
304  }
305  return ParticlesInRadius;
306 }
307 
309  const FOrientedBox& OBox, std::vector<FParticle*> &ParticlesInRadius)
310 {
311  TRACE_CPUPROFILER_EVENT_SCOPE(FDenseTile::GetParticlesInBox);
312  for (FParticle& Particle : Particles)
313  {
314  FVector PToCenter = SIToUEFrame(Particle.Position.ToFVector()) - OBox.Center;
315  if((FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisX)) < OBox.ExtentX) &&
316  (FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisY)) < OBox.ExtentY) &&
317  (FMath::Abs(FVector::DotProduct(PToCenter, OBox.AxisZ)) < OBox.ExtentZ))
318  {
319  ParticlesInRadius.emplace_back(&Particle);
320  }
321  }
322 }
323 
324 void FDenseTile::GetAllParticles(std::vector<FParticle*> &ParticlesInRadius)
325 {
326  for (FParticle& Particle : Particles)
327  {
328  ParticlesInRadius.emplace_back(&Particle);
329  }
330 }
331 
333 {
334  if( bHeightmapNeedToUpdate && bParticlesZOrderedInitialized ){
335  TRACE_CPUPROFILER_EVENT_SCOPE(FDenseTile::UpdateLocalHeightmap);
336  for( uint32_t i = 0; i < ParticlesHeightMap.size() ; ++i ){
337  if( ParticlesZOrdered.size() == ParticlesHeightMap.size() ){
338  float Value = * ( ParticlesZOrdered[i].begin() );
339  ParticlesHeightMap[i] = Value;
340  }
341  }
342  bHeightmapNeedToUpdate = false;
343  }
344 
345 }
346 
347 // revise coordinates
348 std::vector<FParticle*> FSparseHighDetailMap::
350 {
351  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetParticlesInRadius);
352 
353  uint64_t TileId = GetTileId(Position);
354  uint32_t Tile_X = (uint32_t)(TileId >> 32);
355  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
356 
357  // FDenseTile& Tile = GetTile(TileId);
358  // return Tile.GetParticlesInRadius(Position, Radius);
359  std::vector<FParticle*> ParticlesInRadius;
360 
361  GetTile(Tile_X-1, Tile_Y-1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
362  GetTile(Tile_X, Tile_Y-1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
363  GetTile(Tile_X+1, Tile_Y-1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
364  GetTile(Tile_X-1, Tile_Y).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
365  GetTile(Tile_X, Tile_Y).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
366  GetTile(Tile_X+1, Tile_Y).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
367  GetTile(Tile_X-1, Tile_Y+1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
368  GetTile(Tile_X, Tile_Y+1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
369  GetTile(Tile_X+1, Tile_Y+1).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
370 
371  return ParticlesInRadius;
372 }
373 
374 std::vector<FParticle*> FSparseHighDetailMap::
376 {
377  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetParticlesInRadius);
378 
379  uint64_t TileId = GetTileId(Position);
380  uint32_t Tile_X = (uint32_t)(TileId >> 32);
381  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
382 
383  uint32_t RadiusInTiles = (Radius/TileSize);
384  uint32_t MinX,MinY,MaxX,MaxY = 0;
385 
386  if( Tile_X < RadiusInTiles){
387  MinX = 0;
388  }else{
389  MinX = Tile_X - RadiusInTiles;
390  }
391 
392  if( Tile_Y < RadiusInTiles){
393  MinY = 0;
394  }else{
395  MinY = Tile_Y - RadiusInTiles;
396  }
397 
398  if( ((Extension.X) / TileSize - RadiusInTiles) < Tile_X ){
399  MaxX = (Extension.X) / TileSize;
400  }else{
401  MaxX = Tile_X + RadiusInTiles;
402  }
403 
404  if( ((-Extension.Y) / TileSize) - RadiusInTiles < Tile_Y ){
405  MaxY = (-Extension.Y) / TileSize;
406  }else{
407  MaxY = Tile_Y + RadiusInTiles;
408  }
409  /*
410  UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::GetParticlesInTileRadius MinX %zu MaxX: %zu, MinY %zu MaxY %zu"),
411  MinX, MaxX, MinY, MaxY);
412  UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::GetParticlesInTileRadius Extension X: %f, Y %f"), Extension.X, Extension.Y);
413  UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::GetParticlesInTileRadius Position X: %f, Y %f"), Position.X, Position.Y);
414  UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::GetParticlesInTileRadius RadiusInTiles %d"), RadiusInTiles);
415  UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::GetParticlesInTileRadius TileId %lld TileX: %d, TileY %d"),
416  TileId, Tile_X, Tile_Y);
417 
418 
419  */
420  // FDenseTile& Tile = GetTile(TileId);
421  // return Tile.GetParticlesInRadius(Position, Radius);
422  std::vector<FParticle*> ParticlesInRadius;
423  for( uint32_t X = MinX; X <= MaxX; ++X )
424  {
425  for( uint32_t Y = MinY; Y <= MaxY; ++Y )
426  {
427  uint64_t CurrentTileId = GetTileId(X,Y);
428  if( Map.count(CurrentTileId) )
429  {
430  GetTile(X, Y).GetParticlesInRadius(Position, Radius, ParticlesInRadius);
431  }
432  }
433  }
434  return ParticlesInRadius;
435 }
436 
437 std::vector<FParticle*> FSparseHighDetailMap::
438  GetParticlesInBox(const FOrientedBox& OBox)
439 {
440  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetParticlesInBox);
441  std::vector<uint64_t> TilesToCheck = GetIntersectingTiles(OBox);
442 
443  std::vector<FParticle*> ParticlesInRadius;
444  for(uint64_t TileId : TilesToCheck)
445  {
446  GetTile(TileId).GetParticlesInBox(OBox, ParticlesInRadius);
447  }
448  return ParticlesInRadius;
449 }
450 
452  const FOrientedBox& OBox)
453 {
454 TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetIntersectingTiles);
455  std::vector<uint64_t> IntersectingTiles;
456 
457  FVector BoxCenter = UEFrameToSI(OBox.Center);
458  float ExtentX = UEFrameToSI(OBox.ExtentX);
459  float ExtentXSqr = ExtentX*ExtentX;
460  FVector AxisX = UEFrameToSIDirection(OBox.AxisX);
461  float ExtentY = UEFrameToSI(OBox.ExtentY);
462  float ExtentYSqr = ExtentY*ExtentY;
463  FVector AxisY = UEFrameToSIDirection(OBox.AxisY);
464 
465  uint64_t CenterTileId = GetTileId(BoxCenter);
466  uint32_t CenterTile_X = (uint32_t)(CenterTileId >> 32);
467  uint32_t CenterTile_Y = (uint32_t)(CenterTileId & (uint32_t)(~0));
468  uint32_t TileRange = 1;
469  IntersectingTiles.emplace_back(CenterTileId);
470  FVector2D BoxVert0 = FVector2D(BoxCenter - AxisX*ExtentX - AxisY*ExtentY);
471  FVector2D BoxVert1 = FVector2D(BoxCenter + AxisX*ExtentX - AxisY*ExtentY);
472  FVector2D BoxVert2 = FVector2D(BoxCenter + AxisX*ExtentX + AxisY*ExtentY);
473  FVector2D BoxVert3 = FVector2D(BoxCenter - AxisX*ExtentX + AxisY*ExtentY);
474 
475  // Use separate axis theorem to detect intersecting tiles with OBox
476  struct F2DRectangle
477  {
478  FVector2D V1, V2, V3, V4;
479  std::vector<FVector2D> ComputeNormals() const
480  {
481  FVector2D V12 = (V2 - V1).GetSafeNormal();
482  FVector2D V23 = (V3 - V2).GetSafeNormal();
483  return {FVector2D(-V12.Y, V12.X), FVector2D(-V23.Y, V23.X)};
484  }
485  };
486  auto SATtest = [&](const FVector2D& Axis, const F2DRectangle &Shape,
487  float &MinAlong, float &MaxAlong)
488  {
489  for (const FVector2D& Vert : {Shape.V1, Shape.V2, Shape.V3, Shape.V4})
490  {
491  float DotVal = FVector2D::DotProduct(Vert, Axis);
492  if( DotVal < MinAlong )
493  MinAlong = DotVal;
494  if( DotVal > MaxAlong )
495  MaxAlong = DotVal;
496  }
497  };
498  auto IsBetweenOrdered = [&]( float Val, float LowerBound, float UpperBound ) -> bool
499  {
500  return LowerBound <= Val && Val <= UpperBound ;
501  };
502  auto Overlaps = [&]( float Min1, float Max1, float Min2, float Max2 ) -> bool
503  {
504  return IsBetweenOrdered( Min2, Min1, Max1 ) || IsBetweenOrdered( Min1, Min2, Max2 ) ;
505  };
506  auto RectangleIntersect = [&](
507  const F2DRectangle& Rectangle1,
508  const F2DRectangle& Rectangle2) -> bool
509  {
510  for (const FVector2D& Normal : Rectangle1.ComputeNormals())
511  {
512  constexpr float LargeNumber = 10000000;
513  float Shape1Min = LargeNumber, Shape1Max = -LargeNumber;
514  float Shape2Min = LargeNumber, Shape2Max = -LargeNumber;
515  SATtest(Normal, Rectangle1, Shape1Min, Shape1Max);
516  SATtest(Normal, Rectangle2, Shape2Min, Shape2Max);
517  if (!Overlaps(Shape1Min, Shape1Max, Shape2Min, Shape2Max))
518  {
519  return false;
520  }
521  }
522  for (const FVector2D& Normal : Rectangle2.ComputeNormals())
523  {
524  constexpr float LargeNumber = 10000000;
525  float Shape1Min = LargeNumber, Shape1Max = -LargeNumber;
526  float Shape2Min = LargeNumber, Shape2Max = -LargeNumber;
527  SATtest(Normal, Rectangle1, Shape1Min, Shape1Max);
528  SATtest(Normal, Rectangle2, Shape2Min, Shape2Max);
529  if (!Overlaps(Shape1Min, Shape1Max, Shape2Min, Shape2Max))
530  {
531  return false;
532  }
533  }
534  return true;
535  };
536  // check surrounding tiles except CenterTile (as it is always included)
537  std::vector<std::pair<uint32_t, uint32_t>> TilesToCheck = {
538  {CenterTile_X-1, CenterTile_Y-1}, {CenterTile_X, CenterTile_Y-1},
539  {CenterTile_X+1, CenterTile_Y-1}, {CenterTile_X-1, CenterTile_Y},
540  {CenterTile_X+1, CenterTile_Y}, {CenterTile_X-1, CenterTile_Y+1},
541  {CenterTile_X, CenterTile_Y+1}, {CenterTile_X+1, CenterTile_Y+1}};
542  for (auto& TileIdPair : TilesToCheck)
543  {
544  uint32_t &Tile_X = TileIdPair.first;
545  uint32_t &Tile_Y = TileIdPair.second;
546  FVector2D V1 = FVector2D(GetTilePosition(Tile_X, Tile_Y).ToFVector());
547  FVector2D V2 = FVector2D(GetTilePosition(Tile_X+1, Tile_Y).ToFVector());
548  FVector2D V3 = FVector2D(GetTilePosition(Tile_X+1, Tile_Y+1).ToFVector());
549  FVector2D V4 = FVector2D(GetTilePosition(Tile_X, Tile_Y+1).ToFVector());
550  if (RectangleIntersect(
551  F2DRectangle{BoxVert0,BoxVert1,BoxVert2,BoxVert3},
552  F2DRectangle{V1,V2,V3,V4}))
553  {
554  IntersectingTiles.emplace_back(GetTileId(Tile_X, Tile_Y));
555  }
556  }
557 
558  return IntersectingTiles;
559 }
560 
562 {
563  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetLoadedTilesInRange);
564 
565  uint64_t TileId = GetTileId(Position);
566  uint32_t Tile_X = (uint32_t)(TileId >> 32);
567  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
568 
569  uint32_t RadiusInTiles = (Radius/TileSize);
570  uint32_t MinX = 0,MinY = 0,MaxX = 0,MaxY = 0;
571  {
572  TRACE_CPUPROFILER_EVENT_SCOPE(Comparisons);
573  if( Tile_X < RadiusInTiles){
574  MinX = 0;
575  }else{
576  MinX = Tile_X - RadiusInTiles;
577  }
578 
579  if( Tile_Y < RadiusInTiles){
580  MinY = 0;
581  }else{
582  MinY = Tile_Y - RadiusInTiles;
583  }
584 
585  MaxX = Tile_X + RadiusInTiles;
586  MaxY = Tile_Y + RadiusInTiles;
587  }
588 
589  std::vector<uint64_t> LoadedTiles;
590  {
591  TRACE_CPUPROFILER_EVENT_SCOPE(Looping);
592  for( uint32_t X = MinX; X < MaxX; ++X )
593  {
594  for( uint32_t Y = MinY; Y < MaxY; ++Y )
595  {
596  uint64_t CurrentTileId = GetTileId(X,Y);
597  if( Map.find(CurrentTileId) != Map.end() )
598  {
599  LoadedTiles.emplace_back(CurrentTileId);
600  }
601  }
602  }
603  }
604  return LoadedTiles;
605 }
606 
607 uint64_t FSparseHighDetailMap::GetTileId(uint32_t Tile_X, uint32_t Tile_Y)
608 {
609  return (uint64_t) Tile_X << 32 | Tile_Y;
610 }
611 
613 {
614  uint32_t Tile_X = static_cast<uint32_t>((Position.X - Tile0Position.X) / TileSize);
615  uint32_t Tile_Y = static_cast<uint32_t>((Position.Y - Tile0Position.Y) / TileSize);
616  // UE_LOG(LogCarla, Log, TEXT("Getting tile at location %s, (%d, %d)"), *Position.ToString(), Tile_X, Tile_Y);
617  return GetTileId(Tile_X, Tile_Y);
618 }
619 
621 {
622  uint32_t Tile_X = (uint32_t)(TileId >> 32);
623  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
624  return GetTilePosition(Tile_X, Tile_Y);
625 }
626 
627 FDVector FSparseHighDetailMap::GetTilePosition(uint32_t Tile_X, uint32_t Tile_Y)
628 {
629  FDVector Position = FDVector(Tile_X*TileSize, Tile_Y*TileSize, FloorHeight);
630  Position = Position + Tile0Position;
631  return Position;
632 }
633 
635 {
636  uint64_t TileId = GetTileId(Position);
637  return GetTile(TileId);
638 }
639 
640 FDenseTile& FSparseHighDetailMap::GetTile(uint32_t Tile_X, uint32_t Tile_Y)
641 {
642  uint64_t TileId = GetTileId(Tile_X, Tile_Y);
643  return GetTile(TileId);
644 }
646 {
647  auto Iterator = Map.find(TileId);
648  if (Iterator == Map.end())
649  {
650  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::GetTile);
651  // FScopeLock Lock(&Lock_CacheMap);
652  Lock_GetTile.Lock();
653  bool bGotCacheLock = Lock_CacheMap.TryLock();
654  if(bGotCacheLock)
655  {
656  auto CacheIterator = CacheMap.find(TileId);
657  if (CacheIterator != CacheMap.end())
658  {
659  Map.emplace(TileId, std::move(CacheIterator->second));
660  CacheMap.erase(CacheIterator);
661  Lock_CacheMap.Unlock();
662  Lock_GetTile.Unlock();
663  return Map[TileId];
664  }
665  Lock_CacheMap.Unlock();
666  }
667  FDenseTile& Tile = Map[TileId];
668  Lock_GetTile.Unlock();
669  return InitializeRegion(TileId);
670  }
671  return Iterator->second;
672 }
673 
675 {
676  uint32_t Tile_X = static_cast<uint32_t>((Position.X - Tile0Position.X) / TileSize);
677  uint32_t Tile_Y = static_cast<uint32_t>((Position.Y - Tile0Position.Y) / TileSize);
678  return FIntVector(Tile_X, Tile_Y, 0);
679 }
680 FIntVector FSparseHighDetailMap::GetVectorTileId(uint64_t TileId)
681 {
682  uint32_t Tile_X = (uint32_t)(TileId >> 32);
683  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
684  return FIntVector(Tile_X, Tile_Y, 0);
685 }
686 
687 FDenseTile& FSparseHighDetailMap::InitializeRegion(uint32_t Tile_X, uint32_t Tile_Y)
688 {
689  uint64_t TileId = GetTileId(Tile_X, Tile_Y);
690  return InitializeRegion(TileId);
691 }
692 
694 {
695  FDVector TileCenter = GetTilePosition(TileId);
696  FDenseTile& Tile = Map[TileId];
697  //UE_LOG(LogCarla, Log, TEXT("InitializeRegion Tile with (%f,%f,%f)"),
698  // TileCenter.X,TileCenter.Y,TileCenter.Z);
699  Tile.InitializeTile(
700  TextureSize, AffectedRadius,
701  ParticleSize, TerrainDepth,
702  TileCenter, TileCenter + FDVector(TileSize, TileSize, 0.f),
703  SavePath, Heightmap);
704  return Tile;
705 }
706 
708 {
709  FDVector TileCenter = GetTilePosition(TileId);
710  FDenseTile& Tile = CacheMap[TileId];
711  //UE_LOG(LogCarla, Log, TEXT("InitializeRegionInCache Tile with (%f,%f,%f)"),
712  // TileCenter.X,TileCenter.Y,TileCenter.Z);
713 
714  Tile.InitializeTile(
715  TextureSize, AffectedRadius,
716  ParticleSize, TerrainDepth,
717  TileCenter, TileCenter + FDVector(TileSize, TileSize, 0.f),
718  SavePath, Heightmap);
719  Lock_CacheMap.Unlock();
720  return Tile;
721 }
722 
724  FDVector Origin, FDVector MapSize, float Size, float ScaleZ)
725 {
726  Tile0Position = Origin;
727  TileSize = Size;
728  Extension = MapSize;
729  Heightmap.InitializeHeightmap(
730  DataAsset, Extension, Tile0Position,
731  Tile0Position, ScaleZ);
732  UE_LOG(LogCarla, Log,
733  TEXT("Sparse Map initialized"));
734  UE_LOG(LogCarla, Log,
735  TEXT("Map Extension %f %f %f"), MapSize.X, MapSize.Y, MapSize.Z );
736 }
737 
739  FDVector Origin, FDVector MapSize, float Size,
740  float ScaleZ)
741 {
742  Heightmap.Clear();
743  Heightmap.InitializeHeightmap(
744  DataAsset, Extension, Origin,
745  Origin, ScaleZ);
746  UE_LOG(LogCarla, Log,
747  TEXT("Height map updated"));
748 }
750 {
751  Heightmap.Clear();
752  Map.clear();
753 }
754 
756  FDVector Position, float RadiusX, float RadiusY, float CacheRadiusX, float CacheRadiusY)
757 {
758  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::UpdateMaps);
759  double MinX = Position.X - RadiusX;
760  double MinY = Position.Y - RadiusY;
761  double MaxX = Position.X + RadiusX;
762  double MaxY = Position.Y + RadiusY;
763 
764  FIntVector MinVector = GetVectorTileId(FDVector(MinX, MinY, 0));
765  FIntVector MaxVector = GetVectorTileId(FDVector(MaxX, MaxY, 0));
766 
767  FIntVector CacheMinVector = GetVectorTileId(
768  FDVector(Position.X - CacheRadiusX, Position.Y - CacheRadiusY, 0));
769  FIntVector CacheMaxVector = GetVectorTileId(
770  FDVector(Position.X + CacheRadiusX, Position.Y + CacheRadiusY, 0));
771 
772  auto IsInCacheRange = [&](int32_t Tile_X, int32_t Tile_Y) -> bool
773  {
774  return Tile_X >= CacheMinVector.X && Tile_X <= CacheMaxVector.X &&
775  Tile_Y >= CacheMinVector.Y && Tile_Y <= CacheMaxVector.Y;
776  };
777  auto IsInMapRange = [&](int32_t Tile_X, int32_t Tile_Y) -> bool
778  {
779  return Tile_X >= MinVector.X && Tile_X <= MaxVector.X &&
780  Tile_Y >= MinVector.Y && Tile_Y <= MaxVector.Y;
781  };
782  {
783  FScopeLock ScopeLock(&Lock_Map);
784  FScopeLock ScopeCacheLock(&Lock_CacheMap);
785  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateMap);
786  // unload extra tiles
787  std::vector<uint64_t> TilesToErase;
788  for (auto &Element : Map)
789  {
790  uint64_t TileId = Element.first;
791  FIntVector VectorTileId = GetVectorTileId(TileId);
792  if (!IsInMapRange(VectorTileId.X, VectorTileId.Y))
793  {
794  CacheMap.emplace(TileId, std::move(Element.second));
795  TilesToErase.emplace_back(TileId);
796  }
797  }
798  for (uint64_t TileId : TilesToErase)
799  {
800  Map.erase(TileId);
801  }
802  }
803  {
804  FScopeLock ScopeCacheLock(&Lock_CacheMap);
805  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateCache);
806 
807  // unload extra tiles
808  std::vector<uint64_t> TilesToErase;
809  {
810  TRACE_CPUPROFILER_EVENT_SCOPE(GetTilesToErase);
811  for (auto &Element : CacheMap)
812  {
813  uint64_t TileId = Element.first;
814  FIntVector VectorTileId = GetVectorTileId(TileId);
815  if (!IsInCacheRange(VectorTileId.X, VectorTileId.Y))
816  {
817  TilesToErase.emplace_back(TileId);
818  }
819  }
820  }
821 
822  {
823  TRACE_CPUPROFILER_EVENT_SCOPE(EraseTiles);
824  ParallelFor(TilesToErase.size(), [&](int32 Idx)
825  {
826  TRACE_CPUPROFILER_EVENT_SCOPE(SaveData);
827  uint64_t TileId = TilesToErase[Idx];
828  auto& Tile = CacheMap[TileId];
829  std::string FileToSavePath = std::string(
830  TCHAR_TO_UTF8(*( SavePath + Tile.TilePosition.ToString() + ".tile")));
831  std::ofstream OutputStream(FileToSavePath.c_str());
832  WriteFVector(OutputStream, Tile.TilePosition.ToFVector());
833  WriteStdVector<FParticle> (OutputStream, Tile.Particles);
834  OutputStream.close();
835  });
836  {
837  TRACE_CPUPROFILER_EVENT_SCOPE(CacheMap.erase);
838  for (uint64_t TileId : TilesToErase)
839  {
840  CacheMap.erase(TileId);
841  }
842  }
843  }
844  }
845 
846 }
847 
848 void FSparseHighDetailMap::Update(FVector Position, float RadiusX, float RadiusY)
849 {
850  FVector PositionTranslated;
851  PositionTranslated.X = ( Position.X * 0.01 ) + (Extension.X * 0.5f);
852  PositionTranslated.Y = (-Position.Y * 0.01 ) + ( (-Extension.Y) * 0.5f);
853  PositionTranslated.Z = ( Position.Z * 0.01 ) + (Extension.Z * 0.5f);
854  PositionToUpdate = PositionTranslated;
855 
856  double MinX = std::min( std::max( PositionTranslated.X - RadiusX, 0.0f) , static_cast<float>(Extension.X - 1.0f) );
857  double MinY = std::min( std::max( PositionTranslated.Y - RadiusY, 0.0f) , static_cast<float>(-Extension.Y + 1.0f) );
858  double MaxX = std::min( std::max( PositionTranslated.X + RadiusX, 0.0f) , static_cast<float>(Extension.X - 1.0f) );
859  double MaxY = std::min( std::max( PositionTranslated.Y + RadiusY, 0.0f) , static_cast<float>(-Extension.Y + 1.0f) );
860 
861  FIntVector MinVector = GetVectorTileId(FDVector(std::floor(MinX), std::floor(MinY), 0));
862  FIntVector MaxVector = GetVectorTileId(FDVector(std::floor(MaxX), std::floor(MaxY), 0));
863 
864  {
865  TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FSparseHighDetailMap::WaitUntilProperTilesAreLoaded"));
866  for(int32_t X = MinVector.X; X < MaxVector.X; X++ )
867  {
868  for(int32_t Y = MinVector.Y; Y < MaxVector.Y; Y++ )
869  {
870  bool ConditionToStopWaiting = true;
871  // Check if tiles are already loaded
872  // If they are send position
873  // If not wait until loaded
874  while(ConditionToStopWaiting)
875  {
876  uint64_t CurrentTileID = GetTileId(X,Y);
877  {
878  TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FSparseHighDetailMap::WaitUntilProperTilesAreLoaded::TimeLocked"));
879  ConditionToStopWaiting = Map.find(CurrentTileID) == Map.end();
880  }
881 
882  }
883  }
884  }
885  }
886 
887 }
888 
890 {
891  UE_LOG(LogCarla, Warning, TEXT("Save directory %s"), *SavePath );
892  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::SaveMap);
893  ParallelFor(Map.size(), [this](int32 Idx)
894  {
895  std::pair<uint64_t, FDenseTile> it = *(std::next(this->Map.begin(), Idx) );
896  std::string FileToSavePath = std::string(TCHAR_TO_UTF8(*( this->SavePath + it.second.TilePosition.ToString() + ".tile")));
897  std::ofstream OutputStream(FileToSavePath.c_str());
898  WriteFVector(OutputStream, it.second.TilePosition.ToFVector());
899  WriteStdVector<FParticle> (OutputStream, it.second.Particles);
900  OutputStream.close();
901  });
902 
903  ParallelFor(CacheMap.size(), [this](int32 Idx)
904  {
905  std::pair<uint64_t, FDenseTile> it = *(std::next(this->CacheMap.begin(), Idx) );
906  std::string FileToSavePath = std::string(TCHAR_TO_UTF8(*( this->SavePath + it.second.TilePosition.ToString() + ".tile")));
907  std::ofstream OutputStream(FileToSavePath.c_str());
908  WriteFVector(OutputStream, it.second.TilePosition.ToFVector());
909  WriteStdVector<FParticle> (OutputStream, it.second.Particles);
910  OutputStream.close();
911  });
912 
913 }
914 
915 void UCustomTerrainPhysicsComponent::UpdateTexture()
916 {
917  UpdateLoadedTextureDataRegions();
918 
919  ENQUEUE_RENDER_COMMAND(UpdateDynamicTextureCode)
920  (
921  [NewData=Data, Texture=TextureToUpdate](auto &InRHICmdList) mutable
922  {
923  TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UCustomTerrainPhysicsComponent::TickComponent Renderthread"));
924  FUpdateTextureRegion2D region;
925  region.SrcX = 0;
926  region.SrcY = 0;
927  region.DestX = 0;
928  region.DestY = 0;
929  region.Width = Texture->GetSizeX();
930  region.Height = Texture->GetSizeY();
931 
932  FTexture2DResource* resource = (FTexture2DResource*)Texture->Resource;
933  RHIUpdateTexture2D(
934  resource->GetTexture2DRHI(), 0, region, region.Width * sizeof(uint8_t), &NewData[0]);
935  });
936 }
937 
938 void UCustomTerrainPhysicsComponent::InitTexture(){
939  if( Data.Num() == 0 && TextureToUpdate ){
940  float LimitX = TextureToUpdate->GetSizeX();
941  float LimitY = TextureToUpdate->GetSizeY();
942  Data.Init(128, LimitX * LimitY);
943  }
944 
945  if( LargeData.Num() == 0 && LargeTextureToUpdate ){
946  float LimitX = LargeTextureToUpdate->GetSizeX();
947  float LimitY = LargeTextureToUpdate->GetSizeY();
948  LargeData.Init(128, LimitX * LimitY);
949  }
950 }
951 
952 void UCustomTerrainPhysicsComponent::UpdateLoadedTextureDataRegions()
953 {
954  TRACE_CPUPROFILER_EVENT_SCOPE("UCustomTerrainPhysicsComponent::UpdateLoadedTextureDataRegions");
955  const int32_t TextureSizeX = TextureToUpdate->GetSizeX();
956  if ( TextureSizeX == 0) return;
957 
958 
959  FDVector TextureCenterPosition = UEFrameToSI(GetTileCenter(LastUpdatedPosition));
960 
961  std::vector<uint64_t> LoadedTiles =
962  SparseMap.GetLoadedTilesInRange(TextureCenterPosition, TextureRadius );
963  FDVector TextureOrigin = TextureCenterPosition - FDVector(TextureRadius, TextureRadius, 0);
964  float GlobalTexelSize = (2.0f * TextureRadius) / TextureSizeX;
965  int32_t PartialHeightMapSize = std::floor( SparseMap.GetTileSize() * TextureSizeX / (2*TextureRadius) );
966 
967  float LocalTexelSize = SparseMap.GetTileSize() / PartialHeightMapSize;
968  LocalTexelSize = std::floor( LocalTexelSize * 1000.0f ) / 1000.0f;
969 
970  Data.Init( 128, Data.Num() );
971  float DisplacementRange = MaxDisplacement - MinDisplacement;
972  float InverseDisplacementRange = 1.0f / DisplacementRange;
973 
974  for (uint64_t TileId : LoadedTiles)
975  {
976  FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
977 
978  if (!CurrentTile.bParticlesZOrderedInitialized)
979  {
980  continue;
981  }
982 
983  FDVector& TilePosition = CurrentTile.TilePosition;
984  for (int32_t Local_Y = 0; Local_Y < PartialHeightMapSize; ++Local_Y)
985  {
986  for (int32_t Local_X = 0; Local_X < PartialHeightMapSize; ++Local_X)
987  {
988  int32_t LocalIndex = Local_Y * PartialHeightMapSize + Local_X;
989  float Height = CurrentTile.ParticlesHeightMap[LocalIndex];
990  FDVector LocalTexelPosition =
991  TilePosition + FDVector(Local_X*LocalTexelSize, Local_Y*LocalTexelSize, 0);
992  int32_t Coord_X = std::floor( (LocalTexelPosition.X - TextureOrigin.X ) / GlobalTexelSize );
993  int32_t Coord_Y = std::floor( (LocalTexelPosition.Y - TextureOrigin.Y ) / GlobalTexelSize );
994 
995  if ( Coord_X >= 0 && Coord_X < TextureSizeX &&
996  Coord_Y >= 0 && Coord_Y < TextureToUpdate->GetSizeY() )
997  {
998  float OriginalHeight = SparseMap.GetHeight(LocalTexelPosition);
999  float Displacement = Height - OriginalHeight;
1000  float Fraction = (Displacement - MinDisplacement) * InverseDisplacementRange;
1001  Fraction = FMath::Clamp(Fraction, 0.f, 1.f) * 255;
1002  Data[Coord_X * TextureToUpdate->GetSizeY() + Coord_Y] = static_cast<uint8_t>(Fraction );
1003  }
1004  }
1005  }
1006  }
1007 }
1008 
1009 void UCustomTerrainPhysicsComponent::UpdateLargeTexture()
1010 {
1011  UpdateLargeTextureData();
1012 
1013  ENQUEUE_RENDER_COMMAND(UpdateDynamicTextureCode)
1014  (
1015  [NewData=LargeData, Texture=LargeTextureToUpdate](auto &InRHICmdList) mutable
1016  {
1017  TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UCustomTerrainPhysicsComponent::TickComponent Renderthread"));
1018  FUpdateTextureRegion2D region;
1019  region.SrcX = 0;
1020  region.SrcY = 0;
1021  region.DestX = 0;
1022  region.DestY = 0;
1023  region.Width = Texture->GetSizeX();
1024  region.Height = Texture->GetSizeY();
1025 
1026  FTexture2DResource* resource = (FTexture2DResource*)Texture->Resource;
1027  RHIUpdateTexture2D(
1028  resource->GetTexture2DRHI(), 0, region, region.Width * sizeof(uint8_t), &NewData[0]);
1029  });
1030 }
1031 
1032 void UCustomTerrainPhysicsComponent::UpdateLargeTextureData()
1033 {
1034  uint32_t NumberOfParticlesIn1AxisInLocalHeightmap = TextureToUpdate->GetSizeX() / (TextureRadius * 2) / TileSize;
1035  uint32_t NumberOfParticlesIn1AxisInLargeHeightmap = LargeTextureToUpdate->GetSizeX() / (CacheRadius.X * 2) / TileSize;
1036 
1037  std::vector<float> ParticlesPositions;
1038  {
1039  TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UCustomTerrainPhysicsComponent::UpdateLargeTextureData::GettingHeightMaps"));
1040  FVector OriginPosition;
1041  OriginPosition.X = CachePosition.X + (WorldSize.X * 0.5f);
1042  OriginPosition.Y = -CachePosition.Y - (WorldSize.Y * 0.5f);
1043 
1044  //UE_LOG(LogCarla, Log, TEXT("FSparseHighDetailMap::UpdateTextureData OriginPosition X: %f, Y %f"), OriginPosition.X, OriginPosition.Y);
1045  }
1046 
1047  int32_t OffsetX = 0;
1048  int32_t OffsetY = 0;
1049  float* Ptr = &ParticlesPositions[0];
1050  while( OffsetY < LargeTextureToUpdate->GetSizeY() )
1051  {
1052  for(uint32_t y = 0; y < NumberOfParticlesIn1AxisInLocalHeightmap; y++)
1053  {
1054  float LocalYTransformed = std::floor(y / NumberOfParticlesIn1AxisInLocalHeightmap * NumberOfParticlesIn1AxisInLargeHeightmap);
1055  for(uint32_t x = 0; x < NumberOfParticlesIn1AxisInLocalHeightmap; x++)
1056  {
1057  uint32_t LocalIndex = x + y * NumberOfParticlesIn1AxisInLocalHeightmap;
1058  float LocalXTransformed = std::floor(x / NumberOfParticlesIn1AxisInLocalHeightmap * NumberOfParticlesIn1AxisInLargeHeightmap);
1059  //uint32_t AbsolutIndex = (LocalXTransformed + OffsetX) + (LocalYTransformed + OffsetY) *
1060 
1061  }
1062  }
1063 
1064  Ptr += (NumberOfParticlesIn1AxisInLocalHeightmap* NumberOfParticlesIn1AxisInLocalHeightmap);
1065 
1066  OffsetX += NumberOfParticlesIn1AxisInLargeHeightmap;
1067  if( OffsetX >= LargeTextureToUpdate->GetSizeX() )
1068  {
1069  OffsetX = 0;
1070  OffsetY += NumberOfParticlesIn1AxisInLargeHeightmap;
1071  }
1072  }
1073 }
1074 
1075 
1076 UCustomTerrainPhysicsComponent::UCustomTerrainPhysicsComponent()
1077  : Super()
1078 {
1079  PrimaryComponentTick.bCanEverTick = true;
1080 }
1081 
1082 void UCustomTerrainPhysicsComponent::BeginPlay()
1083 {
1084  TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::BeginPlay);
1085  Super::BeginPlay();
1086  //GEngine->Exec( GetWorld(), TEXT( "Trace.Start default,gpu" ) );
1087 
1088  SparseMap.Clear();
1089  RootComponent = Cast<UPrimitiveComponent>(GetOwner()->GetRootComponent());
1090  if (!RootComponent)
1091  {
1092  UE_LOG(LogCarla, Error,
1093  TEXT("UCustomTerrainPhysicsComponent: Root component is not a UPrimitiveComponent"));
1094  }
1095 #ifndef WITH_EDITOR
1096  bUpdateParticles = true;
1097  DrawDebugInfo = false;
1098  bUseDynamicModel = false;
1099  bDisableVehicleGravity = false;
1100  NNVerbose = false;
1101  bUseImpulse = false;
1102  bUseMeanAcceleration = false;
1103  bShowForces = true;
1104  bBenchMark = false;
1105  bDrawHeightMap = false;
1106  ForceMulFactor = 1.f;
1107  ParticleForceMulFactor = 1.f;
1108  FloorHeight = 0.0;
1109  bDrawLoadedTiles = false;
1110  bUseSoilType = true;
1111  EffectMultiplayer = 200.0f;
1112  MinDisplacement = -10.0f;
1113  MaxDisplacement = 10.0f;
1114  bRemoveLandscapeColliders = false;
1115 #endif
1116 
1117  int IntValue;
1118  if (FParse::Value(FCommandLine::Get(), TEXT("-cuda-device="), IntValue))
1119  {
1120  CUDADevice = IntValue;
1121  }
1122  if (FParse::Value(FCommandLine::Get(), TEXT("-max-particles-per-wheel="), IntValue))
1123  {
1124  MaxParticlesPerWheel = IntValue;
1125  }
1126  float Value;
1127  if (FParse::Value(FCommandLine::Get(), TEXT("-particle-size="), Value))
1128  {
1129  ParticleDiameter = MToCM*Value;
1130  }
1131  if (FParse::Value(FCommandLine::Get(), TEXT("-terrain-depth="), Value))
1132  {
1133  TerrainDepth = MToCM*Value;
1134  }
1135  if (FParse::Value(FCommandLine::Get(), TEXT("-search-radius="), Value))
1136  {
1137  SearchRadius = MToCM*Value;
1138  }
1139  if (FParse::Value(FCommandLine::Get(), TEXT("-box-search-forward="), Value))
1140  {
1141  BoxSearchForwardDistance = MToCM*Value;
1142  }
1143  if (FParse::Value(FCommandLine::Get(), TEXT("-box-search-lateral="), Value))
1144  {
1145  BoxSearchLateralDistance = MToCM*Value;
1146  }
1147  if (FParse::Value(FCommandLine::Get(), TEXT("-box-search-depth="), Value))
1148  {
1149  BoxSearchDepthDistance = MToCM*Value;
1150  }
1151  if (FParse::Value(FCommandLine::Get(), TEXT("-force-mul-factor="), Value))
1152  {
1153  ForceMulFactor = Value;
1154  }
1155  if (FParse::Value(FCommandLine::Get(), TEXT("-defor-mul="), Value))
1156  {
1157  EffectMultiplayer = Value;
1158  }
1159  if (FParse::Value(FCommandLine::Get(), TEXT("-defor-res="), Value))
1160  {
1161  ChosenRes = static_cast<EDefResolutionType>(Value);
1162  }
1163  if (FParse::Value(FCommandLine::Get(), TEXT("-min-displacement="), Value))
1164  {
1165  MinDisplacement = Value;
1166  }
1167  if (FParse::Value(FCommandLine::Get(), TEXT("-max-displacement="), Value))
1168  {
1169  MaxDisplacement = Value;
1170  }
1171  if (FParse::Value(FCommandLine::Get(), TEXT("-particle-force-mul-factor="), Value))
1172  {
1173  ParticleForceMulFactor = Value;
1174  }
1175  if (FParse::Value(FCommandLine::Get(), TEXT("-max-force="), Value))
1176  {
1177  MaxForceMagnitude = MToCM*Value;
1178  }
1179  if (FParse::Value(FCommandLine::Get(), TEXT("-floor-height="), Value))
1180  {
1181  FloorHeight = MToCM*Value;
1182  }
1183  if (FParse::Value(FCommandLine::Get(), TEXT("-tile-size="), Value))
1184  {
1185  TileSize = Value;
1186  }
1187  if (FParse::Value(FCommandLine::Get(), TEXT("-tile-radius="), Value))
1188  {
1189  TileRadius = MToCM*FVector(Value, Value, 0.f);
1190  }
1191  if (FParse::Value(FCommandLine::Get(), TEXT("-cache-radius="), Value))
1192  {
1193  CacheRadius = MToCM*FVector(Value, Value, 0.f);
1194  }
1195  if (FParse::Param(FCommandLine::Get(), TEXT("-update-particles")))
1196  {
1197  bUpdateParticles = true;
1198  }
1199  if (FParse::Param(FCommandLine::Get(), TEXT("-draw-debug-info")))
1200  {
1201  DrawDebugInfo = true;
1202  }
1203  if (FParse::Param(FCommandLine::Get(), TEXT("-use-local-frame")))
1204  {
1205  bUseLocalFrame = true;
1206  }
1207  FString Path;
1208  if (FParse::Value(FCommandLine::Get(), TEXT("-network-path="), Path))
1209  {
1210  NeuralModelFile = Path;
1211  }
1212 #ifndef WITH_EDITOR
1213  // if (Path == "")
1214  // {
1215  // NeuralModelFile = FPaths::ProjectContentDir() + NeuralModelFile;
1216  // }
1217 #endif
1218  if (FParse::Param(FCommandLine::Get(), TEXT("-dynamic-model")))
1219  {
1220  bUseDynamicModel = true;
1221  }
1222  if (FParse::Param(FCommandLine::Get(), TEXT("-disable-gravity")))
1223  {
1224  bDisableVehicleGravity = true;
1225  }
1226  if (FParse::Param(FCommandLine::Get(), TEXT("-disable-nn-verbose")))
1227  {
1228  NNVerbose = false;
1229  }
1230  if (FParse::Param(FCommandLine::Get(), TEXT("-use-terrain-type")))
1231  {
1232  bUseSoilType = true;
1233  }
1234  if (FParse::Param(FCommandLine::Get(), TEXT("-use-impulse")))
1235  {
1236  bUseImpulse = true;
1237  }
1238  if (FParse::Param(FCommandLine::Get(), TEXT("-use-mean-acceleration")))
1239  {
1240  bUseMeanAcceleration = true;
1241  }
1242  if (FParse::Param(FCommandLine::Get(), TEXT("-hide-debug-forces")))
1243  {
1244  bShowForces = false;
1245  }
1246  if (FParse::Param(FCommandLine::Get(), TEXT("-benchmark")))
1247  {
1248  bBenchMark = true;
1249  }
1250  if (FParse::Param(FCommandLine::Get(), TEXT("-draw-loaded-tiles")))
1251  {
1252  bDrawLoadedTiles = true;
1253  }
1254  if (FParse::Param(FCommandLine::Get(), TEXT("-remove-colliders")))
1255  {
1256  bRemoveLandscapeColliders = true;
1257  }
1258  if (FParse::Param(FCommandLine::Get(), TEXT("-disable-terramechanics")))
1259  {
1260  SetComponentTickEnabled(false);
1261  return;
1262  }
1263 
1264  if(bRemoveLandscapeColliders)
1265  {
1266  FWorldDelegates::LevelAddedToWorld.AddUObject(
1267  this, &UCustomTerrainPhysicsComponent::OnLevelAddedToWorld);
1268  }
1269 
1270  LargeMapManager = UCarlaStatics::GetLargeMapManager(GetWorld());
1271  if( TexturesRes.Contains(ChosenRes) ){
1272  TextureToUpdate = TexturesRes[ChosenRes];
1273  }
1274 
1275  {
1276  TRACE_CPUPROFILER_EVENT_SCOPE(InitializeDenseMap);
1277  SparseMap.Clear();
1278  UE_LOG(LogCarla, Warning,
1279  TEXT("ParticleDiameter %f"), ParticleDiameter);
1280 
1281  SparseMap.Init(TextureToUpdate->GetSizeX(), TextureRadius, ParticleDiameter * CMToM, TerrainDepth * CMToM, FloorHeight * CMToM );
1282  RootComponent = Cast<UPrimitiveComponent>(GetOwner()->GetRootComponent());
1283  if(LargeMapManager)
1284  {
1285  FIntVector NumTiles = LargeMapManager->GetNumTilesInXY();
1286  // WorldSize = FVector(NumTiles) * LargeMap->GetTileSize();
1287  // UE_LOG(LogCarla, Log,
1288  // TEXT("World Size %s"), *(WorldSize.ToString()));
1289  }
1290  // SparseMap.InitializeMap(HeightMap, UEFrameToSI(Tile0Origin), UEFrameToSI(WorldSize),
1291  // 1.f, MinHeight, MaxHeight, HeightMapScaleFactor.Z);
1292  if (DataAsset)
1293  {
1294  SparseMap.InitializeMap(DataAsset, UEFrameToSI(Tile0Origin), UEFrameToSI(WorldSize),
1295  TileSize, HeightMapScaleFactor.Z);
1296  }
1297  }
1298 #ifdef WITH_PYTORCH
1299  {
1300  TRACE_CPUPROFILER_EVENT_SCOPE(LoadNNModel);
1302  TerramechanicsModel.LoadModel(TCHAR_TO_ANSI(*NeuralModelFile), CUDADevice);
1303  }
1304 #endif
1305 
1306  FString LevelName = GetWorld()->GetMapName();
1307  LevelName.RemoveFromStart(GetWorld()->StreamingLevelsPrefix);
1308 
1309  SavePath = FString(_filesBaseFolder.c_str()) + LevelName + "_Terrain/";
1310  SparseMap.SavePath = SavePath;
1311  // Creating the FileManager
1312  IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
1313  if( FileManager.CreateDirectory(*SavePath)){
1314  UE_LOG(LogCarla, Warning,
1315  TEXT("Folder was created at %s"), *SavePath);
1316  }else{
1317  UE_LOG(LogCarla, Error,
1318  TEXT("Folder was not created at %s"), *SavePath);
1319  }
1320 
1321  if(bUseDeformationPlane){
1322  DeformationPlaneActor = GetWorld()->SpawnActor<AStaticMeshActor>();
1323 
1324  if( DeformationPlaneActor )
1325  {
1326  DeformationPlaneActor->GetStaticMeshComponent()->SetStaticMesh( DeformationPlaneMesh );
1327  DeformationPlaneActor->GetStaticMeshComponent()->SetMaterial( 0, DeformationPlaneMaterial );
1328  DeformationPlaneActor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
1329  }
1330  }
1331 
1332  InitTexture();
1333 
1334  UE_LOG(LogCarla, Log, TEXT("MainThread Data ArraySize %d "), Data.Num());
1335  UE_LOG(LogCarla, Log, TEXT("Map Size %d "), SparseMap.Map.size() );
1336 
1337  if (TilesWorker == nullptr)
1338  {
1339  TilesWorker = new FTilesWorker(this, GetOwner()->GetActorLocation(), TileRadius.X, TileRadius.Y);
1340  Thread = FRunnableThread::Create(TilesWorker, TEXT("TilesWorker"));
1341  }
1342 
1343 }
1344 
1345 void UCustomTerrainPhysicsComponent::BuildLandscapeHeightMapDataAasset(ALandscapeProxy* Landscape,
1346  int Resolution, FVector MapSize, FString AssetPath, FString AssetName)
1347 {
1348  TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::BuildLandscapeHeightMapTexture);
1349  TArray<float> HeightMap;
1350  HeightMap.Reserve(Resolution*Resolution);
1351  FVector Origin = Landscape->GetActorLocation();
1352  float DeltaX = MapSize.X / Resolution;
1353  float DeltaY = MapSize.Y / Resolution;
1354  for (size_t i = 0; i < Resolution; ++i)
1355  {
1356  float PosX = Origin.X + i*DeltaX;
1357  for (size_t j = 0; j < Resolution; ++j)
1358  {
1359  float PosY = Origin.Y + j*DeltaY;
1360  FVector Location = FVector(PosX, PosY, 0);
1361  float Height = Landscape->GetHeightAtLocation(Location).Get(-1);
1362  HeightMap.Emplace(Height);
1363  }
1364  }
1365  int TextureWidth = Resolution;
1366  int TextureHeight = Resolution;
1367  FString PackageName = AssetPath;
1368  PackageName += AssetName;
1369  UPackage* Package = CreatePackage(NULL, *PackageName);
1370  Package->FullyLoad();
1371 
1372  UHeightMapDataAsset* HeightMapAsset = NewObject<UHeightMapDataAsset>(Package, *AssetName, RF_Public | RF_Standalone | RF_MarkAsRootSet);
1373  HeightMapAsset->AddToRoot();
1374  HeightMapAsset->SizeX = TextureWidth;
1375  HeightMapAsset->SizeY = TextureHeight;
1376  HeightMapAsset->HeightValues = HeightMap;
1377 
1378  Package->MarkPackageDirty();
1379  // FAssetRegistryModule::AssetCreated(NewTexture);
1380 
1381  FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
1382  bool bSaved = UPackage::SavePackage(Package, HeightMapAsset, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, *PackageFileName, GError, nullptr, true, true, SAVE_NoError);
1383 }
1384 
1385 
1386 float UCustomTerrainPhysicsComponent::GetHeightAtLocation(ALandscapeProxy * Landscape, FVector Location)
1387 {
1388  TOptional<float> OptionalHeight = Landscape->GetHeightAtLocation(Location);
1389  if(OptionalHeight.IsSet())
1390  return OptionalHeight.GetValue();
1391  return -1;
1392 }
1393 
1394 void UCustomTerrainPhysicsComponent::EndPlay(const EEndPlayReason::Type EndPlayReason){
1395  Super::EndPlay(EndPlayReason);
1396  if( Thread && TilesWorker){
1397  TilesWorker->bShouldContinue = false;
1398  Thread->WaitForCompletion();
1399  Thread->Kill(false);
1400  delete TilesWorker;
1401  TilesWorker = nullptr;
1402  }
1403 
1404  TRACE_CPUPROFILER_EVENT_SCOPE(FSparseHighDetailMap::SaveMap);
1405  SparseMap.SaveMap();
1406 }
1407 
1408 void UCustomTerrainPhysicsComponent::TickComponent(float DeltaTime,
1409  ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
1410 {
1411  TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::TickComponent);
1412  Super::TickComponent(DeltaTime,TickType,ThisTickFunction);
1413 
1414  TArray<AActor*> VehiclesActors;
1415  UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACarlaWheeledVehicle::StaticClass(), VehiclesActors);
1416  UCarlaEpisode* Episode = UCarlaStatics::GetCurrentEpisode(GetWorld());
1417  for (AActor* VehicleActor : VehiclesActors)
1418  {
1419 
1420  ACarlaWheeledVehicle* Vehicle = Cast<ACarlaWheeledVehicle> (VehicleActor);
1421  FCarlaActor* CarlaActor = Episode->FindCarlaActor(Vehicle);
1422  if (!CarlaActor)
1423  {
1424  continue;
1425  }
1426  const FActorInfo* ActorInfo = CarlaActor->GetActorInfo();
1427  const FActorDescription& Description = ActorInfo->Description;
1428  const FActorAttribute* Attribute = Description.Variations.Find("terramechanics");
1429  // If the vehicle has terramechanics enabled
1430  if(!Attribute || !UActorBlueprintFunctionLibrary::ActorAttributeToBool(*Attribute, false))
1431  {
1432  continue;
1433  }
1434 
1435  FVector GlobalLocation = Vehicle->GetActorLocation();
1436  if(LargeMapManager)
1437  {
1438  GlobalLocation = LargeMapManager->LocalToGlobalLocation(Vehicle->GetActorLocation());
1439 
1440  uint64_t TileId = LargeMapManager->GetTileID(GlobalLocation);
1441  FIntVector CurrentTileId =
1442  LargeMapManager->GetTileVectorID(GlobalLocation);
1443  if(CurrentLargeMapTileId != CurrentTileId)
1444  {
1445  //load new height map
1446  FCarlaMapTile* LargeMapTile = LargeMapManager->GetCarlaMapTile(TileId);
1447  if(LargeMapTile)
1448  {
1449  CurrentLargeMapTileId = CurrentTileId;
1450  FString FullTileNamePath = LargeMapTile->Name;
1451  FString TileDirectory;
1452  FString TileName;
1453  FString Extension;
1454  FPaths::Split(FullTileNamePath, TileDirectory, TileName, Extension);
1455  FString AssetPath = TileDirectory + "/HeightMaps/" + TileName + "." + TileName;
1456  UE_LOG(LogCarla, Log, TEXT("Enter tile %s, %s \n %s \n %s \n %s"), *CurrentTileId.ToString(),
1457  *FullTileNamePath, *TileDirectory, *TileName, *Extension);
1458 
1459  UObject* DataAssetObject = StaticLoadObject(UHeightMapDataAsset::StaticClass(), nullptr, *(AssetPath));
1460  if(DataAssetObject)
1461  {
1462  UHeightMapDataAsset* HeightMapDataAsset = Cast<UHeightMapDataAsset>(DataAssetObject);
1463  if (HeightMapDataAsset != nullptr)
1464  {
1465  FVector TilePosition = HeightMapOffset + LargeMapManager->GetTileLocation(CurrentLargeMapTileId) - 0.5f*FVector(LargeMapManager->GetTileSize(), -LargeMapManager->GetTileSize(), 0);
1466  UE_LOG(LogCarla, Log, TEXT("Updating height map to location %s in tile location %s"),
1467  *TilePosition.ToString(), *LargeMapManager->GetTileLocation(CurrentLargeMapTileId).ToString());
1468  TilePosition.Z += UEFrameToSI(FloorHeight) ;
1469  SparseMap.UpdateHeightMap(
1470  HeightMapDataAsset, UEFrameToSI(TilePosition), UEFrameToSI(FVector(
1471  LargeMapManager->GetTileSize(),-LargeMapManager->GetTileSize(), 0)),
1472  1.f, HeightMapScaleFactor.Z);
1473  }
1474  }
1475  }
1476  else
1477  {/*
1478  UE_LOG(LogCarla, Log, TEXT("Tile not found %s %s"),
1479  *GlobalLocation.ToString(), *CurrentTileId.ToString());
1480  */
1481  }
1482  }
1483  }
1484 
1485  SparseMap.LockMutex();
1486  RunNNPhysicsSimulation(Vehicle, DeltaTime);
1487  LastUpdatedPosition = GlobalLocation;
1488  SparseMap.UnLockMutex();
1489 
1490  if (bDrawLoadedTiles)
1491  {
1492  DrawTiles(GetWorld(), SparseMap.GetTileIdInMap(), GlobalLocation.Z + 300, FLinearColor(0.0,0.0,1.0,0.0));
1493  DrawTiles(GetWorld(), SparseMap.GetTileIdInCache(), GlobalLocation.Z + 300, FLinearColor(1.0,0.0,0.0,0.0));
1494  }
1495 
1496  if( MPCInstance == nullptr )
1497  {
1498  if(MPC){
1499  MPCInstance = GetWorld()->GetParameterCollectionInstance( MPC );
1500  }
1501  }
1502 
1503  if( MPCInstance ){
1504  MPCInstance->SetVectorParameterValue("PositionToUpdate", GetTileCenter(LastUpdatedPosition));
1505  // We set texture radius in cm as is UE4 default measure unit
1506  MPCInstance->SetScalarParameterValue("TextureRadius", TextureRadius * 100);
1507  MPCInstance->SetScalarParameterValue("LargeTextureRadius", TextureRadius * 100);
1508  MPCInstance->SetScalarParameterValue("EffectMultiplayer", EffectMultiplayer);
1509  MPCInstance->SetScalarParameterValue("MinDisplacement", MinDisplacement);
1510  MPCInstance->SetScalarParameterValue("MaxDisplacement", MinDisplacement);
1511  if(TextureToUpdate){
1512  MPCInstance->SetScalarParameterValue("TexSizeX", TextureToUpdate->GetSizeX());
1513  }
1514  }
1515 
1516  if(bUseDeformationPlane){
1517  if( DeformationPlaneActor ){
1518  DeformationPlaneActor->SetActorLocation(LastUpdatedPosition, false, nullptr);
1519  }else{
1520  DeformationPlaneActor = GetWorld()->SpawnActor<AStaticMeshActor>();
1521 
1522  if( DeformationPlaneActor )
1523  {
1524  DeformationPlaneActor->GetStaticMeshComponent()->SetStaticMesh( DeformationPlaneMesh );
1525  DeformationPlaneActor->GetStaticMeshComponent()->SetMaterial( 0, DeformationPlaneMaterial );
1526  DeformationPlaneActor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
1527  }
1528  }
1529  }
1530  }
1531 
1532  if (bDrawHeightMap)
1533  {
1534  TRACE_CPUPROFILER_EVENT_SCOPE(DrawHeightMap);
1535  float LifeTime = 0.3f;
1536  bool bPersistentLines = false;
1537  bool bDepthIsForeground = (0 == SDPG_Foreground);
1538  UWorld* World = GetWorld();
1539  ULineBatchComponent* LineBatcher =
1540  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
1541  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
1542  if (!LineBatcher)
1543  {
1544  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
1545  }
1546 
1547  float DrawPos_X = DrawStart.X;
1548  float DrawPos_Y = DrawStart.Y;
1549  for (DrawPos_X = DrawStart.X; DrawPos_X < DrawEnd.X; DrawPos_X += DrawInterval.X)
1550  {
1551  for (DrawPos_Y = DrawStart.Y; DrawPos_Y < DrawEnd.Y; DrawPos_Y += DrawInterval.Y)
1552  {
1553  float Height = SparseMap.GetHeight(UEFrameToSI(FVector(DrawPos_X, DrawPos_Y, 0)));
1554  FVector Point = FVector(DrawPos_X, DrawPos_Y, SIToUEFrame(Height));
1555  if(LargeMapManager)
1556  {
1557  Point = LargeMapManager->GlobalToLocalLocation(Point);
1558  }
1559  LineBatcher->DrawPoint(Point,
1560  FLinearColor(1.f, 0.f, 0.f), 10.0, 0, LifeTime);
1561 
1562  }
1563  }
1564  }
1565 }
1566 
1567 void UCustomTerrainPhysicsComponent::DrawParticles(UWorld* World, std::vector<FParticle*>& Particles,
1568  FLinearColor Color)
1569 {
1570  float LifeTime = 0.3f;
1571  bool bPersistentLines = false;
1572  bool bDepthIsForeground = (0 == SDPG_Foreground);
1573  ULineBatchComponent* LineBatcher =
1574  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
1575  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
1576  if (!LineBatcher)
1577  {
1578  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
1579  }
1580  for(FParticle* Particle : Particles)
1581  {
1582  // DrawDebugPoint(World, MToCM*Particle->Position.ToFVector(),
1583  // 1.0, FColor(255,0,0), false, 0.3, 0);
1584  FVector Point = SIToUEFrame(Particle->Position.ToFVector());
1585  if(LargeMapManager)
1586  {
1587  Point = LargeMapManager->GlobalToLocalLocation(Point);
1588  }
1589  LineBatcher->DrawPoint(Point,
1590  Color, 1.0, 0, LifeTime);
1591  }
1592 }
1593 
1594 void UCustomTerrainPhysicsComponent::DrawParticlesArray(UWorld* World, TArray<float>& ParticlesArray,
1595  FLinearColor Color)
1596 {
1597  float LifeTime = 0.3f;
1598  bool bPersistentLines = false;
1599  bool bDepthIsForeground = (0 == SDPG_Foreground);
1600  ULineBatchComponent* LineBatcher =
1601  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
1602  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
1603  if (!LineBatcher)
1604  {
1605  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
1606  }
1607  for(int i = 0; i < ParticlesArray.Num(); i+=3)
1608  {
1609  FVector Position = FVector(ParticlesArray[i+0], ParticlesArray[i+1], ParticlesArray[i+2]);
1610  // DrawDebugPoint(World, MToCM*Particle->Position.ToFVector(),
1611  // 1.0, FColor(255,0,0), false, 0.3, 0);
1612  FVector Point = SIToUEFrame(Position);
1613  LineBatcher->DrawPoint(Point,
1614  Color, 1.0, 0, LifeTime);
1615  }
1616 }
1617 
1618 void UCustomTerrainPhysicsComponent::DrawOrientedBox(UWorld* World, const TArray<FOrientedBox>& Boxes)
1619 {
1620  float LifeTime = 0.3f;
1621  bool bPersistentLines = false;
1622  bool bDepthIsForeground = (0 == SDPG_Foreground);
1623  float Thickness = 2.0f;
1624  ULineBatchComponent* LineBatcher =
1625  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
1626  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
1627  if (!LineBatcher)
1628  {
1629  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
1630  }
1631  for (const FOrientedBox& OBox : Boxes)
1632  {
1633  TArray<FVector> Vertices;
1634  Vertices.SetNum(8);
1635  OBox.CalcVertices(&Vertices[0]);
1636  if(LargeMapManager)
1637  {
1638  for(FVector& Point : Vertices)
1639  {
1640  Point = LargeMapManager->GlobalToLocalLocation(Point);
1641  }
1642  }
1643  LineBatcher->DrawLines({
1644  FBatchedLine(Vertices[0], Vertices[1],
1645  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1646  FBatchedLine(Vertices[0], Vertices[2],
1647  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1648  FBatchedLine(Vertices[2], Vertices[3],
1649  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1650  FBatchedLine(Vertices[3], Vertices[1],
1651  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1652 
1653  FBatchedLine(Vertices[4], Vertices[5],
1654  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1655  FBatchedLine(Vertices[4], Vertices[6],
1656  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1657  FBatchedLine(Vertices[6], Vertices[7],
1658  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1659  FBatchedLine(Vertices[7], Vertices[5],
1660  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1661 
1662  FBatchedLine(Vertices[0], Vertices[4],
1663  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1664  FBatchedLine(Vertices[1], Vertices[5],
1665  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1666  FBatchedLine(Vertices[2], Vertices[6],
1667  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0),
1668  FBatchedLine(Vertices[3], Vertices[7],
1669  FLinearColor(0.0,0.0,1.0), LifeTime, Thickness, 0)});
1670  }
1671 }
1672 
1673 void UCustomTerrainPhysicsComponent::DrawTiles(UWorld* World, const std::vector<uint64_t>& TilesIds,float Height,
1674  FLinearColor Color)
1675 {
1676  float LifeTime = 0.3f;
1677  bool bPersistentLines = false;
1678  bool bDepthIsForeground = (0 == SDPG_Foreground);
1679  float Thickness = 2.0f;
1680  ULineBatchComponent* LineBatcher =
1681  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
1682  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
1683  if (!LineBatcher)
1684  {
1685  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
1686  }
1687  // UE_LOG(LogCarla, Log, TEXT("Drawing %d Tiles"), TilesIds.size());
1688  for (const uint64_t& TileId : TilesIds)
1689  {
1690  FVector TileCenter = SparseMap.GetTilePosition(TileId).ToFVector();
1691  FVector V1 = SIToUEFrame(TileCenter);
1692  FVector V2 = SIToUEFrame(TileCenter + FVector(SparseMap.GetTileSize(),0,0));
1693  FVector V3 = SIToUEFrame(TileCenter + FVector(0,SparseMap.GetTileSize(),0));
1694  FVector V4 = SIToUEFrame(TileCenter + FVector(SparseMap.GetTileSize(),SparseMap.GetTileSize(),0));
1695  if(LargeMapManager)
1696  {
1697  V1 = LargeMapManager->GlobalToLocalLocation(V1);
1698  V2 = LargeMapManager->GlobalToLocalLocation(V2);
1699  V3 = LargeMapManager->GlobalToLocalLocation(V3);
1700  V4 = LargeMapManager->GlobalToLocalLocation(V4);
1701  }
1702  V1.Z = Height;
1703  V2.Z = Height;
1704  V3.Z = Height;
1705  V4.Z = Height;
1706  LineBatcher->DrawLines({
1707  FBatchedLine(V1, V2,
1708  Color, LifeTime, Thickness, 0),
1709  FBatchedLine(V2, V4,
1710  Color, LifeTime, Thickness, 0),
1711  FBatchedLine(V1, V3,
1712  Color, LifeTime, Thickness, 0),
1713  FBatchedLine(V3, V4,
1714  Color, LifeTime, Thickness, 0)});
1715  // UE_LOG(LogCarla, Log, TEXT("Drawing Tile %ld with verts %s, %s, %s, %s"),
1716  // TileId, *V1.ToString(), *V2.ToString(), *V3.ToString(), *V4.ToString());
1717  }
1718 }
1719 
1720 void UCustomTerrainPhysicsComponent::LimitParticlesPerWheel(std::vector<FParticle*> &Particles)
1721 {
1722  TRACE_CPUPROFILER_EVENT_SCOPE(LimitParticlesPerWheel);
1723  if (Particles.size() < MaxParticlesPerWheel)
1724  {
1725  return;
1726  }
1727  std::sort(Particles.begin(), Particles.end(), [&](FParticle* P1, FParticle* P2) -> bool
1728  {
1729  return P1->Position.Z > P2->Position.Z;
1730  });
1731  Particles.resize(MaxParticlesPerWheel);
1732 }
1733 
1734 void UCustomTerrainPhysicsComponent::GenerateBenchmarkParticles(std::vector<FParticle>& BenchParticles,
1735  std::vector<FParticle*> &ParticlesWheel0, std::vector<FParticle*> &ParticlesWheel1,
1736  std::vector<FParticle*> &ParticlesWheel2, std::vector<FParticle*> &ParticlesWheel3,
1737  FOrientedBox &BboxWheel0, FOrientedBox &BboxWheel1,
1738  FOrientedBox &BboxWheel2, FOrientedBox &BboxWheel3)
1739 {
1740  TRACE_CPUPROFILER_EVENT_SCOPE(GenerateBenchmarkParticles);
1741  BenchParticles.reserve(100000);
1742  auto GenerateBoxParticles = [&](FOrientedBox &BboxWheel, std::vector<FParticle*> &ParticlesWheel)
1743  {
1744  ParticlesWheel.clear();
1745  FVector TileOrigin = FVector(0,0,0);
1746  FVector BoxSize = FVector(2*BboxWheel.ExtentX, 2*BboxWheel.ExtentY, BboxWheel.ExtentZ);
1747  uint32_t NumParticles_X = BoxSize.X / ParticleDiameter;
1748  uint32_t NumParticles_Y = BoxSize.Y / ParticleDiameter;
1749  uint32_t NumParticles_Z = BoxSize.Z / ParticleDiameter;
1750  UE_LOG(LogCarla, Log, TEXT("Generating (%d,%d,%d) particles"),
1751  NumParticles_X,NumParticles_Y,NumParticles_Z);
1752  for(uint32_t i = 0; i < NumParticles_X; i++)
1753  {
1754  float XPos = i*ParticleDiameter;
1755  for(uint32_t j = 0; j < NumParticles_Y; j++)
1756  {
1757  float YPos = j*ParticleDiameter;
1758  for(uint32_t k = 0; k < NumParticles_Z; k++)
1759  {
1760  float ZPos = k*ParticleDiameter;
1761  FVector ParticlePosition = TileOrigin + FVector(XPos, YPos, ZPos);
1762  ParticlePosition = (ParticlePosition.X - BboxWheel.ExtentX) * BboxWheel0.AxisX +
1763  (ParticlePosition.Y - BboxWheel.ExtentY) * BboxWheel0.AxisY +
1764  (ParticlePosition.Z - BboxWheel.ExtentZ) * BboxWheel0.AxisZ + BboxWheel.Center;
1765  ParticlePosition = UEFrameToSI(ParticlePosition);
1766  BenchParticles.emplace_back(FParticle{ParticlePosition, FVector(0), ParticleDiameter/2.f});
1767  ParticlesWheel.emplace_back(&BenchParticles.back());
1768  }
1769  }
1770  }
1771  };
1772  GenerateBoxParticles(BboxWheel0, ParticlesWheel0);
1773  GenerateBoxParticles(BboxWheel1, ParticlesWheel1);
1774  GenerateBoxParticles(BboxWheel2, ParticlesWheel2);
1775  GenerateBoxParticles(BboxWheel3, ParticlesWheel3);
1776 
1777  UE_LOG(LogCarla, Log, TEXT("Generated %d particles"), BenchParticles.size());
1778 }
1779 
1780 void UCustomTerrainPhysicsComponent::RunNNPhysicsSimulation(
1781  ACarlaWheeledVehicle *Vehicle, float DeltaTime)
1782 {
1783  TRACE_CPUPROFILER_EVENT_SCOPE(RunNNPhysicsSimulation);
1784  #ifdef WITH_PYTORCH
1785  FTransform VehicleTransform = Vehicle->GetTransform();
1786  FTransform WheelTransform0 = VehicleTransform;
1787  FTransform WheelTransform1 = VehicleTransform;
1788  FTransform WheelTransform2 = VehicleTransform;
1789  FTransform WheelTransform3 = VehicleTransform;
1790  FVector WheelPosition0 = VehicleTransform.TransformPosition(FVector(140, -70, 40));
1791  FVector WheelPosition1 = VehicleTransform.TransformPosition(FVector(140, 70, 40));
1792  FVector WheelPosition2 = VehicleTransform.TransformPosition(FVector(-140, -70, 40));
1793  FVector WheelPosition3 = VehicleTransform.TransformPosition(FVector(-140, 70, 40));
1794  WheelTransform0.SetLocation(WheelPosition0);
1795  WheelTransform1.SetLocation(WheelPosition1);
1796  WheelTransform2.SetLocation(WheelPosition2);
1797  WheelTransform3.SetLocation(WheelPosition3);
1798  if(LargeMapManager)
1799  {
1800  WheelPosition0 = LargeMapManager->LocalToGlobalLocation(WheelPosition0);
1801  WheelPosition1 = LargeMapManager->LocalToGlobalLocation(WheelPosition1);
1802  WheelPosition2 = LargeMapManager->LocalToGlobalLocation(WheelPosition2);
1803  WheelPosition3 = LargeMapManager->LocalToGlobalLocation(WheelPosition3);
1804  }
1805  FOrientedBox BboxWheel0;
1806  BboxWheel0.AxisX = VehicleTransform.GetUnitAxis(EAxis::X);
1807  BboxWheel0.AxisY = VehicleTransform.GetUnitAxis(EAxis::Y);
1808  BboxWheel0.AxisZ = VehicleTransform.GetUnitAxis(EAxis::Z);
1809  BboxWheel0.Center = WheelPosition0 + FVector(0,0,-TireRadius);
1810  BboxWheel0.ExtentX = BoxSearchForwardDistance;
1811  BboxWheel0.ExtentY = BoxSearchLateralDistance;
1812  BboxWheel0.ExtentZ = BoxSearchDepthDistance;
1813  FOrientedBox BboxWheel1 = BboxWheel0;
1814  BboxWheel1.Center = WheelPosition1 + FVector(0,0,-TireRadius);
1815  FOrientedBox BboxWheel2 = BboxWheel0;
1816  BboxWheel2.Center = WheelPosition2 + FVector(0,0,-TireRadius);
1817  FOrientedBox BboxWheel3 = BboxWheel0;
1818  BboxWheel3.Center = WheelPosition3 + FVector(0,0,-TireRadius);
1819  if (DrawDebugInfo)
1820  {
1821  DrawOrientedBox(GetWorld(), {BboxWheel0, BboxWheel1, BboxWheel2, BboxWheel3});
1822  }
1823 
1824  std::vector<FParticle*> ParticlesWheel0, ParticlesWheel1, ParticlesWheel2, ParticlesWheel3;
1825  {
1826  TRACE_CPUPROFILER_EVENT_SCOPE(ParticleSearch);
1827  auto GetAndFilterParticlesInBox =
1828  [&] (FOrientedBox& OBox) -> std::vector<FParticle*>
1829  {
1830  std::vector<FParticle*> Particles;
1831  Particles = SparseMap.GetParticlesInBox(OBox);
1832  LimitParticlesPerWheel(Particles);
1833  return Particles;
1834  };
1835  auto FutureParticles0 = Async(EAsyncExecution::ThreadPool,
1836  [&]() {return GetAndFilterParticlesInBox(BboxWheel0);});
1837  auto FutureParticles2 = Async(EAsyncExecution::ThreadPool,
1838  [&]() {return GetAndFilterParticlesInBox(BboxWheel2);});
1839  auto FutureParticles1 = Async(EAsyncExecution::ThreadPool,
1840  [&]() {return GetAndFilterParticlesInBox(BboxWheel1);});
1841  auto FutureParticles3 = Async(EAsyncExecution::ThreadPool,
1842  [&]() {return GetAndFilterParticlesInBox(BboxWheel3);});
1843  ParticlesWheel0 = FutureParticles0.Get();
1844  ParticlesWheel2 = FutureParticles2.Get();
1845  ParticlesWheel1 = FutureParticles1.Get();
1846  ParticlesWheel3 = FutureParticles3.Get();
1847  }
1848 
1849  std::vector<FParticle> BenchParticles;
1850  if(bBenchMark)
1851  {
1852  GenerateBenchmarkParticles(BenchParticles,
1853  ParticlesWheel0, ParticlesWheel1, ParticlesWheel2, ParticlesWheel3,
1854  BboxWheel0, BboxWheel1, BboxWheel2, BboxWheel3);
1855  UE_LOG(LogCarla, Log, TEXT("Generated %d particles"), BenchParticles.size());
1856  }
1857 
1858  if(DrawDebugInfo)
1859  {
1860  DrawParticles(GetWorld(), ParticlesWheel0);
1861  DrawParticles(GetWorld(), ParticlesWheel1);
1862  DrawParticles(GetWorld(), ParticlesWheel2);
1863  DrawParticles(GetWorld(), ParticlesWheel3);
1864  DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel0), BboxWheel0.Center.Z);
1865  DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel1), BboxWheel1.Center.Z);
1866  DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel2), BboxWheel2.Center.Z);
1867  DrawTiles(GetWorld(), SparseMap.GetIntersectingTiles(BboxWheel3), BboxWheel3.Center.Z);
1868  }
1869 
1870  TArray<float> ParticlePos0, ParticleVel0, ParticlePos1, ParticleVel1,
1871  ParticlePos2, ParticleVel2, ParticlePos3, ParticleVel3;
1872  TArray<float> WheelPos0, WheelOrient0, WheelLinVel0, WheelAngVel0;
1873  TArray<float> WheelPos1, WheelOrient1, WheelLinVel1, WheelAngVel1;
1874  TArray<float> WheelPos2, WheelOrient2, WheelLinVel2, WheelAngVel2;
1875  TArray<float> WheelPos3, WheelOrient3, WheelLinVel3, WheelAngVel3;
1876  {
1877  TRACE_CPUPROFILER_EVENT_SCOPE(SetUpArrays);
1878  SetUpParticleArrays(ParticlesWheel0, ParticlePos0, ParticleVel0, WheelTransform0);
1879  SetUpParticleArrays(ParticlesWheel1, ParticlePos1, ParticleVel1, WheelTransform1);
1880  SetUpParticleArrays(ParticlesWheel2, ParticlePos2, ParticleVel2, WheelTransform2);
1881  SetUpParticleArrays(ParticlesWheel3, ParticlePos3, ParticleVel3, WheelTransform3);
1882 
1883  SetUpWheelArrays(Vehicle, 0, WheelPos0, WheelOrient0, WheelLinVel0, WheelAngVel0);
1884  SetUpWheelArrays(Vehicle, 1, WheelPos1, WheelOrient1, WheelLinVel1, WheelAngVel1);
1885  SetUpWheelArrays(Vehicle, 2, WheelPos2, WheelOrient2, WheelLinVel2, WheelAngVel2);
1886  SetUpWheelArrays(Vehicle, 3, WheelPos3, WheelOrient3, WheelLinVel3, WheelAngVel3);
1887  }
1888 
1890  static_cast<int>(ParticlesWheel0.size()),
1891  ParticlePos0.GetData(), ParticleVel0.GetData(),
1892  WheelPos0.GetData(), WheelOrient0.GetData(),
1893  WheelLinVel0.GetData(), WheelAngVel0.GetData()};
1895  static_cast<int>(ParticlesWheel1.size()),
1896  ParticlePos1.GetData(), ParticleVel1.GetData(),
1897  WheelPos1.GetData(), WheelOrient1.GetData(),
1898  WheelLinVel1.GetData(), WheelAngVel1.GetData()};
1900  static_cast<int>(ParticlesWheel2.size()),
1901  ParticlePos2.GetData(), ParticleVel2.GetData(),
1902  WheelPos2.GetData(), WheelOrient2.GetData(),
1903  WheelLinVel2.GetData(), WheelAngVel2.GetData()};
1905  static_cast<int>(ParticlesWheel3.size()),
1906  ParticlePos3.GetData(), ParticleVel3.GetData(),
1907  WheelPos3.GetData(), WheelOrient3.GetData(),
1908  WheelLinVel3.GetData(), WheelAngVel3.GetData()};
1909 
1910  const FVehicleControl& VehicleControl = Vehicle->GetVehicleControl();
1911  ASoilTypeManager* SoilTypeManagerActor = Cast<ASoilTypeManager>(UGameplayStatics::GetActorOfClass(GetWorld(), ASoilTypeManager::StaticClass()));
1912  if(SoilTypeManagerActor)
1913  {
1914  FSoilTerramechanicsProperties TerramechanicsProperties =
1915  SoilTypeManagerActor->GetTerrainPropertiesAtGlobalLocation(WheelPosition0);
1916 
1917  switch(TerramechanicsProperties.TerrainType){
1919  SoilType = 0;
1920  break;
1922  SoilType = 1;
1923  break;
1924  default:
1925  SoilType = 0;
1926  }
1927 
1928  }
1929  carla::learning::Inputs NNInput {Wheel0,Wheel1,Wheel2,Wheel3,
1930  VehicleControl.Steer, VehicleControl.Throttle, VehicleControl.Brake,
1931  SoilType, NNVerbose};
1932  if (!bUseSoilType)
1933  {
1934  NNInput.terrain_type = -1;
1935  }
1936  if (VehicleControl.bReverse)
1937  {
1938  NNInput.throttle *= -1;
1939  }
1940  TerramechanicsModel.SetInputs(NNInput);
1941  {
1942  TRACE_CPUPROFILER_EVENT_SCOPE(RunModel);
1943  if(bUseCUDAModel)
1944  {
1945  TerramechanicsModel.ForwardCUDATensors();
1946  }
1947  else if(bUseDynamicModel)
1948  {
1949  TerramechanicsModel.ForwardDynamic();
1950  }
1951  else
1952  {
1953  TerramechanicsModel.Forward();
1954  }
1955  }
1956  carla::learning::Outputs& Output = TerramechanicsModel.GetOutputs();
1957 
1958  if(bUpdateParticles)
1959  {
1960  {
1961  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
1962  FScopeLock ScopeLock(&SparseMap.Lock_Particles);
1963  auto UpdateFutureParticles =
1964  [&] (std::vector<FParticle*>& Particles, std::vector<float>& Forces, float DeltaTime,
1965  const FTransform& WheelTransform)
1966  {
1967  UpdateParticles( Particles, Forces, DeltaTime, WheelTransform );
1968  };
1969  UpdateFutureParticles(
1970  ParticlesWheel0, Output.wheel0._particle_forces, DeltaTime, WheelTransform0);
1971  UpdateFutureParticles(
1972  ParticlesWheel1, Output.wheel1._particle_forces, DeltaTime, WheelTransform1);
1973  UpdateFutureParticles(
1974  ParticlesWheel2, Output.wheel2._particle_forces, DeltaTime, WheelTransform2);
1975  UpdateFutureParticles(
1976  ParticlesWheel3, Output.wheel3._particle_forces, DeltaTime, WheelTransform3);
1977  }
1978  if (DrawDebugInfo)
1979  {
1980  FLinearColor Color(1.0,0.0,1.0,1.0);
1981  DrawParticles(GetWorld(), ParticlesWheel0, Color);
1982  DrawParticles(GetWorld(), ParticlesWheel1, Color);
1983  DrawParticles(GetWorld(), ParticlesWheel2, Color);
1984  DrawParticles(GetWorld(), ParticlesWheel3, Color);
1985  }
1986  }
1987 
1988  if(bUseMeanAcceleration)
1989  {
1990  ApplyMeanAccelerationToVehicle(Vehicle,
1991  ForceMulFactor*SIToUEFrame(FVector(
1992  Output.wheel0.wheel_forces_x,
1993  Output.wheel0.wheel_forces_y,
1994  Output.wheel0.wheel_forces_z)),
1995  ForceMulFactor*SIToUEFrame(FVector(
1996  Output.wheel1.wheel_forces_x,
1997  Output.wheel1.wheel_forces_y,
1998  Output.wheel1.wheel_forces_z)),
1999  ForceMulFactor*SIToUEFrame(FVector(
2000  Output.wheel2.wheel_forces_x,
2001  Output.wheel2.wheel_forces_y,
2002  Output.wheel2.wheel_forces_z)),
2003  ForceMulFactor*SIToUEFrame(FVector(
2004  Output.wheel3.wheel_forces_x,
2005  Output.wheel3.wheel_forces_y,
2006  Output.wheel3.wheel_forces_z)));
2007  }
2008  else
2009  {
2010  ApplyForcesToVehicle(Vehicle,
2011  ForceMulFactor*SIToUEFrame(FVector(
2012  Output.wheel0.wheel_forces_x,
2013  Output.wheel0.wheel_forces_y,
2014  Output.wheel0.wheel_forces_z)),
2015  ForceMulFactor*SIToUEFrame(FVector(
2016  Output.wheel1.wheel_forces_x,
2017  Output.wheel1.wheel_forces_y,
2018  Output.wheel1.wheel_forces_z)),
2019  ForceMulFactor*SIToUEFrame(FVector(
2020  Output.wheel2.wheel_forces_x,
2021  Output.wheel2.wheel_forces_y,
2022  Output.wheel2.wheel_forces_z)),
2023  ForceMulFactor*SIToUEFrame(FVector(
2024  Output.wheel3.wheel_forces_x,
2025  Output.wheel3.wheel_forces_y,
2026  Output.wheel3.wheel_forces_z)),
2027  ForceMulFactor*MToCM*SIToUEFrame(FVector(
2028  Output.wheel0.wheel_torque_x,
2029  Output.wheel0.wheel_torque_y,
2030  Output.wheel0.wheel_torque_z)),
2031  ForceMulFactor*MToCM*SIToUEFrame(FVector(
2032  Output.wheel1.wheel_torque_x,
2033  Output.wheel1.wheel_torque_y,
2034  Output.wheel1.wheel_torque_z)),
2035  ForceMulFactor*MToCM*SIToUEFrame(FVector(
2036  Output.wheel2.wheel_torque_x,
2037  Output.wheel2.wheel_torque_y,
2038  Output.wheel2.wheel_torque_z)),
2039  ForceMulFactor*MToCM*SIToUEFrame(FVector(
2040  Output.wheel3.wheel_torque_x,
2041  Output.wheel3.wheel_torque_y,
2042  Output.wheel3.wheel_torque_z)));
2043  }
2044  #endif
2045 }
2046 
2047 void UCustomTerrainPhysicsComponent::UpdateParticles(
2048  std::vector<FParticle*> Particles, std::vector<float> Forces,
2049  float DeltaTime, const FTransform& WheelTransform)
2050 {
2051  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
2052  //UE_LOG(LogCarla, Log, TEXT("%d vs %d"), Particles.size(), Forces.size()/3);
2053  if(bUseLocalFrame)
2054  {
2055  for (size_t i = 0; i < Particles.size(); i++)
2056  {
2057  FVector Force = FVector(Forces[3*i + 0], Forces[3*i + 1], Forces[3*i + 2]) * ParticleForceMulFactor;
2058  FVector LocalAcceleration = Force;
2059  FVector UELocalAcceleration = SIToUEFrame(LocalAcceleration);
2060  FVector UEGlobalAcceleration = WheelTransform.TransformVector(UELocalAcceleration);
2061  FVector Acceleration = UEFrameToSI(UEGlobalAcceleration);
2062  FParticle* P = Particles[i];
2063  P->Velocity = P->Velocity + Acceleration*DeltaTime;
2064  P->Position = P->Position + P->Velocity*DeltaTime;
2065  }
2066  }
2067  else
2068  {
2069  for (size_t i = 0; i < Particles.size(); i++)
2070  {
2071  FVector Force = FVector(Forces[3*i + 0], Forces[3*i + 1], Forces[3*i + 2]) * ParticleForceMulFactor;
2072  FParticle* P = Particles[i];
2073  FVector Acceleration = Force;
2074  P->Velocity = P->Velocity + Acceleration*DeltaTime;
2075  P->Position = P->Position + P->Velocity*DeltaTime;
2076  }
2077  }
2078 }
2079 
2080 void UCustomTerrainPhysicsComponent::UpdateParticlesDebug( std::vector<FParticle*> Particles)
2081 {
2082  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateParticles);
2083  float DeltaTime = GetWorld()->GetDeltaSeconds();
2084  for (size_t i = 0; i < Particles.size(); i++)
2085  {
2086  FVector Force = FVector( 0, 0, FMath::RandRange(-1.0f, 1.0f));
2087  FParticle* P = Particles[i];
2088  FVector Acceleration = Force;
2089  P->Velocity = P->Velocity + Acceleration*DeltaTime;
2090  P->Position = P->Position + P->Velocity*DeltaTime;
2091  }
2092 }
2093 
2094 void UCustomTerrainPhysicsComponent::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
2095 {
2096  if( bRemoveLandscapeColliders )
2097  {
2098  for(auto CurrentActor : InLevel->Actors)
2099  {
2100  if( ALandscape* CurrentLandscape = Cast<ALandscape>( CurrentActor ) )
2101  {
2102  CurrentLandscape->BodyInstance.ReplaceResponseToChannels( ECollisionResponse::ECR_Block, ECollisionResponse::ECR_Ignore );
2103  CurrentLandscape->BodyInstance.ReplaceResponseToChannels( ECollisionResponse::ECR_Overlap, ECollisionResponse::ECR_Ignore );
2104  CurrentLandscape->BodyInstance.SetCollisionEnabled( ECollisionEnabled::Type::NoCollision, true);
2105 
2106  for(auto CurrentCollision : CurrentLandscape->CollisionComponents){
2107  CurrentCollision->SetCollisionResponseToAllChannels( ECollisionResponse::ECR_Ignore );
2108  CurrentCollision->SetCollisionEnabled( ECollisionEnabled::Type::NoCollision );
2109 
2110  }
2111 
2112  for(auto CurrentComponent : CurrentLandscape->LandscapeComponents){
2113  CurrentComponent->SetCollisionResponseToAllChannels( ECollisionResponse::ECR_Ignore );
2114  CurrentComponent->SetCollisionEnabled( ECollisionEnabled::Type::NoCollision );
2115 
2116  }
2117  }
2118  }
2119  }
2120 }
2121 
2122 void UCustomTerrainPhysicsComponent::UpdateTilesHeightMaps(
2123  const std::vector<FParticle*>& Particles)
2124 {
2125  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateTilesHeightMaps);
2126 
2127  uint32_t PartialHeightMapSize =
2128  SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2129  float InverseTileSize = 1.f/SparseMap.GetTileSize();
2130  float Transformation = InverseTileSize * PartialHeightMapSize;
2131  float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2132  for (size_t i = 0; i < Particles.size(); i++)
2133  {
2134  const FParticle* P = Particles[i];
2135  uint64_t TileId = SparseMap.GetTileId(P->Position);
2136  FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2137  FDVector TilePosition = CurrentTile.TilePosition;
2138  FDVector ParticleLocalPosition = P->Position - TilePosition;
2139  FIntVector HeightMapCoords = FIntVector(
2140  ParticleLocalPosition.X * Transformation,
2141  ParticleLocalPosition.Y * Transformation, 0);
2142 
2143  HeightMapCoords.X = std::min( std::max( HeightMapCoords.X, 0) , static_cast<int>(PartialHeightMapSize-1));
2144  HeightMapCoords.Y = std::min( std::max( HeightMapCoords.Y, 0) , static_cast<int>(PartialHeightMapSize-1));
2145  uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2146  // Compare to the current value, if higher replace
2147  if( P->Position.Z > CurrentTile.ParticlesHeightMap[Index] )
2148  CurrentTile.ParticlesHeightMap[Index] = P->Position.Z;
2149  }
2150 }
2151 
2152 void UCustomTerrainPhysicsComponent::RemoveParticlesFromOrderedContainer(
2153  const std::vector<FParticle*>& Particles)
2154 {
2155  TRACE_CPUPROFILER_EVENT_SCOPE(RemoveParticlesFromOrderedContainer);
2156 
2157  uint32_t PartialHeightMapSize =
2158  SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2159  float InverseTileSize = 1.f/SparseMap.GetTileSize();
2160  float Transformation = InverseTileSize * PartialHeightMapSize;
2161  float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2162  for (size_t i = 0; i < Particles.size(); i++)
2163  {
2164  const FParticle* P = Particles[i];
2165  uint64_t TileId = SparseMap.GetTileId(P->Position);
2166  FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2167  CurrentTile.bHeightmapNeedToUpdate = true;
2168  FDVector TilePosition = CurrentTile.TilePosition;
2169  FDVector ParticleLocalPosition = P->Position - TilePosition;
2170  FIntVector HeightMapCoords = FIntVector(
2171  ParticleLocalPosition.X * Transformation,
2172  ParticleLocalPosition.Y * Transformation, 0);
2173 
2174  HeightMapCoords.X = std::min( std::max( HeightMapCoords.X, 0) , static_cast<int>(PartialHeightMapSize-1));
2175  HeightMapCoords.Y = std::min( std::max( HeightMapCoords.Y, 0) , static_cast<int>(PartialHeightMapSize-1));
2176  // uint32_t Index = std::floor(ParticleLocalPosition.Y) * PartialHeightMapSize + std::floor(ParticleLocalPosition.X);
2177  uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2178 
2179  if( Index < CurrentTile.ParticlesZOrdered.size() )
2180  {
2181  if( CurrentTile.ParticlesZOrdered[Index].size() > 1 )
2182  {
2183  auto it = CurrentTile.ParticlesZOrdered[Index].find(P->Position.Z );
2184  if( it != CurrentTile.ParticlesZOrdered[Index].end() )
2185  {
2186  CurrentTile.ParticlesZOrdered[Index].erase(it);
2187  }
2188  else
2189  {
2190  //UE_LOG(LogCarla, Error, TEXT("Cannot find in %d, position %f"), Index, P->Position.Z );
2191  }
2192  }
2193  else
2194  {
2195  UE_LOG(LogCarla, Error, TEXT("Cannot Remove more from %d, currentsize %d Tile : %s"), Index,CurrentTile.ParticlesZOrdered[Index].size(), *(TilePosition.ToString()) );
2196  }
2197  }
2198  else
2199  {
2200  UE_LOG(LogCarla, Error, TEXT("RemoveParticlesFromOrderedContainer Invalid Index %d ZOrderedSize %d Tile: %s"), Index,CurrentTile.ParticlesZOrdered.size(), *(TilePosition.ToString()) );
2201  }
2202  }
2203 }
2204 
2205 void UCustomTerrainPhysicsComponent::AddParticlesToOrderedContainer(
2206  const std::vector<FParticle*>& Particles)
2207 {
2208  TRACE_CPUPROFILER_EVENT_SCOPE(AddParticlesToOrderedContainer);
2209 
2210  uint32_t PartialHeightMapSize =
2211  SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2212  float InverseTileSize = 1.f/SparseMap.GetTileSize();
2213  float Transformation = InverseTileSize * PartialHeightMapSize;
2214  float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2215  for (size_t i = 0; i < Particles.size(); i++)
2216  {
2217  const FParticle* P = Particles[i];
2218  uint64_t TileId = SparseMap.GetTileId(P->Position);
2219  FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2220  CurrentTile.bHeightmapNeedToUpdate = true;
2221  FDVector TilePosition = CurrentTile.TilePosition;
2222  FDVector ParticleLocalPosition = P->Position - TilePosition;
2223  FIntVector HeightMapCoords = FIntVector(
2224  std::floor(ParticleLocalPosition.X * Transformation),
2225  std::floor(ParticleLocalPosition.Y * Transformation), 0);
2226  //HeightMapCoords.X = std::min( std::max( HeightMapCoords.X, 0) , static_cast<int>(PartialHeightMapSize-1));
2227  //HeightMapCoords.Y = std::min( std::max( HeightMapCoords.Y, 0) , static_cast<int>(PartialHeightMapSize-1));
2228  uint32_t Index = HeightMapCoords.Y * PartialHeightMapSize + HeightMapCoords.X;
2229  if( Index < CurrentTile.ParticlesZOrdered.size() )
2230  {
2231  float CurrentHeight = *( CurrentTile.ParticlesZOrdered[Index].begin() );
2232  if( P->Position.Z - CurrentHeight < UEFrameToSI( ParticleDiameter ) * 2.0f )
2233  {
2234  CurrentTile.ParticlesZOrdered[Index].insert(P->Position.Z);
2235  }
2236  }else{
2237  UE_LOG(LogCarla, Error, TEXT("RemoveParticlesFromOrderedContainer Invalid Index %d ZOrderedSize %d Tile: %s"), Index,CurrentTile.ParticlesZOrdered.size(), *(TilePosition.ToString()) );
2238 
2239  }
2240  }
2241 }
2242 
2243 void UCustomTerrainPhysicsComponent::FlagTilesToRedoOrderedContainer(
2244  const std::vector<FParticle*>& Particles)
2245 {
2246  TRACE_CPUPROFILER_EVENT_SCOPE(AddParticlesToOrderedContainer);
2247 
2248  uint32_t PartialHeightMapSize =
2249  SparseMap.GetTileSize() * TextureToUpdate->GetSizeX() / (2*TextureRadius);
2250  float InverseTileSize = 1.f/SparseMap.GetTileSize();
2251  float Transformation = InverseTileSize * PartialHeightMapSize;
2252  float ParticlesInARowInHeightMap = TextureToUpdate->GetSizeX() / (TextureRadius * 2);
2253  for (size_t i = 0; i < Particles.size(); i++)
2254  {
2255  const FParticle* P = Particles[i];
2256  uint64_t TileId = SparseMap.GetTileId(P->Position);
2257  FDenseTile& CurrentTile = SparseMap.GetTile(TileId);
2258  CurrentTile.bHeightmapNeedToUpdate = true;
2259  CurrentTile.bParticlesZOrderedInitialized = false;
2260  }
2261 }
2262 
2263 
2264 void UCustomTerrainPhysicsComponent::UpdateTilesHeightMapsInRadius(FDVector Position, uint32 Rad )
2265 {
2266  TRACE_CPUPROFILER_EVENT_SCOPE(UpdateTilesHeightMapsInRadius);
2267 
2268  uint64_t TileId = SparseMap.GetTileId( UEFrameToSI(Position.ToFVector() ) );
2269  uint32_t Tile_X = (uint32_t)(TileId >> 32);
2270  uint32_t Tile_Y = (uint32_t)(TileId & (uint32_t)(~0));
2271  uint32_t RadiusInTiles = (Rad/TileSize);
2272 
2273  FDVector Extension = UEFrameToSI(WorldSize);
2274  uint32_t MinX = Tile_X - RadiusInTiles;
2275  uint32_t MinY = Tile_Y - RadiusInTiles;
2276  uint32_t MaxX = Tile_X + RadiusInTiles;
2277  uint32_t MaxY = Tile_Y + RadiusInTiles;
2278 
2279  for( uint32_t X = MinX; X <= MaxX; ++X )
2280  {
2281  for( uint32_t Y = MinY; Y <= MaxY; ++Y )
2282  {
2283  uint64_t CurrentTileId = SparseMap.GetTileId(X,Y);
2284  if( SparseMap.Map.count(CurrentTileId) )
2285  {
2286  SparseMap.GetTile(X, Y).UpdateLocalHeightmap();
2287  }
2288  }
2289  }
2290 }
2291 
2292 void UCustomTerrainPhysicsComponent::AddForceToSingleWheel( USkeletalMeshComponent* SkeletalMeshComponent, FVector WheelPosition, FVector WheelNormalForce )
2293 {
2294  FVector WheelBottomLocation = WheelPosition - FVector(0,0, 0.337);
2295  float OriginalHeight = SparseMap.GetHeight(WheelPosition);
2296  float NewFloorHeight = OriginalHeight - UEFrameToSI(TerrainDepth);
2297 
2298  if( WheelNormalForce.Size() == 0 ){
2299  WheelNormalForce = FVector::UpVector;
2300  }
2301 
2302  float ForceFactor = ( WheelBottomLocation.Z - OriginalHeight ) / ( NewFloorHeight - OriginalHeight );
2303  if( ForceFactor < 0){
2304  ForceFactor = 0;
2305  }
2306 
2307  SkeletalMeshComponent->AddForceAtLocationLocal(WheelPosition, SIToUEFrame(WheelNormalForce) * ( ForceFactor * NormalForceIntensity) );
2308 }
2309 
2310 void UCustomTerrainPhysicsComponent::ApplyForcesToVehicle(
2311  ACarlaWheeledVehicle *Vehicle,
2312  FVector ForceWheel0, FVector ForceWheel1, FVector ForceWheel2, FVector ForceWheel3,
2313  FVector TorqueWheel0, FVector TorqueWheel1, FVector TorqueWheel2, FVector TorqueWheel3)
2314 {
2315  TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::ApplyForcesToVehicle);
2316 
2317  FTransform VehicleTransform = Vehicle->GetTransform();
2318  FVector WheelPosition0 = VehicleTransform.TransformPosition(FVector(140, -70, 40));
2319  FVector WheelPosition1 = VehicleTransform.TransformPosition(FVector(140, 70, 40));
2320  FVector WheelPosition2 = VehicleTransform.TransformPosition(FVector(-140, -70, 40));
2321  FVector WheelPosition3 = VehicleTransform.TransformPosition(FVector(-140, 70, 40));
2322  UPrimitiveComponent* PrimitiveComponent =
2323  Cast<UPrimitiveComponent>(Vehicle->GetRootComponent());
2324  if(!PrimitiveComponent)
2325  {
2326  UE_LOG(LogCarla, Error, TEXT("ApplyForcesToVehicle Vehicle does not contain UPrimitiveComponent"));
2327  return;
2328  }
2329  if(bDisableVehicleGravity && PrimitiveComponent->IsGravityEnabled())
2330  {
2331  PrimitiveComponent->SetEnableGravity(false);
2332  }
2333  if(bUseLocalFrame)
2334  {
2335  ForceWheel0 = VehicleTransform.TransformVector(ForceWheel0);
2336  ForceWheel1 = VehicleTransform.TransformVector(ForceWheel1);
2337  ForceWheel2 = VehicleTransform.TransformVector(ForceWheel2);
2338  ForceWheel3 = VehicleTransform.TransformVector(ForceWheel3);
2339  }
2340  ForceWheel0 = ForceWheel0.GetClampedToMaxSize(MaxForceMagnitude);
2341  ForceWheel1 = ForceWheel1.GetClampedToMaxSize(MaxForceMagnitude);
2342  ForceWheel2 = ForceWheel2.GetClampedToMaxSize(MaxForceMagnitude);
2343  ForceWheel3 = ForceWheel3.GetClampedToMaxSize(MaxForceMagnitude);
2344 
2345  if(bUseImpulse)
2346  {
2347  PrimitiveComponent->AddImpulseAtLocation(ForceWheel0, WheelPosition0);
2348  PrimitiveComponent->AddImpulseAtLocation(ForceWheel1, WheelPosition1);
2349  PrimitiveComponent->AddImpulseAtLocation(ForceWheel2, WheelPosition2);
2350  PrimitiveComponent->AddImpulseAtLocation(ForceWheel3, WheelPosition3);
2351  }
2352  else
2353  {
2354  PrimitiveComponent->AddForceAtLocationLocal(ForceWheel0, FVector(140, -70, 40));
2355  PrimitiveComponent->AddForceAtLocationLocal(ForceWheel1, FVector(140, 70, 40));
2356  PrimitiveComponent->AddForceAtLocationLocal(ForceWheel2, FVector(-140, -70, 40));
2357  PrimitiveComponent->AddForceAtLocationLocal(ForceWheel3, FVector(-140, 70, 40));
2358  }
2359 
2360  PrimitiveComponent->AddTorqueInRadians(TorqueWheel0);
2361  PrimitiveComponent->AddTorqueInRadians(TorqueWheel1);
2362  PrimitiveComponent->AddTorqueInRadians(TorqueWheel2);
2363  PrimitiveComponent->AddTorqueInRadians(TorqueWheel3);
2364  if (DrawDebugInfo && bShowForces)
2365  {
2366  float LifeTime = 0.3f;
2367  bool bPersistentLines = false;
2368  bool bDepthIsForeground = (0 == SDPG_Foreground);
2369  UWorld * World = GetWorld();
2370  ULineBatchComponent* LineBatcher =
2371  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
2372  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
2373  if (!LineBatcher)
2374  {
2375  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
2376  }
2377  LineBatcher->DrawLine(WheelPosition0 + FVector(0,0,50),
2378  WheelPosition0 + FVector(0,0,50)+ ForceWheel0.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel0.Size()),
2379  FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2380  LineBatcher->DrawLine(WheelPosition1 + FVector(0,0,50),
2381  WheelPosition1 + FVector(0,0,50)+ ForceWheel1.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel1.Size()),
2382  FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2383  LineBatcher->DrawLine(WheelPosition2 + FVector(0,0,50),
2384  WheelPosition2 + FVector(0,0,50)+ ForceWheel2.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel2.Size()),
2385  FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2386  LineBatcher->DrawLine(WheelPosition3 + FVector(0,0,50),
2387  WheelPosition3 + FVector(0,0,50)+ ForceWheel3.GetSafeNormal()*(5 + ForceMulFactor*10*ForceWheel3.Size()),
2388  FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2389  }
2390 }
2391 
2392 void UCustomTerrainPhysicsComponent::ApplyMeanAccelerationToVehicle(
2393  ACarlaWheeledVehicle *Vehicle,
2394  FVector ForceWheel0, FVector ForceWheel1, FVector ForceWheel2, FVector ForceWheel3)
2395 {
2396  TRACE_CPUPROFILER_EVENT_SCOPE(UCustomTerrainPhysicsComponent::ApplyForcesToVehicle);
2397  FVector MeanAcceleration = (ForceWheel0 + ForceWheel1 + ForceWheel2 + ForceWheel3)/4.f;
2398  UPrimitiveComponent* PrimitiveComponent =
2399  Cast<UPrimitiveComponent>(Vehicle->GetRootComponent());
2400  if (!PrimitiveComponent)
2401  {
2402  UE_LOG(LogCarla, Error, TEXT("ApplyMeanAccelerationToVehicle Vehicle does not contain UPrimitiveComponent"));
2403  return;
2404  }
2405  if(bDisableVehicleGravity && PrimitiveComponent->IsGravityEnabled())
2406  {
2407  PrimitiveComponent->SetEnableGravity(false);
2408  }
2409  if(bUseLocalFrame)
2410  {
2411  FTransform VehicleTransform = Vehicle->GetTransform();
2412  MeanAcceleration = VehicleTransform.TransformVector(MeanAcceleration);
2413  }
2414  PrimitiveComponent->AddForce(MeanAcceleration, FName(""), true);
2415 
2416  if (DrawDebugInfo && bShowForces)
2417  {
2418  float LifeTime = 0.3f;
2419  bool bPersistentLines = false;
2420  bool bDepthIsForeground = (0 == SDPG_Foreground);
2421  UWorld * World = GetWorld();
2422  ULineBatchComponent* LineBatcher =
2423  (World ? (bDepthIsForeground ? World->ForegroundLineBatcher :
2424  (( bPersistentLines || (LifeTime > 0.f) ) ? World->PersistentLineBatcher : World->LineBatcher)) : nullptr);
2425  if (!LineBatcher)
2426  {
2427  UE_LOG(LogCarla, Error, TEXT("Missing linebatcher"));
2428  }
2429  LineBatcher->DrawLine(PrimitiveComponent->GetComponentLocation() + FVector(0,0,200),
2430  PrimitiveComponent->GetComponentLocation() + FVector(0,0,200)+ MeanAcceleration.GetSafeNormal()*(1 + MeanAcceleration.Size()),
2431  FLinearColor(0.0,1.0,0.0), 0, 3.0, 0.3);
2432  }
2433 }
2434 
2435 TArray<FVector> UCustomTerrainPhysicsComponent::GetParticlesInRadius(FVector Position, float InRadius)
2436 {
2437  std::vector<FParticle*> Particles = SparseMap.GetParticlesInRadius(UEFrameToSI(Position), InRadius*CMToM);
2438  TArray<FVector> ParticlePositions;
2439  for(FParticle* Particle : Particles)
2440  {
2441  ParticlePositions.Add(SIToUEFrame(Particle->Position.ToFVector()));
2442  }
2443  return ParticlePositions;
2444 }
2445 
2446 TArray<FVector> UCustomTerrainPhysicsComponent::GetParticlesInTileRadius(FVector Position, float InRadius)
2447 {
2448  std::vector<FParticle*> Particles = SparseMap.GetParticlesInTileRadius(UEFrameToSI(Position), InRadius*CMToM);
2449  TArray<FVector> ParticlePositions;
2450  for(FParticle* Particle : Particles)
2451  {
2452  ParticlePositions.Add(SIToUEFrame(Particle->Position.ToFVector()));
2453  }
2454  return ParticlePositions;
2455 }
2456 
2457 
2458 FVector UCustomTerrainPhysicsComponent::GetTileCenter(FVector Position)
2459 {
2460  return SIToUEFrame(
2461  SparseMap.GetTilePosition(
2462  SparseMap.GetTileId(
2463  UEFrameToSI(Position))).ToFVector());
2464 }
2465 
2466 void UCustomTerrainPhysicsComponent::SetUpParticleArrays(std::vector<FParticle*>& ParticlesIn,
2467  TArray<float>& ParticlePosOut,
2468  TArray<float>& ParticleVelOut,
2469  const FTransform &WheelTransform)
2470 {
2471  ParticlePosOut.Empty();
2472  ParticleVelOut.Empty();
2473  ParticlePosOut.Reserve(ParticlesIn.size()*3);
2474  ParticleVelOut.Reserve(ParticlesIn.size()*3);
2475  if(bUseLocalFrame)
2476  {
2477  const FTransform InverseTransform = WheelTransform.Inverse();
2478  for(FParticle* Particle : ParticlesIn)
2479  {
2480  FVector UEPosition = SIToUEFrame(Particle->Position.ToFVector());
2481  FVector UELocalPosition = InverseTransform.TransformPosition(UEPosition);
2482  FVector Position = UEFrameToSI(UELocalPosition);
2483  ParticlePosOut.Add(static_cast<float>(Position.X));
2484  ParticlePosOut.Add(static_cast<float>(Position.Y));
2485  ParticlePosOut.Add(static_cast<float>(Position.Z));
2486  ParticleVelOut.Add(Particle->Velocity.X);
2487  ParticleVelOut.Add(Particle->Velocity.Y);
2488  ParticleVelOut.Add(Particle->Velocity.Z);
2489  }
2490  if(ParticlesIn.size() < MaxParticlesPerWheel)
2491  {
2492  for (int i = 0; i < (MaxParticlesPerWheel - ParticlesIn.size()); ++i)
2493  {
2494  ParticlePosOut.Add(0.f);
2495  ParticlePosOut.Add(0.f);
2496  ParticlePosOut.Add(0.f);
2497  ParticleVelOut.Add(0.f);
2498  ParticleVelOut.Add(0.f);
2499  ParticleVelOut.Add(0.f);
2500  }
2501  }
2502  }
2503  else
2504  {
2505  for(FParticle* Particle : ParticlesIn)
2506  {
2507  ParticlePosOut.Add(static_cast<float>(Particle->Position.X));
2508  ParticlePosOut.Add(static_cast<float>(Particle->Position.Y));
2509  ParticlePosOut.Add(static_cast<float>(Particle->Position.Z));
2510  ParticleVelOut.Add(Particle->Velocity.X);
2511  ParticleVelOut.Add(Particle->Velocity.Y);
2512  ParticleVelOut.Add(Particle->Velocity.Z);
2513  }
2514  if(ParticlesIn.size() < MaxParticlesPerWheel)
2515  {
2516  FVector WheelPosition = UEFrameToSI(WheelTransform.GetLocation());
2517  for (int i = 0; i < (MaxParticlesPerWheel - ParticlesIn.size()); ++i)
2518  {
2519  ParticlePosOut.Add(WheelPosition.X);
2520  ParticlePosOut.Add(WheelPosition.Y);
2521  ParticlePosOut.Add(WheelPosition.Z);
2522  ParticleVelOut.Add(0.f);
2523  ParticleVelOut.Add(0.f);
2524  ParticleVelOut.Add(0.f);
2525  }
2526  }
2527  }
2528 }
2529 
2530 void UCustomTerrainPhysicsComponent::SetUpWheelArrays(ACarlaWheeledVehicle *Vehicle, int WheelIdx,
2531  TArray<float>& WheelPos,
2532  TArray<float>& WheelOrientation,
2533  TArray<float>& WheelLinearVelocity,
2534  TArray<float>& WheelAngularVelocity)
2535 {
2536  FTransform VehicleTransform = Vehicle->GetTransform();
2537  FVector Position;
2538  //placeholder
2539  switch (WheelIdx)
2540  {
2541  case 0:
2542  Position = FVector(140, -70, 40);
2543  break;
2544  case 1:
2545  Position = FVector(140, 70, 40);
2546  break;
2547  case 2:
2548  Position = FVector(-140, -70, 40);
2549  break;
2550  case 3:
2551  default:
2552  Position = FVector(-140, 70, 40);
2553  break;
2554  }
2555  FVector PhysAngularVelocity = Vehicle->GetMesh()->GetPhysicsAngularVelocityInRadians();
2556  //UE_LOG(LogCarla, Log, TEXT("AngVel: %s"), *PhysAngularVelocity.ToString());
2557  if (bUseLocalFrame)
2558  {
2559  FTransform InverseTransform = VehicleTransform.Inverse();
2560  Position = FVector(0,0,0);
2561  FVector Velocity = UEFrameToSI(
2562  InverseTransform.TransformVector(Vehicle->GetVelocity()));
2563  WheelPos = {Position.X, Position.Y, Position.Z};
2564  // convert to SI
2565  WheelOrientation = {1.f, 0.f, 0.f, 0.f};
2566  WheelLinearVelocity = {Velocity.X, Velocity.Y, Velocity.Z};
2567  FVector LocalAngularVelocity = InverseTransform.TransformVector(PhysAngularVelocity);
2568  //UE_LOG(LogCarla, Log, TEXT("Local Total AngVel: %s"), *LocalAngularVelocity.ToString());
2569  float ForwardSpeed = Velocity.X;
2570  float AngularSpeed = (ForwardSpeed/(CMToM*TireRadius));
2571  WheelAngularVelocity = {
2572  LocalAngularVelocity.X,
2573  AngularSpeed + LocalAngularVelocity.Y,
2574  -LocalAngularVelocity.Z};
2575  }
2576  else
2577  {
2578  Position = VehicleTransform.TransformPosition(Position);
2579  if(LargeMapManager)
2580  {
2581  Position = LargeMapManager->LocalToGlobalLocation(Position);
2582  }
2583  Position = UEFrameToSI(Position);
2584  float ForwardSpeed = FVector::DotProduct(
2585  Vehicle->GetVelocity(),VehicleTransform.GetRotation().GetForwardVector());
2586  FVector Velocity = UEFrameToSI(Vehicle->GetVelocity());
2587  WheelPos = {Position.X, Position.Y, Position.Z};
2588  FQuat Quat = VehicleTransform.GetRotation();
2589  //UE_LOG(LogCarla, Log, TEXT("Quat: %s"), *Quat.ToString());
2590  // convert to SI
2591  WheelOrientation = {Quat.W,Quat.X,-Quat.Y,Quat.Z};
2592  WheelLinearVelocity = {Velocity.X, Velocity.Y, Velocity.Z};
2593  float AngularSpeed = (ForwardSpeed)/(TireRadius);
2594  FVector GlobalAngulaSpeed = VehicleTransform.TransformVector(FVector(0, AngularSpeed, 0));
2595  PhysAngularVelocity = PhysAngularVelocity + GlobalAngulaSpeed;
2596  WheelAngularVelocity = {
2597  PhysAngularVelocity.X,
2598  PhysAngularVelocity.Y,
2599  -PhysAngularVelocity.Z};
2600  //UE_LOG(LogCarla, Log, TEXT("Total AngVel: %s"), *PhysAngularVelocity.ToString());
2601  }
2602 }
2603 
2604 void UCustomTerrainPhysicsComponent::AddForces(
2605  const TArray<FForceAtLocation> &Forces)
2606 {
2607  for (const FForceAtLocation& Force : Forces)
2608  {
2609  ForcesToApply.Add(Force);
2610  }
2611 }
2612 
2613 void UCustomTerrainPhysicsComponent::ApplyForces()
2614 {
2615  for (const FForceAtLocation& Force : ForcesToApply)
2616  {
2617  RootComponent->AddForceAtLocationLocal(Force.Force, Force.Location);
2618  }
2619  ForcesToApply.Empty();
2620 }
2621 
2622 void UCustomTerrainPhysicsComponent::UpdateMaps(
2623  FVector Position, float RadiusX, float RadiusY, float CacheRadiusX, float CacheRadiusY)
2624 {
2625  SparseMap.UpdateMaps(UEFrameToSI(Position), UEFrameToSI(RadiusX), UEFrameToSI(RadiusY),
2626  UEFrameToSI(CacheRadiusX), UEFrameToSI(CacheRadiusY));
2627 }
2628 
2629 FTilesWorker::FTilesWorker(UCustomTerrainPhysicsComponent* TerrainComp, FVector NewPosition, float NewRadiusX, float NewRadiusY )
2630 {
2631  CustomTerrainComp = TerrainComp;
2632  Position = NewPosition;
2633  RadiusX = NewRadiusX;
2634  RadiusY = NewRadiusY;
2635 }
2636 
2638 {
2639  CustomTerrainComp = nullptr;
2640 }
2641 
2642 
2644 
2645  FDateTime CacheCurrentTime = FDateTime::Now();
2646  FDateTime LoadTilesCurrentTime = FDateTime::Now();
2647  FDateTime UnloadTilesCurrentTime = FDateTime::Now();
2648 
2649  while(bShouldContinue){
2650  FVector LastPosition = CustomTerrainComp->LastUpdatedPosition;
2651  if(Position != LastPosition)
2652  {
2653  Position = LastPosition;
2654  CustomTerrainComp->UpdateMaps(CustomTerrainComp->LastUpdatedPosition,
2655  CustomTerrainComp->TileRadius.X, CustomTerrainComp->TileRadius.Y,
2656  CustomTerrainComp->CacheRadius.X, CustomTerrainComp->CacheRadius.Y);
2657  }
2658  if(!bShouldContinue)
2659  {
2660  break;
2661  }
2662  }
2663 
2664  return 0;
2665 }
void GetParticlesInBox(const FOrientedBox &OBox, std::vector< FParticle *> &ParticlesInRadius)
virtual uint32 Run() override
FCarlaActor * FindCarlaActor(FCarlaActor::IdType ActorId)
Find a Carla actor by id.
Definition: CarlaEpisode.h:173
void InitializeMap(UHeightMapDataAsset *DataAsset, FDVector Origin, FDVector MapSize, float Size, float ScaleZ)
double Y
Definition: DVector.h:14
std::vector< FParticle * > GetParticlesInRadius(FDVector Position, float Radius)
void Update(FVector Position, float RadiusX, float RadiusY)
float GetHeight(FDVector Position) const
sensor::data::Color Color
std::vector< float > _particle_forces
Definition: pytorch.h:50
virtual FVector GetVelocity() const override
void GetAllParticles(std::vector< FParticle *> &ParticlesInRadius)
void InitializeHeightmap(UHeightMapDataAsset *DataAsset, FDVector Size, FDVector Origin, FDVector Tile0, float ScaleZ)
FDVector GetTilePosition(uint64_t TileId)
FSoilTerramechanicsProperties GetTerrainPropertiesAtGlobalLocation(FVector VehicleLocation)
FString ToString() const
Definition: DVector.h:52
FVector UEFrameToSI(const FVector &In)
static bool ActorAttributeToBool(const FActorAttribute &ActorAttribute, bool Default)
============================================================================ – Helpers to retrieve a...
constexpr float CMToM
void InitializeTile(uint32_t TextureSize, float AffectedRadius, float ParticleSize, float Depth, FDVector TileOrigin, FDVector TileEnd, const FString &SavePath, const FHeightMapData &HeightMap)
std::vector< uint64_t > GetLoadedTilesInRange(FDVector Position, float Radius)
void ReadFVector(std::istream &InFile, FVector &OutObj)
void test_learning()
Definition: pytorch.cpp:27
std::vector< std::multiset< float, std::greater< float > > > ParticlesZOrdered
std::vector< FParticle * > GetParticlesInRadius(FDVector Position, float Radius)
std::vector< cg::Location > Path
FIntVector GetVectorTileId(FDVector Position)
FTilesWorker(class UCustomTerrainPhysicsComponent *TerrainComp, FVector NewPosition, float NewRadiusX, float NewRadiusY)
std::string _filesBaseFolder
FDenseTile & InitializeRegionInCache(uint64_t TileId)
WheelOutput wheel2
Definition: pytorch.h:56
double Z
Definition: DVector.h:15
static T Get(carla::rpc::Response< T > &response)
TEnumAsByte< ESoilTerramechanicsType > TerrainType
FVector ToFVector() const
Definition: DVector.h:47
geom::Location Location
Definition: rpc/Location.h:14
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
void UpdateHeightMap(UHeightMapDataAsset *DataAsset, FDVector Origin, FDVector MapSize, float Size, float ScaleZ)
A simulation episode.
Definition: CarlaEpisode.h:38
const int CacheExtraRadius
double min(double v1, double v2)
Definition: Simplify.h:294
std::vector< float > ParticlesHeightMap
FDenseTile & InitializeRegion(uint32_t Tile_X, uint32_t Tile_Y)
virtual ~FTilesWorker() override
FVector UEFrameToSIDirection(const FVector &In)
const FVehicleControl & GetVehicleControl() const
Vehicle control currently applied to this vehicle.
void UpdateMaps(FDVector Position, float RadiusX, float RadiusY, float CacheRadiusX, float CacheRadiusY)
double X
Definition: DVector.h:13
FDenseTile & operator=(FDenseTile &&Origin)
A description of a Carla Actor with all its variation.
FActorDescription Description
Definition: ActorInfo.h:26
void WriteFVector(std::ostream &OutFile, const FVector &InObj)
rpc::DebugShape Shape
Definition: DebugHelper.cpp:15
FDenseTile & GetTile(uint32_t Tile_X, uint32_t Tile_Y)
FVector SIToUEFrameDirection(const FVector &In)
uint64_t GetTileId(uint32_t Tile_X, uint32_t Tile_Y)
static UCarlaEpisode * GetCurrentEpisode(const UObject *WorldContextObject)
Definition: CarlaStatics.h:68
WheelOutput wheel0
Definition: pytorch.h:54
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
Definition: CarlaStatics.h:100
std::vector< FParticle > Particles
A view over an actor and its properties.
Definition: ActorInfo.h:22
constexpr float MToCM
WheelOutput wheel3
Definition: pytorch.h:57
std::vector< FParticle * > GetParticlesInTileRadius(FDVector Position, float Radius)
std::vector< float > Pixels
std::vector< uint64_t > GetIntersectingTiles(const FOrientedBox &OBox)
Base class for CARLA wheeled vehicles.
std::vector< FParticle * > GetParticlesInBox(const FOrientedBox &OBox)
An actor attribute, may be an intrinsic (non-modifiable) attribute of the actor or an user-defined ac...
WheelOutput wheel1
Definition: pytorch.h:55
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7444
FVector SIToUEFrame(const FVector &In)
A view over an actor and its properties.
Definition: CarlaActor.h:23