• UE4 绘制Gizmo


    Unity的Gizmos可以很方便的在编辑器下进行调试,Unreal中也有一些办法可以达到效果。

    本文主要参考:https://zhuanlan.zhihu.com/p/363625037,进行了一些简化。并在Unreal 4.27中实现。

    具体流程如下:

    1. 需要绘制Gizmo的Actor挂载继承UPrimitiveComponent的组件;该组件重写了CreateSceneProxy方法,这个方法里可以拿到PDI绘制
    2. 然后进行这个组件的编写(继承UPrimitiveComponent实际上也继承了USceneComponent),手动挂载到Actor上就可以绘制Gizmo了
    3. 再在Actor的构造函数中编写自动挂载该组件的逻辑,方便使用

    先来编写绘制Gizmo的组件,这里命名为UMyPrimitiveComponent:

    MyPrimitiveComponent.h (MYPROJECT_API注意替换)

    //MyPrimitiveComponent.h
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Components/PrimitiveComponent.h"
    #include "PrimitiveSceneProxy.h"
    #include "MyPrimitiveComponent.generated.h"
    
    UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
    class MYPROJECT_API UMyPrimitiveComponent : public UPrimitiveComponent
    {
        GENERATED_BODY()
        
    public:
        //绘制逻辑主要在这里
        virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
    
        //如果要在非选中情况下始终绘制的话,需要有Bounds信息,所以要重写该函数
        virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const;
    };

    MyPrimitiveComponent.cpp

    //MyPrimitiveComponent.cpp
    #include "MyPrimitiveComponent.h"
    
    FPrimitiveSceneProxy* UMyPrimitiveComponent::CreateSceneProxy()
    {
        class FMySceneProxy : public FPrimitiveSceneProxy
        {
        public:
    
            SIZE_T GetTypeHash() const override
            {
                static size_t UniquePointer;
                return reinterpret_cast<size_t>(&UniquePointer);
            }
    
            FMySceneProxy(const UPrimitiveComponent* InComponent) : FPrimitiveSceneProxy(InComponent)
            {
                CacheInComponent = InComponent;
                bWillEverBeLit = false;
            }
    
            virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
            {
                QUICK_SCOPE_CYCLE_COUNTER(STAT_Draw3DAgentSceneProxy_GetDynamicMeshElements);
    
                for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
                {
                    if (VisibilityMap & (1 << ViewIndex))
                    {
                        const FSceneView* View = Views[ViewIndex];
                        FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
    
                        //拿到Actor的矩阵绘制,而不是Component自己的
                        const FMatrix& LocalToWorld = CacheInComponent->GetTypedOuter<AActor>()->GetTransform().ToMatrixWithScale();
    
                        //绘制函数可以去看下PrimitiveDrawingUtils.cpp
                        DrawOrientedWireBox(PDI
                            , LocalToWorld.TransformPosition(FVector::ZeroVector)
                            , LocalToWorld.GetScaledAxis(EAxis::X)
                            , LocalToWorld.GetScaledAxis(EAxis::Y)
                            , LocalToWorld.GetScaledAxis(EAxis::Z)
                            , FVector(100.0, 100.0, 100.0)
                            , FLinearColor(1.0, 0.0, 0.0, 1.0)
                            , SDPG_World
                            , 1.0);
                    }
                }
            }
            virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
            {
                /*const bool bVisibleForSelection = IsSelected();
                const bool bShowForCollision = View->Family->EngineShowFlags.Collision && IsCollisionEnabled();
    
                FPrimitiveViewRelevance Result;
                Result.bDrawRelevance = (IsShown(View) && bVisibleForSelection) || bShowForCollision;
                Result.bDynamicRelevance = true;
                Result.bShadowRelevance = IsShadowCast(View);
                Result.bEditorPrimitiveRelevance = true;
                Result.bEditorNoDepthTestPrimitiveRelevance = true; */
                //上面这段表示选中绘制Gizmo
    
                FPrimitiveViewRelevance Result;
                Result.bDrawRelevance = true;
                Result.bDynamicRelevance = true;
                Result.bShadowRelevance =false;
                Result.bEditorPrimitiveRelevance = true;
                Result.bEditorNoDepthTestPrimitiveRelevance = true;
                //这段表示始终绘制
    
                return Result;
            }
    
            virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
            uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
    
        private:
            const UPrimitiveComponent* CacheInComponent;
        };
    
        return new FMySceneProxy(this);
    }
    
    FBoxSphereBounds UMyPrimitiveComponent::CalcBounds(const FTransform& LocalToWorld) const
    {
        return FBoxSphereBounds(FBox(FVector(-50, -50, -50), FVector(50, 50, 50))).TransformBy(LocalToWorld);
        //因为缩放是1,这里填的就是实际尺寸,也可以遍历所有组件取最大Bounds.
    }

    然后手动再挂载一下组件,就有效果了:

    如果需要像Unity那样;直接就有Gizmo,可以在Actor构造函数中编写逻辑自动挂载组件:

    AMyTestActor::AMyTestActor()
    {
        UBBoxActorGizmoComponent* Gizmo = CreateDefaultSubobject<UBBoxActorGizmoComponent>(TEXT("Gizmo"));
        if (Gizmo)
        {
            Gizmo->SetupAttachment(GetRootComponent());
        }
    }
  • 相关阅读:
    Redis 设置密码登录
    SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换...
    laravel 博客项目部署到Linux系统后报错 权限都设置为777,仍然报错没有权限
    linux用netstat查看服务及监听端口
    redis使用rediscli查看所有的keys及清空所有的数据
    一起谈.NET技术,Oxite 项目结构分析 狼人:
    一起谈.NET技术,VS 2010 和 .NET 4.0 系列之《在VS 2010中查询和导航代码》篇 狼人:
    一起谈.NET技术,VS 2010 和 .NET 4.0 系列之《添加引用对话框的改进》篇 狼人:
    一起谈.NET技术,VS 2010 和 .NET 4.0 系列之《代码优化的Web开发Profile》篇 狼人:
    一起谈.NET技术,数组排序方法的性能比较(3):LINQ排序实现分析 狼人:
  • 原文地址:https://www.cnblogs.com/hont/p/15860271.html
Copyright © 2020-2023  润新知