IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 虚幻引擎UI组件开发快速入门【UMG/Slate】 -> 正文阅读

[游戏开发]虚幻引擎UI组件开发快速入门【UMG/Slate】

Unreal 的 UMG 提供了相当多的UI Widget,并允许你在蓝图中做很多事情。但是,有时可能仍需要创建自定义Widget来填补空白。这篇文章中将介绍使用自定义渲染创建Slate Widget的基础知识。

在这里插入图片描述

UMG Widget涉及两个类:

  • 一个 UWidget 派生类,可以在编辑器中与之交互
  • 一个 SCompoundWidget 类,处理低级功能和渲染

让我们看一个展示切片的简单UMG Widget,它具有给定的起始角度和圆弧大小。我们可以控制颜色和不透明度,并且可以选择使用图像来渲染它:

在这里插入图片描述

1、最小UMG Widget类

首先,我们将添加没有任何功能的类,并确保我们看到新的小部件出现在编辑器面板中。

这是一个 UMG 小部件的最小化头文件:

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;
};
对应的CPP文件如下:

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

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

请注意,在创建新UMG Widget时,始终必须实现这两个方法 - RebuildWidget负责构建 Slate Widget, ReleaseSlateResources负责清理资源。

2、最小Slate Widget类

这是 UMG Widget类引用的 Slate 类:

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

  void Construct(const FArguments& InArgs);
};

以及对应的CPP文件:

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

END_SLATE_FUNCTION_BUILD_OPTIMIZATION
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION和END_SLATE_FUNCTION_BUILD_OPTIMIZATION经常在Construct函数周围使用,因为它最终可能会产生一个非常复杂的表达式,编译器可能会花费大量时间来尝试优化。这些宏关闭并再次打开优化。

3、传递Widget属性

为了让我们的UMG Widget绘制切片,需要添加一些属性来确定它的外观。首先,我们将Brush、Angle和ArcSize添加到 UMG Widget:

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

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

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

我们还需要在 Slate 类中添加类似的属性。它们都作为参数添加到 SLATE_BEGIN_ARGS / SLATE_END_ARGS宏中,以及类中的常规成员变量:

  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方法需要将这些属性从 UMG Widget传递给 Slate Widget:

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

Slate Widget现在将这些属性作为Construct方法的参数获取:

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

在类头中定义的每个SLATE_ARGUMENT作为成员添加到FArguments结构中,并在其名称前加上下划线。Construct方法只是将这些值复制到类成员变量中,以便稍后在渲染Widget时使用它们。

4、Widget渲染

现在我们终于可以添加OnPaint方法了,它处理Widget的实际渲染。

在这一点上,我不会详细介绍所有参数 - 以下是我们在以下方法中引用的参数:

  • AllottedGeometry为我们提供了Widget的位置和大小
  • OutDrawElements接收用于渲染Widget的绘制元素
  • nWidgetStyle为我们提供了应该应用的颜色和不透明度

FSlateDrawElement 是渲染 Slate Widget的主力。它具有绘制框、线、文本、样条线等的方法。我们将在这里使用顶点(在 2D 空间中)和索引来渲染任意网格。

我们需要为顶点填充 FSlateVertex 结构的 TArray,以及定义从顶点构建的三角形的 SlateIndex (uint32) 索引值的 TArray。

为了渲染切片,我们在中心添加一个顶点,然后沿弧添加边缘顶点。然后索引缓冲区使用中心和一对连续的边顶点定义三角形。每个顶点的颜色是通过使用通过小部件样式传入的颜色和不透明度以及小部件的整体颜色和不透明度来调制画笔颜色来计算的。

如果画笔使用图像,我们也可以为顶点设置 UV 坐标——我暂时不考虑它。

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;
}

这允许我们以不同的大小和颜色渲染切片:

在这里插入图片描述

5、更新Widget属性

为了使编辑器正常工作,我们需要在 Slate 小部件中的属性在 UMG 小部件中发生更改时更新它们。我们通过重写SynchronizeProperties函数来做到这一点:

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

Slate 小部件需要以下 setter 函数:

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

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

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

现在,只要在编辑器中更改任何属性,切片就会立即更新。

6、设置Widget类别

除非另行指定,否则Widget在 UMG 设计器的Widget面板中显示为未分类。要设置类别,请添加对GetPaletteCategory函数的覆盖:

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

在这里插入图片描述

7、后续工作

本文涉及的源码可以从 GitHub 库中下载。

在能够与 Unreal 中的常规 UMG Widget相提并论之前,仍有许多工作要做。例如,属性不支持动画,也不支持属性绑定。我也没有讨论鼠标事件——UMG(和 Slate)中的所有Widget都是矩形的,因此在不规则形状的Widget上正确处理鼠标需要一些技巧。

实现自定义Widget的一个潜在原因是优化 - 例如,实现一个组合多个元素呈现的单个Widget可能会更快 - 我将在不久的将来探讨这一点。


原文链接:Slate Widget开发教程 — BimAnt

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:31:23  更:2022-02-14 21:31:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:28:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码