Hey @TimeWinder2 ,
I ran into the same issue. After changing the Transform on the object at runtime, the water suddenly appeared. Then I added the “UpdateAll” method call and it loaded the water correctly at runtime. Hope this helps.
UE::Geometry::FDynamicMesh3 WaterMeshRef;
UE::Geometry::FDynamicMesh3 DilatedMeshRef;
WaterBody = World->SpawnActor<ABellwetherWaterBody>(ABellwetherWaterBody::StaticClass(), GetActorLocation(), GetActorRotation());
WaterBody->InitializeBody();
WaterBody->SetActorScale3D(FVector(5.0f, 5.0f, 5.0f));
WaterBody->SetActorLocation(FVector(0.0f, 0.0f, 0.0f));
WaterBody->MarkComponentsRenderStateDirty();
WaterBody->UpdateComponentTransforms();
UGerstnerWaterWaves* Waves = NewObject<UGerstnerWaterWaves>(WaterBody, UGerstnerWaterWaves::StaticClass(), TEXT("WaterWaves"));
UGerstnerWaterWaveGeneratorSimple* WaveGenerator = NewObject<UGerstnerWaterWaveGeneratorSimple>(Waves, UGerstnerWaterWaveGeneratorSimple::StaticClass(), TEXT("GerstnerWaterWaveGeneratorSimple"));
Waves->GerstnerWaveGenerator = WaveGenerator;
WaterBody->SetWaterWaves(Waves);
UWaterBodyComponent* WaterBodyComponent = WaterBody->GetWaterBodyComponent();
WaterBodyComponent->SetMobility(EComponentMobility::Movable);
UWaterBodyLakeComponent* LakeComponent = Cast<UWaterBodyLakeComponent>(WaterBodyComponent);
LakeComponent->SetMobility(EComponentMobility::Movable);
WaterBodyManager->AddWaterBodyComponent(WaterBodyComponent);
WaterBodyComponent->ShouldGenerateWaterMeshTile();
WaterBodyComponent->UpdateWaterZones();
AWaterZone* WaterZone = WaterBodyComponent->GetWaterZone();
WaterBodyComponent->SetWaterZoneOverride(WaterZone);
WaterBodyComponent->WaterMaterial = LoadObject<UMaterialInterface>(nullptr, TEXT("/Water/Materials/WaterSurface/Water_Material_Lake.Water_Material_Lake"));
FWaterBodyHeightmapSettings* HeightmapSettings = new FWaterBodyHeightmapSettings();
HeightmapSettings->BlendMode = EWaterBrushBlendType::AlphaBlend;
FWaterCurveSettings* WaterCurveSettings = new FWaterCurveSettings();
WaterCurveSettings->ChannelDepth = 500.0f;
WaterCurveSettings->bUseCurveChannel = true;
WaterCurveSettings->ChannelEdgeOffset = 0.0f;
WaterCurveSettings->CurveRampWidth = 2000.0f;
WaterCurveSettings->ElevationCurveAsset = LoadObject<UCurveFloat>(nullptr, TEXT("/Water/Curves/FloatCurve.FloatCurve"));
if (!WaterCurveSettings->ElevationCurveAsset)
{
UE_LOG(LogTemp, Warning, TEXT("Failed to load ElevationCurveAsset! Check the path."));
}
WaterBodyComponent->CurveSettings = *WaterCurveSettings;
WaterBodyComponent->WaterHeightmapSettings = *HeightmapSettings;
WaterBodyComponent->WaterHLODMaterial = LoadObject<UMaterialInterface>(nullptr, TEXT("/Water/Materials/HLOD/HLODWater.HLODWater"));
UDynamicMeshComponent* WaterMeshComp = NewObject<UDynamicMeshComponent>(this);
WaterMeshComp->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
WaterMeshComp->RegisterComponent();
WaterMeshComp->SetCastShadow(false);
WaterMeshComp->GetDynamicMesh()->EditMesh([&](FDynamicMesh3& MeshRef)
{
MeshRef.EnableAttributes();
MeshRef.Attributes()->EnablePrimaryColors();
MeshRef.Attributes()->EnableTangents();
}, EDynamicMeshChangeType::GeneralEdit);
UE_LOG(LogTemp, Log, TEXT("Assigning material to mesh component."));
WaterMeshComp->SetMaterial(0, WaterMaterial);
if (UBodySetup* BodySetup = WaterMeshComp->GetBodySetup())
{
BodySetup->InvalidatePhysicsData();
BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
BodySetup->CreatePhysicsMeshes();
WaterMeshComp->RecreatePhysicsState();
}
WaterMeshComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
WaterMeshComp->SetCollisionResponseToAllChannels(ECR_Block);
WaterMeshComp->SetCollisionObjectType(ECC_WorldStatic);
WaterMeshComp->EnableComplexAsSimpleCollision();
WaterMeshComp->UpdateComponentToWorld();
WaterMeshComp->MarkRenderStateDirty();
WaterMeshComp->MarkRenderDynamicDataDirty();
WaterMeshComp->SetMobility(EComponentMobility::Movable);
UDynamicMeshComponent* DilatedWaterMeshComp = NewObject<UDynamicMeshComponent>(this);
DilatedWaterMeshComp->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
DilatedWaterMeshComp->RegisterComponent();
DilatedWaterMeshComp->SetCastShadow(false); // clearly disable shadows on water mesh
DilatedWaterMeshComp->GetDynamicMesh()->EditMesh([&](FDynamicMesh3& MeshRef)
{
MeshRef.EnableAttributes();
MeshRef.Attributes()->EnablePrimaryColors();
MeshRef.Attributes()->EnableTangents();
}, EDynamicMeshChangeType::GeneralEdit);
UE_LOG(LogTemp, Log, TEXT("Assigning material to mesh component."));
DilatedWaterMeshComp->SetMaterial(0, WaterMaterial);
if (UBodySetup* BodySetup = DilatedWaterMeshComp->GetBodySetup())
{
BodySetup->InvalidatePhysicsData();
BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;
BodySetup->CreatePhysicsMeshes();
DilatedWaterMeshComp->RecreatePhysicsState();
}
DilatedWaterMeshComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
DilatedWaterMeshComp->SetCollisionResponseToAllChannels(ECR_Block);
DilatedWaterMeshComp->SetCollisionObjectType(ECC_WorldStatic);
DilatedWaterMeshComp->EnableComplexAsSimpleCollision();
DilatedWaterMeshComp->UpdateComponentToWorld();
DilatedWaterMeshComp->MarkRenderStateDirty();
DilatedWaterMeshComp->MarkRenderDynamicDataDirty();
DilatedWaterMeshComp->SetMobility(EComponentMobility::Movable);
// Extract Water Mesh
WaterMeshComp->GetDynamicMesh()->ProcessMesh([&](const FDynamicMesh3& Mesh)
{
WaterMeshRef = Mesh; // Copy actual mesh data
});
// Extract Dilated Mesh (if available)
if (DilatedWaterMeshComp)
{
DilatedWaterMeshComp->GetDynamicMesh()->ProcessMesh([&](const FDynamicMesh3& Mesh)
{
DilatedMeshRef = Mesh; // Copy actual mesh data
});
}
WaterBodyComponent->SetWaterBodyStaticMeshEnabled(true);
FOnWaterBodyChangedParams OnWaterBodyChangedParams;
OnWaterBodyChangedParams.bShapeOrPositionChanged = true;
OnWaterBodyChangedParams.bUserTriggered = true;
OnWaterBodyChangedParams.bWeightmapSettingsChanged = true;
WaterBodyComponent->UpdateAll(OnWaterBodyChangedParams);
WaterBodyComponent->GenerateWaterBodyMesh(WaterMeshRef, DilatedWaterMeshComp ? &DilatedMeshRef : nullptr);
WaterSubsystem->MarkAllWaterZonesForRebuild(
EWaterZoneRebuildFlags::All,
nullptr
);
// delete FalloffSettings;
delete HeightmapSettings;
delete WaterCurveSettings;