Adjusting How Fast Landscape Grass Appears

Adjusting How Fast Landscape Grass Appears

Article written by Ryan B.

If you find your Landscape Grass taking a long time to appear, there are 3 main CVars that control the speed at which grass will appear that you should try adjusting the following:

grass.TickInterval

Specifies how much time (number of frames) there is between 2 updates of a given landscape proxy with respect to grass. This means every landscape proxy will be updated once every n frames (n = grass.TickInterval). By default, grass.TickInterval is 1 and every landscape proxy will be updated once per frame. At the time of writing this, Fornite uses a grass tick interval of 10.

grass.MaxAsyncTasks

Limits how many async tasks can be spawned to generate grass during a grass tick. Landscape components not being updated during a given frame due to grass.TickInterval will not spawn any tasks. These tasks are deeply nested within 4 distinctive loops of ALandscapeProxy::UpdateGrass (LandscapeGrass.cpp) and depending on the number of grass types, grass varieties, and the number of subsections then only a few of them may be allowed to generate an HISM (hierarchical instanced static mesh) component once the async tasks finish, which is most likely to happen at least “one tick later” because of grass.TickInterval. In ALandscapeProxy::UpdateGrass (LandscapeGrass.cpp):

for (ULandscapeGrassType* GrassType : LandscapeGrassTypes)
{
    ...
    for (auto& GrassVariety : GrassType->GrassVarieties)
    {
        ...
        for (int32 SubX = 0; SubX < SqrtSubsections; SubX++)
		{
			for (int32 SubY = 0; SubY < SqrtSubsections; SubY++)
			{

grass.MaxCreatePerFrame

Sets the max HISM components that can be created per frame. The default value is 1 since the creation of components is expensive. It also means that, across all Landscape proxies, grass types, grass varieties, and subsections, only a single HISM component will be allowed to be created per frame. This can severely delay the processing of a given grass model by preventing anything from being spawned this frame. For further explanation, take a look at this section of code in LandscapeGrass.cpp:

if (!bRebuildForBoxes && !bForceSync && (InOutNumCompsCreated >= GGrassMaxCreatePerFrame || AsyncFoliageTasks.Num() >= MaxTasks))
{
	continue; // one per frame, but we still want to touch the existing ones and we must do the rebuilds because we changed the tag
}

This combination of factors can greatly limit how fast grass will appear when there are multiple grass types or varieties, especially on larger Landscapes that have many Landscape proxies, and are a good starting point for investigating grass showing up late.

See more on the Knowledge Base.

3 Likes