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