Bug: Landscape Grass Takes Forever To Load

Heya,

I’ve tried getting help for this on the forum, which didn’t quite work out well. Thus, I am hoping someone here might be able to assist me, as I’ve tried everything I can think of at this point.

As per my findings in the forum thread: Changing the grass mesh and using a lower density didn’t do anything (My density is 250, grass mesh has ~40 triangles). This is definitely some sort of engine bug because while not playing inside the editor the grass loads just fine. I could literally be at the start point with the camera, with the grass all there, and when I hit play, the grass would clear and very slowly load back in. As soon as I stop play it’ll load up instantly.

Hey DamirH,

In order to assist you with this issue I am going to need a bit more information as to the steps you are taking.

  • Would you provide me we some simple steps to reproduce this issue in a blank project?
  • Would you provide me with some screenshots so I can visualize the issue you are experiencing?
  • You mention, “I might be wrong, but I think this started in 4.9”. Would you be able to test and confirm this does not occur in the 4.8.3 engine version?
  • Could you provide me with your ‘dxdiag’ so I can take a look at your systems specifications?

If you discover any new information on this issue, or if you have further questions please let me know.

Thank you,

Hey Andrew,

Sorry for the delayed response, been at home with a fever today unfortunately. Interesting development though! I did manage to reproduce the issue very simply on multiple PCs, even my i74-4770k with a GTX780 takes ~10 seconds to load it all. I can also confirm that it DOES happen on 4.8.3. These are the reproduction steps:

Create a landscape with the following settings:

http://i.imgur.com/SgtJc36.png

Create this landscape material and apply it:

http://i.imgur.com/8bAFlNX.png

The only notable thing about the material are the grass types. It doesn’t have to be 4, but I’m trying to match my real project environment. Now, most of the settings in the landscape grass assets remains at their default settings. The only changes are these:

  1. The mesh is set to anything. It doesn’t matter what.
  2. The density is dropped down to ~20 on each.
  3. The fourth one (or any one really) has at least 5 variations, each of which uses a different mesh and a density of ~20 each.

With these in place play at various positions on the landscape. Note that it all loads instantly.

And now for the big bang: Reduce the landscape scale to 25x25x100. Play somewhere at the midpoint. Observe how the grass tiles slowly creep towards you.

Incidentally, dropping all but the first variation of the 4th grass asset will make it load up instantly (or at least much faster) again.

I hope this is enough to replicate it. Thank you for your time!

Hey DamirH,

Your process is different than that of the suggested workflow. The Landscape material using the procedurally placed foliage, needs to Sample one of the layers of my landscape material in order to apply it correctly.

In the screenshot below, you can see I have created a simple Layer Blend for my landscapes material, and then added the Grass type node with the four unique inputs.

Each sample then can contain its own ‘GrassType’ (collection of foliage meshes) to be applied to a specific landscape layer. It seems you are compiling all of your meshes on the same layer, and could be experiencing all of the cull distances and Level Of detail changes of each mesh. You will want to edit these values to get your meshes to render correctly at the appropriate distance to the camera. Also scaling your Landscape non uniformly is going to cause all sorts of problems and is not recommended.

If you have any questions let me know.

Thank you,

Hey Andrew,

My production material does sample layers, the above setup is just for testing purposes, it makes no difference. The big culprint is the landscape scale, as I have noted in my reproduction step. You can take your landscape, assuming it’s set to the same settings as I noted in the repro steps, and set its scale to 25x25x100 and you will see the problem.

Best regards,
Damir H.

Sorry but with all due respect this is not the solution. I’ve tried this a dozen times on half a dozen PCs - it’s a bug, the draw calls go up tenfold with the SAME material on the SAME terrain with just the terrain scale being changed. If what you suggest is the culprit I’d see the fps drop right off the bat, without changing the terrain scale.

I feel like you haven’t honestly even read the reproduction steps.

I did read your repro steps, and tried to respond by letting you know that your workflow is incorrect, therefore you are going to experience some issues. Scaling your landscape, especially one the size of 32x32 and with all of your foliage placed on the same material layer, with those densities is definitely going to cause an issue.

Scaling your landscape is not suggested, as it will cause all types of errors. It is best to create the correct scale at the beginning and stick with that. Here is a post that will shed some more light on this.

Changing Landscape Scale

As for the load times of your foliage, this is also mentioned in our documetation and is expected. Especially with the test set up you have provided as all of your meshes are being spawned on the same material layer.

Using the Grass Tools

https://docs.unrealengine.com/latest/INT/Engine/OpenWorldTools/Grass/QuickStart/4/index.html

If you have further questions, let me know.

Thanks,

Hey Andrew,

As I said, my “real” terrain doesn’t put all the meshes everywhere, it samples layers. The behavior is absolutely identical. The loading I am seeing is definitely not the expected behavior as it loads up instantly unless the landscape is scaled down. (It also happens on a packaged build, not in the editor during painting).

