Updating Landscape during runtime

Hi all!

I’m trying to dynamically update Landscape components during runtime, but hit a wall and need some help.
Here’s what I got so far.


void ATerrainImporter::CreateTerrain()
{
	// Generate 8x8 array with height 65000
	uint16 *Heights;
	GenerateHeights(8, 8, 65000, &Heights);

	for (TActorIterator<ALandscapeProxy> ActorItr(GetWorld()); ActorItr; ++ActorItr)
	{
		TArray<ULandscapeHeightfieldCollisionComponent*> Components = ActorItr->CollisionComponents;

		for (int c = 0; c < Components.Num(); c++)
		{
			UpdateTexture(Components[c]->RenderComponent->HeightmapTexture, Heights);
			//UpdateCollision(Components[c], Heights);
		}
	}

	delete] Heights;
}

The visible height of the terrain DOES change, but appears completely black and stops casting shadow (even with only Movable light sources).
Unfortunately, I can’t find a way to update the colliders - function ‘UpdateCollision’ is the closest I could get to finding what seemed collision related, but doesn’t work and can randomly crash the editor.

Landscape->Import(…) is a no-go, since it only works inside editor.

Any ideas?


void UpdateTexture(UTexture2D *InTexture, uint16 *InSource)
{
	for (int m = 0; m < InTexture->PlatformData->Mips.Num(); m++)
	{
		uint16 *Dest = (uint16*)InTexture->PlatformData->Mips[m].BulkData.Lock(LOCK_READ_WRITE);

		// How many pixels to advance for given Mip level
		uint16 StepX = (uint16)pow(2.0f, m);	
		uint16 StepY = (StepX - 1) * InTexture->PlatformData->Mips[0].SizeX;

		for (uint16 y = 0; y < InTexture->PlatformData->Mips[m].SizeY; y++, InSource += StepY)
			for (uint16 x = 0; x < InTexture->PlatformData->Mips[m].SizeX; x++, InSource += StepX)
			{
				*(Dest++) = *InSource;
				// No idea what the reverse is used for, but doesn't work otherwise
				*(Dest++) = Reverse(*InSource);
			}

		// Reset Source
		InSource -= InTexture->PlatformData->Mips[0].SizeX * InTexture->PlatformData->Mips[0].SizeY;
		InTexture->PlatformData->Mips[m].BulkData.Unlock();
	}

	InTexture->UpdateResource();
}


void UpdateCollision(ULandscapeHeightfieldCollisionComponent* InComponent, uint16 *InSource)
{
	uint16 *Dest = (uint16*)InComponent->CollisionHeightData.Lock(LOCK_READ_WRITE);

	for (int i = 0; i < InComponent->CollisionHeightData.GetElementCount(); i++, InSource++, Dest++)
		*Dest = *InSource;

	InComponent->CollisionHeightData.Unlock();

	// Editor only
	//Components[c]->UpdateHeightfieldRegion(0, 0, 1, 1);
}

Hi,

Did you managed to go further on this?

Any luck with this? hoping to do the same thing!

Phoboz, have you managed to fix the collisions issue? I’d need an invisible but deforming and colliding terrain but no idea how to pull it off.

Im intersted in this topic too, but now is too early for me to working with it. But when Im looking at this…

Collision update fails probably because ULandscapeHeightfieldCollisionComponent::CollisionHeightData is marked with WITH_EDITORONLY_DATA.
Some time ago I read that navigation system is updated in run-time based on height data through TRefCountPtr<FPhysXHeightfieldRef> HeightfieldRef.

FPhysXHeightfieldRef is a struct that hold pointers to PhysX structures RBHeightfield and RBHeightfieldSimple, both of PhysX type PxHeightfield.
The PxHeightfield has a method modifySamples.

IMHO it is worth to look into the functions:

  • void ULandscapeHeightfieldCollisionComponent::CreatePhysicsState() (LandscapeCollision.cpp)
  • virtual void ExportPxHeightField(physx::PxHeightField const * const HeightField, const FTransform& LocalToWorld) (RecastNavMeshGenerator.cpp)

Deeper digging in engine code and another interesting function

  • ConvertHeightfieldDataForPhysx ( alse LandscapeCollision.cpp)
1 Like

In a topic i created with a pretty different question somebody (sorta) mentioned this plugin: Runtime Mesh Component
And (having seen this topic earlier) i was just thinking this may actually be what you guys are looking for, im sure you can can make some landscape out of tiles of that.
Just a thought :slight_smile: