当前位置:网站首页>Quick start of UI component development of phantom engine [umg/slate]

Quick start of UI component development of phantom engine [umg/slate]

2022-07-05 03:28:00 Brain in new VAT

Unreal Of UMG Provides quite a number of UI Widget, And allow you to do many things in the blueprint . however , Sometimes you may still need to create customizations Widget To fill in the blanks . In this article, we will introduce how to use custom rendering to create Slate Widget Basic knowledge of .

 Insert picture description here

UMG Widget Two classes are involved :

  • One UWidget Derived class , You can interact with it in the editor
  • One SCompoundWidget class , Deal with low-level functions and rendering

Let's see a simple example of slicing UMG Widget, It has a given starting angle and arc size . We can control the color and opacity , And you can choose to use the image to render it :

 Insert picture description here

1、 Minimum UMG Widget class

First , We will add classes without any functionality , And make sure we see the new widget appear in the editor panel .

This is a UMG Minimize header file for widget :

UCLASS()
class CUSTOMWIDGET_API USlice : public UWidget
{
  GENERATED_BODY()
public:
  virtual void ReleaseSlateResources(bool bReleaseChildren) override;

protected:
  virtual TSharedRef<SWidget> RebuildWidget() override;
  TSharedPtr<SSlateSlice> MySlice;
};
 Corresponding CPP The documents are as follows :

void USlice::ReleaseSlateResources(bool bReleaseChildren)
{
  MySlice.Reset();
}

TSharedRef<SWidget> USlice::RebuildWidget()
{
  MySlice = SNew(SSlateSlice);
  return MySlice.ToSharedRef();
}

Please note that , Creating a new UMG Widget when , These two methods must always be implemented - RebuildWidget Responsible for building Slate Widget, ReleaseSlateResources Responsible for cleaning up resources .

2、 Minimum Slate Widget class

This is a UMG Widget Class referenced Slate class :

class CUSTOMWIDGET_API SSlateSlice : public SCompoundWidget
{
public:
  SLATE_BEGIN_ARGS(SSlateSlice)
  {}
  SLATE_END_ARGS()

  void Construct(const FArguments& InArgs);
};

And corresponding CPP file :

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlateSlice::Construct(const FArguments& InArgs)
{
}

END_SLATE_FUNCTION_BUILD_OPTIMIZATION
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION and END_SLATE_FUNCTION_BUILD_OPTIMIZATION Often in Construct Use around functions , Because it may eventually produce a very complex expression , The compiler may spend a lot of time trying to optimize . These macros close and turn optimization on again .

3、 Pass on Widget attribute

To make our UMG Widget Draw slice , You need to add some attributes to determine its appearance . First , We will Brush、Angle and ArcSize Add to UMG Widget:

  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
  FSlateBrush Brush;

  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
  float Angle;

  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
  float ArcSize;

We still need to Slate Class . They are all added as parameters to SLATE_BEGIN_ARGS / SLATE_END_ARGS In macro , And the regular member variables in the class :

  SLATE_BEGIN_ARGS(SSlateSlice)
  {}
  SLATE_ARGUMENT(FSlateBrush*, Brush)
  SLATE_ARGUMENT(float, Angle)
  SLATE_ARGUMENT(float, ArcSize)
  SLATE_END_ARGS()
  
  ...
  
protected:
  FInvalidatableBrushAttribute Brush;
  float Angle;
  float ArcSize;  

RebuildWidget Method needs to change these attributes from UMG Widget Pass to Slate Widget:

TSharedRef<SWidget> USlice::RebuildWidget()
{
  MySlice = SNew(SSlateSlice)
    .Brush(&Brush)
    .Angle(Angle)
    .ArcSize(ArcSize);
  return MySlice.ToSharedRef();
}

Slate Widget Now treat these attributes as Construct Method :

void SSlateSlice::Construct(const FArguments& InArgs)
{
  Brush = FInvalidatableBrushAttribute(InArgs._Brush);
  Angle = InArgs._Angle;
  ArcSize = InArgs._ArcSize;
}

Each defined in the class header SLATE_ARGUMENT Add as a member to FArguments In structure , And underline its name .Construct Method just copies these values into class member variables , For later rendering Widget When using them .

4、Widget Rendering

Now we can finally add OnPaint The method , It deals with Widget The actual rendering of .

At this point , I won't go into details on all the parameters - Here are the parameters we refer to in the following methods :

  • AllottedGeometry For us Widget Location and size of
  • OutDrawElements Receive for rendering Widget Drawing elements of
  • nWidgetStyle It provides us with the color and opacity that should be applied

FSlateDrawElement It's rendering Slate Widget Main force . It has a draw box 、 Line 、 Text 、 Spline, etc . We will use vertices here ( stay 2D In the space ) And index to render arbitrary meshes .

