Description

Foliage usually follows when the Transform of the placed ground or floor changes. However, if the ground or floor is a Level Instance Actor, it will not follow.

The cause is in the code below.

void AInstancedFoliageActor::OnLevelActorMoved(AActor* InActor)
{
	UWorld* InWorld = InActor->GetWorld();	if (!InWorld || !InWorld->IsGameWorld())
	{
		for (UActorComponent* Component : InActor->GetComponents())
		{
			if (Component)
			{
				MoveInstancesForMovedComponent(Component);
			}
		}
...
}

void AInstancedFoliageActor::MoveInstancesForMovedComponent(UActorComponent* InComponent)
{
...		
	const auto BaseId = InstanceBaseCache.GetInstanceBaseId(InComponent);
	if (BaseId == FFoliageInstanceBaseCache::InvalidBaseId)
	{
		return;
	}

...

Instance of Foliage has the information of the placed Component. This component is a component of the Actor in LevelInstance. But since the Component of LevelInstanceActor itself is used in the check of the tracking process, the tracking process is not executed.

To solve this, you need to save the RootComponent of LevelInstanceActor in Instance like following code.

 

Engine\Source\Editor\FoliageEdit\Private\FoliageEdMode.cpp

// add
#include "LevelInstance/LevelInstanceSubsystem.h"
#include "LevelInstance/LevelInstanceActor.h"
//

bool FEdModeFoliage::AddInstancesImp(UWorld* InWorld, const UFoliageType* Settings, const TArray<FDesiredFoliageInstance>& DesiredInstances, const TArray<int32>& ExistingInstanceBuckets, const float Pressure, LandscapeLayerCacheData* LandscapeLayerCachesPtr, const FFoliageUISettings* UISettings, const FFoliagePaintingGeometryFilter* OverrideGeometryFilter, bool InRebuildFoliageTree)
{
...		{
			SCOPE_CYCLE_COUNTER(STAT_FoliageSpawnInstance);			
			
			TArray<FFoliageInstance> PlacedInstances;
			PlacedInstances.Reserve(AdditionalInstances);			
			
			// add 
			ULevelInstanceSubsystem* LevelInstanceSubsystem = InWorld->GetSubsystem<ULevelInstanceSubsystem>();
			/////	
			
			for (int32 Idx = 0; Idx < AdditionalInstances; Idx++)
			{
				FPotentialInstance& PotentialInstance = PotentialInstances[Idx];
				FFoliageInstance Inst;
				if (PotentialInstance.PlaceInstance(InWorld, Settings, Inst))
				{
					Inst.ProceduralGuid = PotentialInstance.DesiredInstance.ProceduralGuid;
					Inst.BaseComponent = PotentialInstance.HitComponent;					
					
					// add 
					if (LevelInstanceSubsystem)
					{
						ALevelInstance* LevelInstanceActor = LevelInstanceSubsystem->GetParentLevelInstance(Inst.BaseComponent->GetOwner());
						if (LevelInstanceActor)
						{
							Inst.BaseComponent = LevelInstanceActor->GetRootComponent();
						}
					}
					/////	
					
					PlacedInstances.Add(MoveTemp(Inst));
					bPlacedInstances = true;
				}
			}			
			SpawnFoliageInstance(InWorld, Settings, UISettings, PlacedInstances, InRebuildFoliageTree);
		}
	}	
	return bPlacedInstances;
}

 

 

Steps to Reproduce
  1. Create OpenWorld Level
  2. Create a Level with a Static Mesh Actor such as a floor
  3. Place 2 in 1 with LevelInstanceActor
  4. Place Foliage on 3
  5. Move 3

expect : Foliage follow 3
result : foliage does not follow 3. Therefore, foliage and 3 appear to be separated

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-157536 in the post.

3
Login to Vote

Unresolved
CreatedJun 24, 2022
UpdatedMay 3, 2024