bool FBeginModifyLandscapeCommand::Update() { //Find the landscape FEdModeLandscape* LandscapeEdMode = (FEdModeLandscape*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_Landscape); //Find a location on the edge of the landscape along the x axis so the default camera can see it in the distance. FVector LandscapeSizePerComponent = LandscapeEdMode->UISettings->NewLandscape_QuadsPerSection * LandscapeEdMode->UISettings->NewLandscape_SectionsPerComponent * LandscapeEdMode->UISettings->NewLandscape_Scale; FVector TargetLoctaion(0); TargetLoctaion.X = -LandscapeSizePerComponent.X * (LandscapeEdMode->UISettings->NewLandscape_ComponentCount.X / 2.f); ALandscapeProxy* Proxy = LandscapeEdMode->CurrentToolTarget.LandscapeInfo.Get()->GetCurrentLevelLandscapeProxy(true); if (Proxy) { TargetLoctaion = Proxy->LandscapeActorToWorld().InverseTransformPosition(TargetLoctaion); } //Begin using the sculpting tool FLevelEditorViewportClient* SelectedViewport = LandscapeTestUtils::FindSelectedViewport(); LandscapeEdMode->CurrentTool->BeginTool(SelectedViewport, LandscapeEdMode->CurrentToolTarget, TargetLoctaion); SelectedViewport->Invalidate(); UE_LOG(LogLandscapeAutomationTests, Display, TEXT("Modified the landscape using the sculpt tool")); return true; }
virtual void EnterTool() { FLandscapeToolPaintBase<ToolTarget, FLandscapeToolStrokeFlatten<ToolTarget>>::EnterTool(); ALandscapeProxy* LandscapeProxy = this->EdMode->CurrentToolTarget.LandscapeInfo->GetLandscapeProxy(); MeshComponent = ConstructObject<UStaticMeshComponent>(UStaticMeshComponent::StaticClass(), LandscapeProxy, NAME_None, RF_Transient); MeshComponent->StaticMesh = PlaneMesh; MeshComponent->AttachTo(LandscapeProxy->GetRootComponent()); MeshComponent->RegisterComponent(); }
FText FLandscapeEditorDetails::GetTargetLandscapeName() { FEdModeLandscape* LandscapeEdMode = GetEditorMode(); if (LandscapeEdMode) { ULandscapeInfo* Info = LandscapeEdMode->CurrentToolTarget.LandscapeInfo.Get(); if (Info) { ALandscapeProxy* Proxy = Info->GetLandscapeProxy(); if (Proxy) { return FText::FromString(Proxy->GetActorLabel()); } } } return FText(); }
/** * Attempts to apply the material to the specified actor. * * @param TargetActor the actor to apply the material to * @param MaterialToApply the material to apply to the actor * @param OptionalMaterialSlot the material slot to apply to. * * @return true if the material was successfully applied to the actor */ bool FActorFactoryAssetProxy::ApplyMaterialToActor( AActor* TargetActor, UMaterialInterface* MaterialToApply, int32 OptionalMaterialSlot ) { bool bResult = false; if ( TargetActor != NULL && MaterialToApply != NULL ) { ALandscapeProxy* Landscape = Cast<ALandscapeProxy>(TargetActor); if (Landscape != NULL) { UProperty* MaterialProperty = FindField<UProperty>(ALandscapeProxy::StaticClass(), "LandscapeMaterial"); Landscape->PreEditChange(MaterialProperty); Landscape->LandscapeMaterial = MaterialToApply; FPropertyChangedEvent PropertyChangedEvent(MaterialProperty); Landscape->PostEditChangeProperty(PropertyChangedEvent); bResult = true; } else { TArray<UActorComponent*> EditableComponents; FActorEditorUtils::GetEditableComponents( TargetActor, EditableComponents ); // Some actors could potentially have multiple mesh components, so we need to store all of the potentially valid ones // (or else perform special cases with IsA checks on the target actor) TArray<USceneComponent*> FoundMeshComponents; // Find which mesh the user clicked on first. TInlineComponentArray<USceneComponent*> SceneComponents; TargetActor->GetComponents(SceneComponents); for ( int32 ComponentIdx=0; ComponentIdx < SceneComponents.Num(); ComponentIdx++ ) { USceneComponent* SceneComp = SceneComponents[ComponentIdx]; // Only apply the material to editable components. Components which are not exposed are not intended to be changed. if( EditableComponents.Contains( SceneComp ) ) { UMeshComponent* MeshComponent = Cast<UMeshComponent>(SceneComp); if((MeshComponent && MeshComponent->IsRegistered()) || SceneComp->IsA<UDecalComponent>()) { // Intentionally do not break the loop here, as there could be potentially multiple mesh components FoundMeshComponents.AddUnique( SceneComp ); } } } if ( FoundMeshComponents.Num() > 0 ) { // Check each component that was found for ( TArray<USceneComponent*>::TConstIterator MeshCompIter( FoundMeshComponents ); MeshCompIter; ++MeshCompIter ) { USceneComponent* SceneComp = *MeshCompIter; bResult = FComponentEditorUtils::AttemptApplyMaterialToComponent(SceneComp, MaterialToApply, OptionalMaterialSlot); } } } } return bResult; }
void RasterizeSegmentPoints(ULandscapeInfo* LandscapeInfo, TArray<FLandscapeSplineInterpPoint> Points, const FTransform& SplineToWorld, bool bRaiseTerrain, bool bLowerTerrain, ULandscapeLayerInfoObject* LayerInfo) { ALandscapeProxy* LandscapeProxy = LandscapeInfo->GetLandscapeProxy(); const FTransform SplineToLandscape = SplineToWorld.GetRelativeTransform(LandscapeProxy->LandscapeActorToWorld()); FLandscapeEditDataInterface LandscapeEdit(LandscapeInfo); TSet<ULandscapeComponent*> ModifiedComponents; // I'd dearly love to use FIntRect in this code, but Landscape works with "Inclusive Max" and FIntRect is "Exclusive Max" int32 LandscapeMinX, LandscapeMinY, LandscapeMaxX, LandscapeMaxY; if (!LandscapeInfo->GetLandscapeExtent(LandscapeMinX, LandscapeMinY, LandscapeMaxX, LandscapeMaxY)) { return; } FBox SegmentBounds = FBox(0); for (const FLandscapeSplineInterpPoint& Point : Points) { SegmentBounds += Point.FalloffLeft; SegmentBounds += Point.FalloffRight; } SegmentBounds = SegmentBounds.TransformBy(SplineToLandscape.ToMatrixWithScale()); int32 MinX = FMath::CeilToInt(SegmentBounds.Min.X); int32 MinY = FMath::CeilToInt(SegmentBounds.Min.Y); int32 MaxX = FMath::FloorToInt(SegmentBounds.Max.X); int32 MaxY = FMath::FloorToInt(SegmentBounds.Max.Y); MinX = FMath::Max(MinX, LandscapeMinX); MinY = FMath::Max(MinY, LandscapeMinY); MaxX = FMath::Min(MaxX, LandscapeMaxX); MaxY = FMath::Min(MaxY, LandscapeMaxY); if (MinX > MaxX || MinY > MaxY) { // The segment's bounds don't intersect the landscape, so skip it entirely return; } for (int32 j = 0; j < Points.Num(); j++) { Points[j].Center = SplineToLandscape.TransformPosition(Points[j].Center); Points[j].Left = SplineToLandscape.TransformPosition(Points[j].Left); Points[j].Right = SplineToLandscape.TransformPosition(Points[j].Right); Points[j].FalloffLeft = SplineToLandscape.TransformPosition(Points[j].FalloffLeft); Points[j].FalloffRight = SplineToLandscape.TransformPosition(Points[j].FalloffRight); // local-heights to texture value heights Points[j].Left.Z = Points[j].Left.Z * LANDSCAPE_INV_ZSCALE + LandscapeDataAccess::MidValue; Points[j].Right.Z = Points[j].Right.Z * LANDSCAPE_INV_ZSCALE + LandscapeDataAccess::MidValue; Points[j].FalloffLeft.Z = Points[j].FalloffLeft.Z * LANDSCAPE_INV_ZSCALE + LandscapeDataAccess::MidValue; Points[j].FalloffRight.Z = Points[j].FalloffRight.Z * LANDSCAPE_INV_ZSCALE + LandscapeDataAccess::MidValue; } // Heights raster if (bRaiseTerrain || bLowerTerrain) { RasterizeSegmentHeight(MinX, MinY, MaxX, MaxY, LandscapeEdit, Points, bRaiseTerrain, bLowerTerrain, ModifiedComponents); if (MinX > MaxX || MinY > MaxY) { // The segment's bounds don't intersect any data, so we skip it entirely // it wouldn't intersect any weightmap data either so we don't even bother trying } } // Blend layer raster if (LayerInfo != NULL) { RasterizeSegmentAlpha(MinX, MinY, MaxX, MaxY, LandscapeEdit, Points, LayerInfo, ModifiedComponents); } LandscapeEdit.Flush(); for (ULandscapeComponent* Component : ModifiedComponents) { // Recreate collision for modified components and update the navmesh ULandscapeHeightfieldCollisionComponent* CollisionComponent = Component->CollisionComponent.Get(); if (CollisionComponent) { CollisionComponent->RecreateCollision(); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(Component); if (NavSys) { NavSys->UpdateNavOctree(CollisionComponent); } } } }