UE4 C++ Slate

一、概述

       UE4的大部分编辑器界面都是Slate构建的,包括一些插件也是由Slate构建。Slate是一个分辨率自适应的相对布局界面系统,为了完成这样的目的,slate实际上采用了一个两次排布的“思路”。

 (一)、首先是递归计算每个控件的大小,父控件会根据子控件来计算自己的大小。

 (二)、根据控件大小,计算出每个控件的绘制位置。

二、Slate渲染

      所有的Slate对象首先会准备渲染的内容,即WindowElement,然后这些内容会交给SlateRHIRenderer负责,最终被绘制出来。

渲染流程为:

(一)、将控件对象转换为需要绘制的图形面片。

(二)、通过PixelShader和VertexShader来使用GPU绘制。

(三)、拿回绘图结果,显示在SWindow中。

值得注意的是:Slate的渲染是没有开启深度检测的。

三、Slate的继承方式

    所有的Slate部件都继承自SWidget,SWidget继承自FSlateControlledConstruction和TSharedFromThis。SWidget分为SCompoundWidget、SEditableText、SLeafWidget、SMultiLineEditableText、SPanel、SRichTextBlock、SWeakWidget。

SCompoundWidget只含有一个FSimpleSlot 类型的ChildSlot,只可以添加一个Child Widget,在Construct()函数里面初始化ChildSlot,简单的布局。例如SBorder、SButton。

SEditableText、SLeafWidget、SMultiLineEditableText、SRichTextBlock不包含ChildSlot,不可以添加Widget。

SPanel可以包含多个ChildWidget,Spanel本身没有Slot结构,继承它的子类自己添加Slot结构,并且实现不同的结构方式。例如SWidgetSwitcher。

不同的继承方式,ChildSlot也不同。

四、Slate属性方法

Slate提供了一系列宏来初始化控件。

SLATE_BEGIN_ARGS()SLATE_END_ARGS()之间声明参数。

常用的宏有SLATE_ATTRIBUTE(属性)SLATE_EVENT(事件)SLATE_ARGUMENT(参数)SLATE_NAMED_SLOT(插槽) 和 SLATE_DEFAULT_SLOT。

SLATE_BEGIN_ARGS(SBackgroundBlurWidget)
		: _HAlign(HAlign_Fill)
		, _VAlign(VAlign_Fill)
		, _Padding(FMargin(2.0f))
		, _bApplyAlphaToBlur(true)
		, _BlurStrength(0.f)
		, _BlurRadius()
		, _LowQualityFallbackBrush(nullptr)
	{
		_Visibility = EVisibility::SelfHitTestInvisible;
	}
	SLATE_DEFAULT_SLOT(FArguments, Content)

		SLATE_ARGUMENT(EHorizontalAlignment, HAlign)
		SLATE_ARGUMENT(EVerticalAlignment, VAlign)
		SLATE_ATTRIBUTE(FMargin, Padding)

		SLATE_ARGUMENT(bool, bApplyAlphaToBlur)
		SLATE_ATTRIBUTE(float, BlurStrength)
		SLATE_ATTRIBUTE(TOptional<int32>, BlurRadius)
		SLATE_ARGUMENT(const FSlateBrush*, LowQualityFallbackBrush)
		SLATE_END_ARGS()

构造函数初始化

