// Copyright Epic Games, Inc. All Rights Reserved. #include "PositionPlaneGizmo.h" #include "InteractiveGizmoManager.h" #include "Generators/MinimalBoxMeshGenerator.h" #include "Materials/MaterialInstanceDynamic.h" #include "Engine/Engine.h" // for GEngine - @todo remove this? #include "ToolSceneQueriesUtil.h" #include "ExplicitUseGeometryMathTypes.h" // using UE::Geometry::(math types) using namespace UE::Geometry; UInteractiveGizmo* UPositionPlaneGizmoBuilder::BuildGizmo(const FToolBuilderState& SceneState) const { UPositionPlaneGizmo* NewGizmo = NewObject(SceneState.GizmoManager); NewGizmo->SetWorld(SceneState.World); return NewGizmo; } void UPositionPlaneGizmo::SetWorld(UWorld* World) { TargetWorld = World; } void UPositionPlaneGizmo::Setup() { UInteractiveGizmo::Setup(); UPositionPlaneOnSceneInputBehavior* MouseBehavior = NewObject(); MouseBehavior->Initialize(this); AddInputBehavior(MouseBehavior); QuickTransformer.Initialize(); bInTransformDrag = false; // create temporary mesh object for pivot CenterBallShape = MakeSphereMesh(); } void UPositionPlaneGizmo::Shutdown() { CenterBallShape->Disconnect(); } UPreviewMesh* UPositionPlaneGizmo::MakeSphereMesh() { UPreviewMesh* PreviewMesh = NewObject(this, TEXT("PreviewMesh")); PreviewMesh->CreateInWorld(this->TargetWorld, FTransform::Identity); PreviewMesh->SetVisible(true); PreviewMesh->bBuildSpatialDataStructure = true; PreviewMesh->bDrawOnTop = true; FLinearColor AxisColorX = FLinearColor(0.594f, 0.0197f, 0.0f); UMaterial* AxisMaterialBase = GEngine->ArrowMaterial; UMaterialInstanceDynamic* AxisMaterialX = UMaterialInstanceDynamic::Create(AxisMaterialBase, NULL); AxisMaterialX->SetVectorParameterValue("GizmoColor", AxisColorX); CenterBallMaterial = AxisMaterialX; //CenterBallMaterial = LoadObject(nullptr, TEXT("/MeshModelingToolset/Materials/GizmoDefaultMaterial")); if (CenterBallMaterial != nullptr) { PreviewMesh->SetMaterial(CenterBallMaterial); } FMinimalBoxMeshGenerator BoxGen; BoxGen.Box = FOrientedBox3d(FVector3d::Zero(), FVector3d(10, 10, 3)); FDynamicMesh3 Mesh(&BoxGen.Generate()); PreviewMesh->UpdatePreview(&Mesh); return PreviewMesh; } void UPositionPlaneGizmo::Render(IToolsContextRenderAPI* RenderAPI) { FPrimitiveDrawInterface* PDI = RenderAPI->GetPrimitiveDrawInterface(); FViewCameraState CameraState; GetGizmoManager()->GetContextQueriesAPI()->GetCurrentViewState(CameraState); QuickTransformer.UpdateCameraState(CameraState); FTransform Transform = CenterBallShape->GetTransform(); FMatrix Matrix = Transform.ToMatrixNoScale(); DrawBox(PDI, Matrix, FVector(10, 10, 3), CenterBallMaterial->GetRenderProxy(), SDPG_Foreground); //DrawSphere(PDI, FVector(0, 0, 100), FRotator(), FVector(50, 50, 50), 16, 16, // CenterBallMaterial->GetRenderProxy(), SDPG_Foreground); // if (bInTransformDrag) { QuickTransformer.Render(RenderAPI); } } bool UPositionPlaneGizmo::HitTest(const FRay& Ray, FHitResult& OutHit) { if (CenterBallShape->TestRayIntersection(FRay3d(Ray))) { OutHit.Distance = 0.1; return true; } return false; } void UPositionPlaneGizmo::OnBeginDrag(const FRay& Ray) { bInTransformDrag = true; FTransform CurTransform = CenterBallShape->GetTransform(); QuickTransformer.SetActiveFrameFromWorldNormal( (FVector3d)CurTransform.GetTranslation(), (FVector3d)CurTransform.GetRotation().GetAxisZ(), true); } void UPositionPlaneGizmo::OnUpdateDrag(const FRay& Ray) { if (bInTransformDrag) { FVector3d SnapPos; if (QuickTransformer.UpdateSnap(FRay3d(Ray), SnapPos)) { FTransform CurTransform = CenterBallShape->GetTransform(); CurTransform.SetTranslation((FVector)SnapPos); CenterBallShape->SetTransform(CurTransform); PostUpdatedPosition(); } } else { FHitResult Result; bool bHitWorld = ToolSceneQueriesUtil::FindNearestVisibleObjectHit(TargetWorld, Result, Ray); if (bHitWorld) { FFrame3f UpdatedFrame(CenterBallShape->GetTransform()); UpdatedFrame.AlignAxis(2, (FVector3f)Result.ImpactNormal); UpdatedFrame.Origin = (FVector3f)Result.ImpactPoint; CenterBallShape->SetTransform(UpdatedFrame.ToFTransform()); PostUpdatedPosition(); } } } void UPositionPlaneGizmo::OnEndDrag(const FRay& Ray) { bInTransformDrag = false; } void UPositionPlaneGizmo::ExternalUpdatePosition(const FVector& Position, const FQuat& Orientation, bool bPostUpdate) { CenterBallShape->SetTransform(FTransform(Orientation, Position)); if (bPostUpdate) { PostUpdatedPosition(); } } void UPositionPlaneGizmo::PostUpdatedPosition() { FFrame3d CurPosition(CenterBallShape->GetTransform()); if (OnPositionUpdatedFunc != nullptr) { OnPositionUpdatedFunc(CurPosition); } } /* * Mouse Input Behavior */ void UPositionPlaneOnSceneInputBehavior::Initialize(UPositionPlaneGizmo* GizmoIn) { this->Gizmo = GizmoIn; bInDragCapture = false; } FInputCaptureRequest UPositionPlaneOnSceneInputBehavior::WantsCapture(const FInputDeviceState& input) { if (IsPressed(input)) { FHitResult OutHit; if (Gizmo->HitTest(input.Mouse.WorldRay, OutHit)) { return FInputCaptureRequest::Begin(this, EInputCaptureSide::Any, OutHit.Distance); } } return FInputCaptureRequest::Ignore(); } FInputCaptureUpdate UPositionPlaneOnSceneInputBehavior::BeginCapture(const FInputDeviceState& input, EInputCaptureSide eSide) { //Gizmo->SetShiftToggle(input.bShiftKeyDown); Gizmo->OnBeginDrag(input.Mouse.WorldRay); LastWorldRay = input.Mouse.WorldRay; bInDragCapture = true; return FInputCaptureUpdate::Begin(this, EInputCaptureSide::Any); } FInputCaptureUpdate UPositionPlaneOnSceneInputBehavior::UpdateCapture(const FInputDeviceState& input, const FInputCaptureData& data) { LastWorldRay = input.Mouse.WorldRay; if (IsReleased(input)) { Gizmo->OnEndDrag(input.Mouse.WorldRay); bInDragCapture = false; return FInputCaptureUpdate::End(); } Gizmo->OnUpdateDrag(input.Mouse.WorldRay); return FInputCaptureUpdate::Continue(); } void UPositionPlaneOnSceneInputBehavior::ForceEndCapture(const FInputCaptureData& data) { if (bInDragCapture) { Gizmo->OnEndDrag(LastWorldRay); bInDragCapture = false; } // nothing to do }