We need to fill the vertices FSlateVertex Structural TArray, And defining a triangle constructed from vertices SlateIndex (uint32) Index value TArray.

To render slices , We add a vertex in the center , Then add edge vertices along the arc . Then the index buffer uses the center and a pair of continuous edge vertices to define the triangle . The color of each vertex is calculated by modulating the brush color using the color and opacity passed in through the widget style and the overall color and opacity of the widget .

If the brush uses an image , We can also set for vertices UV coordinate —— I won't consider it for the time being .

int32 SSlateSlice::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
  FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
  bool bParentEnabled) const
{
  const FVector2D Pos = AllottedGeometry.GetAbsolutePosition();
  const FVector2D Size = AllottedGeometry.GetAbsoluteSize();
  const FVector2D Center = Pos + 0.5 * Size;
  const float Radius = FMath::Min(Size.X, Size.Y) * 0.5f;

  const FSlateBrush* SlateBrush = Brush.GetImage().Get();
  FLinearColor LinearColor = ColorAndOpacity.Get() * InWidgetStyle.GetColorAndOpacityTint() * SlateBrush->GetTint(InWidgetStyle);
  FColor FinalColorAndOpacity = LinearColor.ToFColor(true);

  const int NumSegments = FMath::RoundToInt(ArcSize / 10.0f);
  TArray<FSlateVertex> Vertices;
  Vertices.Reserve(NumSegments + 3);

  // Add center vertex
  Vertices.AddZeroed();
  FSlateVertex& CenterVertex = Vertices.Last();

  CenterVertex.Position = Center;
  CenterVertex.Color = FinalColorAndOpacity;

  // Add edge vertices
  for (int i = 0; i < NumSegments + 2; ++i)
  {
    const float CurrentAngle = FMath::DegreesToRadians(ArcSize * i / NumSegments + Angle);
    const FVector2D EdgeDirection(FMath::Cos(CurrentAngle), FMath::Sin(CurrentAngle));
    const FVector2D OuterEdge(Radius*EdgeDirection);

    Vertices.AddZeroed();
    FSlateVertex& OuterVert = Vertices.Last();

    OuterVert.Position = Center + OuterEdge;
    OuterVert.Color = FinalColorAndOpacity;
  }

  TArray<SlateIndex> Indices;
  for (int i = 0; i < NumSegments; ++i)
  {
    Indices.Add(0);
    Indices.Add(i);
    Indices.Add(i + 1);
  }

  const FSlateResourceHandle Handle = FSlateApplication::Get().GetRenderer()->GetResourceHandle( *SlateBrush );
  FSlateDrawElement::MakeCustomVerts(
        OutDrawElements,
        LayerId,
        Handle,
        Vertices,
        Indices,
        nullptr,
        0,
        0
    );
  return LayerId;
}

This allows us to render slices in different sizes and colors :

 Insert picture description here

5、 to update Widget attribute

In order for the editor to work properly , We need to be in Slate The properties in the widget are UMG Update widgets as they change . We rewrite SynchronizeProperties Function to do this :

void USlice::SynchronizeProperties()
{
  Super::SynchronizeProperties();
  MySlice->SetBrush(&Brush);
  MySlice->SetAngle(Angle);
  MySlice->SetArcSize(ArcSize);
}

Slate Widgets need the following setter function :

void SSlateSlice::SetBrush(FSlateBrush* InBrush)
{
  Brush.SetImage(*this, InBrush);
}

void SSlateSlice::SetAngle(float InAngle)
{
  Angle = InAngle;
}

void SSlateSlice::SetArcSize(float InArcSize)
{
  ArcSize = InArcSize;
}

Now? , Just change any attribute in the editor , The slice will be updated immediately .

6、 Set up Widget Category

Unless otherwise specified , otherwise Widget stay UMG Designer's Widget The panel displays as unclassified . To set a category , Please add a pair GetPaletteCategory The covering of functions :

#if WITH_EDITOR
const FText USlice::GetPaletteCategory()
{
  return LOCTEXT("CustomPaletteCategory", "My custom category!");
}
#endif

 Insert picture description here

7、 follow-up work

The source code involved in this article can be obtained from GitHub library Download .

Be able to communicate with Unreal In the conventional UMG Widget Before comparison , There is still much work to be done . for example , Property does not support animation , Nor does it support attribute binding . I also didn't discuss the mouse event ——UMG( and Slate) All in Widget It's all rectangular , So in irregular shape Widget It takes some skills to handle the mouse correctly .

Implement customization Widget One potential reason for is optimization - for example , Realize a single... That combines multiple element rendering Widget It could be faster - I will discuss this in the near future .


Link to the original text :Slate Widget Development tutorial — BimAnt

原网站

版权声明
本文为[Brain in new VAT]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202140737211872.html