ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UE4 绘制Gizmo

2022-02-02 14:03:57  阅读:452  来源: 互联网

标签:LocalToWorld const 绘制 Result UE4 true 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

//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();

                    //UE封装了很多绘制函数,可以去看下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);//把自己传进去,然后把FPrimitiveSceneProxy信息返回

}

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构造函数中编写逻辑自动挂载组件:

#include "MyTestActor.h"

AMyTestActor::AMyTestActor()//构造函数这里进行挂载
{
    PrimaryActorTick.bCanEverTick = true;

    UMyPrimitiveComponent* Gizmo = NewObject<UMyPrimitiveComponent>(this, "Gizmo");
    AddInstanceComponent(Gizmo);
    Gizmo->RegisterComponent();
}

 

标签:LocalToWorld,const,绘制,Result,UE4,true,Gizmo
来源: https://www.cnblogs.com/hont/p/15860271.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有