However, I see that landscape scaling causes glitches so I’ll see to it to rescale the height map to get the right scale right away.

This is for anyone who is still having trouble with this issue :

Short Answer : You need to call ‘UpdateGrass’ on the landscape proxy actor with bForceSync = true to make all the grass get created at once. This is not available from blueprints, you’re going to need to import that Landscape module and do it in C++.

Long Answer :
The grass is created on a per-landscape actor basis and each frame the grass actor queues up a certain number of subcomponents to have their meshes generated at runtime. The number of tasks it can queue each frame is 4, but regardless is only pops one async tasks off its finished queue each frame. Basically the larger your landscape in terms of components, the more frames it’ll take to render regardless of how dense the foliage is on the landscape.

To understand this go check out ‘LandscapeGrass.cpp’ in the ‘UpdateGrass’ method. You’ll find that if bForceSync is set to true that it’ll make sure to queue up all tasks and wait for them to drain. Otherwise in the queuing logic it checks the ‘AsyncFoliageTasks’ array against the async task counter to queue logic, and at the very bottom of the function it pulls tasks off (and has nice little comment about how ‘one per frame is fine’).

I’m on version 4.16 and before I finish playing on the first frame I make sure that I call this method and all my grass instantly spawns in.

1 Like

is it possible to do this by modifying Landscape.cpp to instantly loading grasses when creating landscape or loading scene as default?

Thanks, it worked! Great help, I was searching the solution in the grass’ LODs, texture streaming but would never figure out!

who want to implement:

void UMyCodeLibrary::UpdateGrass(ALandscapeProxy* landscape)
{
	FOccluderVertexArray arr;
	landscape->UpdateGrass(arr, true);
}
2 Likes

I am using a Blueprint project and having this same issue. Do you mind assisting me on how to implement this? I’ve been looking for a way to do this but I don’t want to blow up my enigne.

Did you add it to a Blueprint project? If so, do you think you could walk me through the steps? It would really help, this is the closest thing that I’ve found to a solution.

Ah shucks, I’ll see if there’s another way to do this. Thanks for answering though!

Hi, unfortunately, no BP/node version available, that’s why I added it in C++.

No, you have to use a C++/BP project.

I’m, using a C++/BP project and still don’t know how to implement that code, any suggestions for a desperate man down on his luck?

For those coming to this later and not skilled in c++. This is my solution. Create an actor, add it to the scene and assign a landscape which you want to spawn immediately.

You also NEED to add Landscape to your project.Build.cs file, otherwise it will fail to find proper libraries.

YourProject.build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Landscape"});)

LFLandscapeGrassHack.h

#pragma once

#include "CoreMinimal.h"
#include "LandscapeProxy.h"
#include "GameFramework/Actor.h"
#include "LandscapeGrassHack.generated.h"

UCLASS()
class YOURPROJECT_API ALandscapeGrassHack : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ALandscapeGrassHack();

	UPROPERTY()
	USceneComponent* Root;

	UPROPERTY(EditAnywhere)
	ALandscapeProxy* Landscape;

protected:
	virtual void BeginPlay() override;

	void UpdateGrass(ALandscapeProxy* LandscapeToUpdate);
};

LandscapeGrassHack.cpp

#include "LandscapeGrassHack.h"

ALandscapeGrassHack::ALandscapeGrassHack()
{
	PrimaryActorTick.bCanEverTick = false;	
	Root = CreateDefaultSubobject<USceneComponent>("Root");
	RootComponent = Root;
}

void ALandscapeGrassHack::BeginPlay()
{
	Super::BeginPlay();
	UpdateGrass(Landscape);
}

void ALandscapeGrassHack::UpdateGrass(ALandscapeProxy* LandscapeToUpdate)
{
	if(!IsValid(LandscapeToUpdate))
	{
		UE_LOG(LogTemp, Warning, TEXT("NO landscape has been assigned, cannot recreate grass"));
		return;
	}
	FOccluderVertexArray arr;
	LandscapeToUpdate->UpdateGrass(arr, true);
}
2 Likes

Thank you, this was a straightforward solution, which did the job.

In Unreal Engine 5, there seems to be no FOccluderVertexArray, so when I was upgrading, I needed to pass a simple array in to make it work:

void UMyCodeLibrary::UpdateGrass(ALandscapeProxy* landscape)
{
	const TArray<FVector> arr;
	landscape->UpdateGrass(arr, true);
}
1 Like

This solution worked! Thank you so much.
Since I’m using UE5 I had to add the array @Kaspi mentioned.

When I have this actor enabled it causes all the foliage on the map to be visible and ignores the cull distances. This is obviously very bad for FPS. Is anyone else also experiencing this? Is there something that I would need to add to the code to enable the distant foliage to be culled again?

Distance culling works fine when I don’t run this code, but then the foliage takes forever to load again.