原文地址:https://www.cnblogs.com/LynnVon/p/11804286.html
在上一篇文章基本已经将如何做runtime landscape写完了 但后来发现 频繁的生成和删除组件会造成主线程卡顿 而因为要操作gameobject 所以不能异步 经过一番思考 决定 不生成和删除组件 而是改为移动组件
将本来删除的组件移动到要增加的位置 只需要改变位置就可以了
在改变landscapecomponent位置时 要设置为movable 但是设置为movable后landscape就不见了 ,所以只在setrelativetransform时改为movable,设置完位置后再改为static就行了
// RuntimeGenerateTerrain.h
#pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "FS_ImageLoader.h" #include "RuntimeGenerateTerrain.generated.h" class ALandscapeProxy; class UMaterialInstanceDynamic; class UMaterialInstance; class ULandscapeComponent; #define LANDSCAPESIZE 31 DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnLandscapeGenerateComplete); UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class FLIGHTSIM_API URuntimeGenerateTerrain : public UActorComponent { GENERATED_BODY() public: // Sets default values for this component's properties URuntimeGenerateTerrain(); protected: // Called when the game starts virtual void BeginPlay() override; public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const; void StartGenerate(); void InitLandscapeComponent(); bool LoadTexture(ULandscapeComponent* C); bool AsyncLoadTexture(ULandscapeComponent* C); void MoveLandscapeComponent(); void RemoveLandscapeComponent(); void UpdateLeftAndRightPoint(); void SetXYtoComponentMap(ULandscapeComponent* C); void RemoveXYtoComponentMap(ULandscapeComponent* C); void StartAddComponent(); void StopAddComponent(); void CalComponentIndex(); void ResetComponentIndex(); int GetComponentIndexX(ULandscapeComponent* C); int GetComponentIndexY(ULandscapeComponent* C); UFUNCTION() void LoadTextureComplete(UTexture2D* texture); public: ALandscapeProxy* mLandscape = nullptr; UMaterialInstanceDynamic* GI; UMaterialInstance* SounceMaterial; TMap<FIntPoint, ULandscapeComponent*> mXYtoComponentMap; UPROPERTY(EditAnywhere,BlueprintReadWrite) FString MapFileName = FString(); FOnLandscapeGenerateComplete OnLandscapeGenerateComplete; private: bool bAddComponent:1; int ComponentIndexX1 = -1; int ComponentIndexY1 = -1; int ComponentIndexX2 = -1; int ComponentIndexY2 = -1; FVector ForeLocation = FVector::ZeroVector; FVector2D LeftBottom = FVector2D(0,0); FVector2D RightTop = FVector2D(LANDSCAPESIZE,LANDSCAPESIZE); TArray<ULandscapeComponent*> DeleteComponents; TArray<ULandscapeComponent*> ReadyForTextureMID; };
1 2 /*! 3 * file RuntimeGenerateTerrain.cpp 4 * 5 * author Hailiang Feng 6 * date 2019/11/01 9:45 7 * 8 * 9 */ 10 #include "RuntimeGenerateTerrain.h" 11 #include "Kismet/GameplayStatics.h" 12 #include "LandscapeComponent.h" 13 #include "LandscapeInfo.h" 14 #include "LandscapeProxy.h" 15 #include "EngineUtils.h" 16 #include "Materials/MaterialInstanceConstant.h" 17 #include "RenderingThread.h" 18 #include "FS_Utils.h" 19 #include "Components/TextRenderComponent.h" 20 #include "LandscapeInfoMap.h" 21 #include "Guid.h" 22 #include "LandscapeHeightfieldCollisionComponent.h" 23 #include "UnrealMathUtility.h" 24 #include "Async.h" 25 #include "FS_ImageLoader.h" 26 27 28 // Sets default values for this component's properties 29 URuntimeGenerateTerrain::URuntimeGenerateTerrain() 30 { 31 // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features 32 // off to improve performance if you don't need them. 33 PrimaryComponentTick.bCanEverTick = true; 34 bReplicates = true; 35 bAddComponent = false; 36 // ... 37 static ConstructorHelpers::FObjectFinder<UMaterialInstance> _material(TEXT("MaterialInstanceConstant'/Game/FlightSim/material/M_GoogleBASE_Inst.M_GoogleBASE_Inst'")); 38 if (_material.Succeeded()) 39 { 40 SounceMaterial = _material.Object; 41 } 42 43 } 44 45 // Called when the game starts 46 void URuntimeGenerateTerrain::BeginPlay() 47 { 48 Super::BeginPlay(); 49 50 StartGenerate(); 51 } 52 53 // Called every frame 54 void URuntimeGenerateTerrain::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) 55 { 56 Super::TickComponent(DeltaTime, TickType, ThisTickFunction); 57 58 // ... 59 60 if (!mLandscape)return; 61 CalComponentIndex(); 62 if (bAddComponent) 63 { 64 StopAddComponent(); 65 RemoveLandscapeComponent(); 66 MoveLandscapeComponent(); 67 68 } 69 } 70 71 void URuntimeGenerateTerrain::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const 72 { 73 } 74 75 void URuntimeGenerateTerrain::StartGenerate() 76 { 77 GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Red, FString("Runtime Landscape Generate Start")); 78 UE_LOG(LogFlightSim, Log, TEXT("Runtime Landscape Generate Start")); 79 80 FString levelName = UGameplayStatics::GetCurrentLevelName(this); 81 if (levelName.Equals(FString("Level_China"))) 82 { 83 MapFileName = FString("FileName_China"); 84 MapFileName = FString("Texture2D'/Game/GoogleMap/ChinaImage1/"); 85 } 86 if (levelName.Equals(FString("Level_Farm"))) 87 { 88 MapFileName = FString("Texture2D'/Game/GoogleMap/Level_Farm/"); 89 } 90 91 // ... 92 UWorld* world = GetWorld(); 93 check(world); 94 TArray<AActor*> _actor; 95 UGameplayStatics::GetAllActorsOfClass(GetWorld(), ALandscapeProxy::StaticClass(), _actor); 96 if (_actor.Num() > 0) 97 { 98 mLandscape = (ALandscapeProxy*)_actor[0]; 99 } 100 if (mLandscape) 101 { 102 mLandscape->LandscapeMaterial = SounceMaterial; 103 mLandscape->bUseDynamicMaterialInstance = true; 104 for (ULandscapeComponent* C : mLandscape->LandscapeComponents) 105 { 106 LoadTexture(C); 107 SetXYtoComponentMap(C); 108 } 109 110 } 111 if (OnLandscapeGenerateComplete.IsBound()) 112 { 113 OnLandscapeGenerateComplete.Broadcast(); 114 } 115 116 } 117 118 bool URuntimeGenerateTerrain::LoadTexture(ULandscapeComponent* C) 119 { 120 //GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,FString("RuntimeGenerateTerrain LoadTexture")); 121 122 for (int i = 0; i < C->MaterialInstancesDynamic.Num(); i++) 123 { 124 UMaterialInstanceDynamic* MID = C->MaterialInstancesDynamic[i]; 125 int XIndex = GetComponentIndexY(C); 126 int YIndex = GetComponentIndexX(C); 127 128 129 //FString _fileName = UFS_Utils::GetTerrainConfigSection(MapFileName); 130 FString _fileName = MapFileName; 131 132 /* GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,FString("FileNameSection = ")+MapFileName+FString("---Filename=")+_fileName); 133 if (_fileName.IsEmpty()) 134 { 135 _fileName = FString("Texture2D'/Game/GoogleMap/ChinaImage1/"); 136 }*/ 137 /*int rowOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("rowOffset"))); 138 int columnOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("columnOffset")));*/ 139 int rowOffset = 1; 140 int columnOffset = 1; 141 _fileName.Append(FString::FromInt(XIndex + rowOffset)); 142 _fileName.Append(FString("/")); 143 _fileName.Append(FString::FromInt(YIndex + columnOffset)); 144 _fileName.Append(FString(".")); 145 _fileName.Append(FString::FromInt(YIndex + columnOffset)); 146 _fileName.Append(FString("'")); 147 UTexture2D* texture = LoadObject<UTexture2D>(NULL, *_fileName); 148 if (texture) 149 { 150 MID->SetTextureParameterValue(FName("Texture"), texture); 151 } 152 else 153 { 154 return false; 155 } 156 } 157 return true; 158 159 } 160 161 bool URuntimeGenerateTerrain::AsyncLoadTexture(ULandscapeComponent* C) 162 { 163 164 ReadyForTextureMID.Add(C); 165 166 for (int i = 0; i < C->MaterialInstancesDynamic.Num(); i++) 167 { 168 UMaterialInstanceDynamic* MID = C->MaterialInstancesDynamic[i]; 169 int XIndex = GetComponentIndexX(C); 170 int YIndex = GetComponentIndexY(C); 171 FIntPoint ComponentIndex = FIntPoint(XIndex, YIndex); 172 FString _fileName = FString("H:/MapDownload/FlightMap/googlemaps/Terrain_1/18/"); 173 int rowOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("rowOffset"))); 174 int columnOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("columnOffset"))); 175 _fileName.Append(FString::FromInt(XIndex + rowOffset)); 176 _fileName.Append(FString("/")); 177 _fileName.Append(FString::FromInt(YIndex + columnOffset)); 178 _fileName.Append(FString(".")); 179 _fileName.Append(FString::FromInt(YIndex + columnOffset)); 180 _fileName.Append(FString("'")); 181 _fileName = FString("C:/MapDownload/test/12.jpg"); 182 183 184 UFS_ImageLoader* loader = UFS_ImageLoader::LoadImageFromDiskAsync(this, _fileName); 185 if (loader) 186 { 187 loader->OnLoadCompleted().AddDynamic(this, &URuntimeGenerateTerrain::LoadTextureComplete); 188 } 189 } 190 return true; 191 } 192 193 void URuntimeGenerateTerrain::MoveLandscapeComponent() 194 { 195 ReadyForTextureMID.Empty(); 196 197 for (int32 ComponentIndexY = ComponentIndexY1; ComponentIndexY <= ComponentIndexY2; ComponentIndexY++) 198 { 199 for (int32 ComponentIndexX = ComponentIndexX1; ComponentIndexX <= ComponentIndexX2; ComponentIndexX++) 200 { 201 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)); 202 if (!LandscapeComponent) 203 { 204 // Add New component... 205 FIntPoint ComponentBase = FIntPoint(ComponentIndexX, ComponentIndexY)*mLandscape->ComponentSizeQuads; 206 207 if (DeleteComponents.Num() > 0) 208 { 209 LandscapeComponent = DeleteComponents.Top(); 210 LandscapeComponent->SetMobility(EComponentMobility::Movable); 211 LandscapeComponent->SetRelativeLocation(FVector(ComponentBase.X, ComponentBase.Y, 0)); 212 LandscapeComponent->SetMobility(EComponentMobility::Static); 213 SetXYtoComponentMap(LandscapeComponent); 214 215 LoadTexture(LandscapeComponent); 216 217 DeleteComponents.RemoveSingleSwap(LandscapeComponent); 218 } 219 } 220 } 221 } 222 223 UpdateLeftAndRightPoint(); 224 225 UE_LOG(LogTemp, Warning, TEXT("LeftBottom = %s,RightTop = %s"), *LeftBottom.ToString(), *RightTop.ToString()); 226 UE_LOG(LogTemp, Warning, TEXT("X1 = %s,X2 = %s"), *FString::FromInt(ComponentIndexX1), *FString::FromInt(ComponentIndexX2)); 227 UE_LOG(LogTemp, Warning, TEXT("Y1 = %s,Y2 = %s"), *FString::FromInt(ComponentIndexY1), *FString::FromInt(ComponentIndexY2)); 228 //结束本次增加 229 ResetComponentIndex(); 230 } 231 232 void URuntimeGenerateTerrain::RemoveLandscapeComponent() 233 { 234 DeleteComponents.Empty(); 235 //删除远处的component 236 //X正向 加 237 238 int Xnum = ComponentIndexX2 - ComponentIndexX1 + 1; 239 if (ComponentIndexX1 > RightTop.X) 240 { 241 242 for (int32 y = LeftBottom.Y; y <= RightTop.Y; y++) 243 { 244 for (int32 x = LeftBottom.X; x < LeftBottom.X + Xnum; x++) 245 { 246 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y)); 247 if (LandscapeComponent) 248 { 249 DeleteComponents.Add(LandscapeComponent); 250 } 251 252 } 253 } 254 255 } 256 //x 负方向 加 257 if (ComponentIndexX2 < LeftBottom.X) 258 { 259 for (int32 y = LeftBottom.Y; y <= RightTop.Y; y++) 260 { 261 for (int32 x = RightTop.X; x > RightTop.X - Xnum; x--) 262 { 263 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y)); 264 if (LandscapeComponent) 265 { 266 DeleteComponents.Add(LandscapeComponent); 267 } 268 269 } 270 } 271 272 } 273 //Y方向 274 int Ynum = ComponentIndexY2 - ComponentIndexY1 + 1; 275 if (ComponentIndexY1 > RightTop.Y) 276 { 277 for (int32 x = LeftBottom.X; x < (RightTop.X + 1); x++) 278 { 279 for (int32 y = LeftBottom.Y; y < LeftBottom.Y + Ynum; y++) 280 { 281 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y)); 282 if (LandscapeComponent) 283 { 284 DeleteComponents.Add(LandscapeComponent); 285 } 286 287 } 288 } 289 290 } 291 if (ComponentIndexY2 < LeftBottom.Y) 292 { 293 for (int32 x = LeftBottom.X; x < (RightTop.X + 1); x++) 294 { 295 for (int32 y = RightTop.Y; y > RightTop.Y - Ynum; y--) 296 { 297 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y)); 298 if (LandscapeComponent) 299 { 300 DeleteComponents.Add(LandscapeComponent); 301 } 302 303 } 304 } 305 } 306 for (ULandscapeComponent* DeleteComponent : DeleteComponents) 307 { 308 if (!DeleteComponent)continue; 309 310 RemoveXYtoComponentMap(DeleteComponent); 311 } 312 } 313 314 void URuntimeGenerateTerrain::UpdateLeftAndRightPoint() 315 { 316 //更新左下及右上的坐标 317 if (ComponentIndexX1 > RightTop.X) 318 { 319 LeftBottom.X = ComponentIndexX1 - LANDSCAPESIZE; 320 RightTop.X = ComponentIndexX2; 321 } 322 if (ComponentIndexX2 < LeftBottom.X) 323 { 324 325 LeftBottom.X = ComponentIndexX1; 326 RightTop.X = LANDSCAPESIZE + ComponentIndexX1; 327 } 328 //Y方向 329 if (ComponentIndexY1 > RightTop.Y) 330 { 331 RightTop.Y = ComponentIndexY2; 332 LeftBottom.Y = ComponentIndexY1 - LANDSCAPESIZE; 333 } 334 if (ComponentIndexY2 < LeftBottom.Y) 335 { 336 337 LeftBottom.Y = ComponentIndexY1; 338 RightTop.Y = LANDSCAPESIZE + ComponentIndexY1; 339 340 } 341 } 342 343 void URuntimeGenerateTerrain::SetXYtoComponentMap(ULandscapeComponent* C) 344 { 345 346 int XIndex = GetComponentIndexX(C); 347 int YIndex = GetComponentIndexY(C); 348 mXYtoComponentMap.Add(FIntPoint(XIndex, YIndex), C); 349 } 350 351 void URuntimeGenerateTerrain::RemoveXYtoComponentMap(ULandscapeComponent* C) 352 { 353 354 int XIndex = GetComponentIndexX(C); 355 int YIndex = GetComponentIndexY(C); 356 mXYtoComponentMap.Remove(FIntPoint(XIndex, YIndex)); 357 } 358 359 void URuntimeGenerateTerrain::StartAddComponent() 360 { 361 bAddComponent = true; 362 } 363 364 void URuntimeGenerateTerrain::StopAddComponent() 365 { 366 bAddComponent = false; 367 } 368 369 void URuntimeGenerateTerrain::CalComponentIndex() 370 { 371 372 int XOffset = GetOwner()->GetActorLocation().X - ForeLocation.X; 373 int YOffset = GetOwner()->GetActorLocation().Y - ForeLocation.Y; 374 bool bXChange = false; 375 bool bYChange = false; 376 if (FMath::Abs(XOffset) > mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X) 377 { 378 if (XOffset > 0) 379 { 380 int Xnum = XOffset / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X); 381 ComponentIndexX1 = RightTop.X + 1; 382 ComponentIndexX2 = RightTop.X + Xnum; 383 384 } 385 else 386 { 387 int Xnum = FMath::Abs(XOffset) / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X); 388 ComponentIndexX2 = LeftBottom.X - 1; 389 ComponentIndexX1 = LeftBottom.X - Xnum; 390 391 } 392 bXChange = true; 393 } 394 else 395 { 396 ComponentIndexX1 = LeftBottom.X; 397 ComponentIndexX2 = RightTop.X; 398 } 399 400 if (FMath::Abs(YOffset) > mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y) 401 { 402 if (YOffset > 0) 403 { 404 int Ynum = YOffset / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y); 405 ComponentIndexY1 = RightTop.Y + 1; 406 ComponentIndexY2 = RightTop.Y + Ynum; 407 } 408 else 409 { 410 int Ynum = FMath::Abs(YOffset) / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y); 411 ComponentIndexY2 = LeftBottom.Y - 1; 412 ComponentIndexY1 = LeftBottom.Y - Ynum; 413 } 414 bYChange = true; 415 } 416 else 417 { 418 ComponentIndexY1 = LeftBottom.Y; 419 ComponentIndexY2 = RightTop.Y; 420 } 421 422 if (bXChange || bYChange) 423 { 424 StartAddComponent(); 425 ForeLocation = GetOwner()->GetActorLocation(); 426 427 } 428 429 430 } 431 432 void URuntimeGenerateTerrain::ResetComponentIndex() 433 { 434 ComponentIndexX1 = -1; 435 ComponentIndexX2 = -1; 436 ComponentIndexY1 = -1; 437 ComponentIndexY2 = -1; 438 } 439 440 int URuntimeGenerateTerrain::GetComponentIndexX(ULandscapeComponent* C) 441 { 442 return C->GetRelativeTransform().GetLocation().X / mLandscape->ComponentSizeQuads; 443 } 444 445 int URuntimeGenerateTerrain::GetComponentIndexY(ULandscapeComponent* C) 446 { 447 return C->GetRelativeTransform().GetLocation().Y / mLandscape->ComponentSizeQuads; 448 } 449 450 void URuntimeGenerateTerrain::LoadTextureComplete(UTexture2D* texture) 451 { 452 453 if (!texture)return; 454 455 //GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,texture->GetName()); 456 //if (ReadyForTextureMID.Num()>0) 457 //{ 458 // ULandscapeComponent* c = ReadyForTextureMID.Top(); 459 // UMaterialInstanceDynamic* mid = c->MaterialInstancesDynamic.Top(); 460 // mid->SetTextureParameterValue(FName("Texture"),texture); 461 // ReadyForTextureMID.RemoveSingleSwap(c); 462 //} 463 }