void SBackgroundBlurWidget::Construct(const FArguments& InArgs)
{
	bApplyAlphaToBlur = InArgs._bApplyAlphaToBlur;
	LowQualityFallbackBrush = InArgs._LowQualityFallbackBrush;
	BlurStrength = InArgs._BlurStrength;
	BlurRadius = InArgs._BlurRadius;

	ChildSlot
		.HAlign(InArgs._HAlign)
		.VAlign(InArgs._VAlign)
		.Padding(InArgs._Padding)
	[
		InArgs._Content.Widget
	];

 绘制函数:SLeafWidget和SCompoundWidget是在OnPaint中用FSlateDrawElement绘制。

virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
nt32 SBackgroundBlurWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
	int32 PostFXLayerId = LayerId;
	if (bAllowBackgroundBlur && AllottedGeometry.GetLocalSize() > FVector2D::ZeroVector)
	{
		if (!bForceLowQualityBrushFallback)
		{
			// Modulate blur strength by the widget alpha
			const float Strength = BlurStrength.Get() * (bApplyAlphaToBlur ? InWidgetStyle.GetColorAndOpacityTint().A : 1.f);
			if (Strength > 0.f)
			{
				FPaintGeometry PaintGeometry = AllottedGeometry.ToPaintGeometry();

				// extract the layout transform from the draw element
				FSlateLayoutTransform InverseLayoutTransform(Inverse(FSlateLayoutTransform(PaintGeometry.DrawScale, PaintGeometry.DrawPosition)));
				// The clip rect is NOT subject to the rotations specified by MakeRotatedBox.
				FSlateRotatedClipRectType RenderClipRect = FSlateRotatedClipRectType::MakeSnappedRotatedRect(MyClippingRect, InverseLayoutTransform, AllottedGeometry.GetAccumulatedRenderTransform());

				float OffsetX = PaintGeometry.DrawPosition.X - FMath::TruncToFloat(PaintGeometry.DrawPosition.X);
				float OffsetY = PaintGeometry.DrawPosition.Y - FMath::TruncToFloat(PaintGeometry.DrawPosition.Y);

				int32 RenderTargetWidth = FMath::RoundToInt(RenderClipRect.ExtentX.X);
				int32 RenderTargetHeight = FMath::RoundToInt(RenderClipRect.ExtentY.Y);

				int32 KernelSize = 0;
				int32 DownsampleAmount = 0;
				ComputeEffectiveKernelSize(Strength, KernelSize, DownsampleAmount);

				float ComputedStrength = FMath::Max(.5f, Strength);

				if (DownsampleAmount > 0)
				{
					RenderTargetWidth = FMath::DivideAndRoundUp(RenderTargetWidth, DownsampleAmount);
					RenderTargetHeight = FMath::DivideAndRoundUp(RenderTargetHeight, DownsampleAmount);
					ComputedStrength /= DownsampleAmount;
				}

				if (RenderTargetWidth > 0 && RenderTargetHeight > 0)
				{
//					FSlateDrawElement::MakePostProcessPass(OutDrawElements, LayerId, PaintGeometry, MyClippingRect, FVector4(KernelSize, ComputedStrength, RenderTargetWidth, RenderTargetHeight), DownsampleAmount);
				}


				++PostFXLayerId;
			}
		}
		else if (bAllowBackgroundBlur && bForceLowQualityBrushFallback && LowQualityFallbackBrush && LowQualityFallbackBrush->DrawAs != ESlateBrushDrawType::NoDrawType)
		{
			const bool bIsEnabled = ShouldBeEnabled(bParentEnabled);
			const uint32 DrawEffects = bIsEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

			const FLinearColor FinalColorAndOpacity(InWidgetStyle.GetColorAndOpacityTint() * LowQualityFallbackBrush->GetTint(InWidgetStyle));

			FSlateDrawElement::MakeBox(OutDrawElements, PostFXLayerId, AllottedGeometry.ToPaintGeometry(), LowQualityFallbackBrush, MyClippingRect, DrawEffects, FinalColorAndOpacity);
			++PostFXLayerId;
		}
	}

	return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, PostFXLayerId, InWidgetStyle, bParentEnabled);
}

数据更新 

UE4提供了函数SynchronizeProperties(),编译时会调用该函数,使得属性能够同步到UI控件上。

PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)该函数响应编辑器属性改变事件。

Slate代理

DECLARE_DYNAMIC_DELEGATE_RetVal(bool, FGetBool);
	DECLARE_DYNAMIC_DELEGATE_RetVal(float, FGetFloat);
	DECLARE_DYNAMIC_DELEGATE_RetVal(int32, FGetInt32);
	DECLARE_DYNAMIC_DELEGATE_RetVal(FText, FGetText);
	DECLARE_DYNAMIC_DELEGATE_RetVal(FSlateColor, FGetSlateColor);
	DECLARE_DYNAMIC_DELEGATE_RetVal(FLinearColor, FGetLinearColor);
	DECLARE_DYNAMIC_DELEGATE_RetVal(FSlateBrush, FGetSlateBrush);
	DECLARE_DYNAMIC_DELEGATE_RetVal(ESlateVisibility, FGetSlateVisibility);
	DECLARE_DYNAMIC_DELEGATE_RetVal(EMouseCursor::Type, FGetMouseCursor);
	DECLARE_DYNAMIC_DELEGATE_RetVal(ECheckBoxState, FGetCheckBoxState);
	DECLARE_DYNAMIC_DELEGATE_RetVal(UWidget*, FGetWidget);

	// Events
	DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(UWidget*, FGenerateWidgetForString, FString, Item);
	DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(UWidget*, FGenerateWidgetForObject, UObject*, Item);

	// Events
	DECLARE_DYNAMIC_DELEGATE_RetVal(FEventReply, FOnReply);
	DECLARE_DYNAMIC_DELEGATE_RetVal_TwoParams(FEventReply, FOnPointerEvent, FGeometry, MyGeometry, const FPointerEvent&, MouseEvent);

猜你喜欢

转载自blog.csdn.net/qq_43021038/article/details/127257103