zoukankan      html  css  js  c++  java
  • UE4 Runtime Landscape 改进版

    原文地址: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 }

      

     
  • 相关阅读:
    BZOJ 1001: [BeiJing2006]狼抓兔子
    BZOJ 1031: [JSOI2007]字符加密Cipher
    BZOJ 1083: [SCOI2005]繁忙的都市
    BZOJ 1034: [ZJOI2008]泡泡堂BNB
    BZOJ 1040: [ZJOI2008]骑士
    BZOJ 1026: [SCOI2009]windy数
    BZOJ 1022: [SHOI2008]小约翰的游戏John
    BZOJ 1018: [SHOI2008]堵塞的交通traffic
    BZOJ: 2819 Nim
    bzoj 3144
  • 原文地址:https://www.cnblogs.com/LynnVon/p/11804286.html
Copyright © 2011-2022 走看看