2018-10-13 02:40:00 u012614151 阅读数 5
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2488 人正在学习 去看看 杨石兴

@author:白袍小道

随缘查看

   

前言:

绘制相关类

MeshCompoent

模型组件

FVertexBuffer

顶点缓冲区封装

FIndexBuffer

顶点索引缓冲区封装

FRHIResourceCreateInfo

资源创建描述,分装了底层(DX,OPENGL)的资源(如缓冲区)的描述

FMemory

C++内存操作封装

RHIUnlockIndexBuffer

????????

FPrimitiveSceneProxy

   

为渲染线程映射 UPrimitiveComponent 状态。

划分为子类以支持不同类型的基元(骨架、刚体、BSP 等)

实现某些非常重要的函数.

  

FSceneView

单个视图到一个 FScene 的引擎代表。

通过对 FSceneRenderer::Render 的不同调用不同视图来渲染(多编辑器视口)

通过对 FSceneRenderer::Render 的同一调用中的多个视图来渲染(分屏游戏)。

为每个帧构建新视图

  

FSceneViewFamily

一组视图进入一个场景,该场景有不同的视图转换和所有者角色,所以有个管理(维护)

FMeshElementCollector

  

FDynamicMeshBuilder

  

 

绘制规则

  • Constructor : 从给定的顶点工厂(vertex factory)和材质着色器列表(material shader map)找出适当的着色器,并存储他们的引用。

    其中材质着色器可以看GlobalShader的管理部分【值得参考类比和学习】。

  • CreateBoundShaderState : 为绘制规则(Drawing Policy)创建绑定到RHI的着色器状态。
  • Matches/Compare : 提供了排序该drawing policy和渲染列表(draw lists)中其他drawing policy的函数,Matches 必须比较 DrawShared 依赖的所有因素。
  • DrawShared : 设置在从 Matches 返回 True 的绘制规则之间一致的 RHI 状态。例如,大多数绘制规则会为材质和顶点工厂排序,因此着色器参数只依赖可以设置的材质,并且可以绑定特定于该顶点工厂的顶点缓冲区。应尽可能在此处设置状态,而非在 SetMeshRenderState 设置,因为 DrawShared 在静态渲染路径中调用较少。
  • SetMeshRenderState : 设置特定于此网格体的 RHI 状态,或 DrawShared 中未设置的状态。这比 DrawShared 调用的次数多得多,因此此处性能非常重要。
  • DrawMesh : 实际发出 RHI 绘制调用

   

参考源码及其说明

DZCPP_CustomMeshComponent_01.h


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/MeshComponent.h"
#include <VertexFactory.h>
#include "ContentExamples.h"
#include "DynamicMeshBuilder.h"
#include "DZCPP_CustomMeshComponent_01.generated.h"

/**
*
*/
UCLASS(ClassGroup=Experimental,meta = (BlueprintSpawnableComponent))
class CONTENTEXAMPLES_API UDZCPP_CustomMeshComponent_01 : public UMeshComponent
{
GENERATED_BODY()
public:
virtual FPrimitiveSceneProxy * CreateSceneProxy() override;
TArray<int32> Indices;
TArray<FVector> Vertices;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Materials)
UMaterial * TheMaterial;

UDZCPP_CustomMeshComponent_01();
};

 

   

DZCPP_CustomMeshComponent_01.cpp


// Fill out your copyright notice in the Description page of Project Settings.
#include "DZCPP_CustomMeshComponent_01.h"
class FMyVertexBuffer : public FVertexBuffer
{
public:
TArray<FVector> Vertices;
virtual void InitRHI() override
{
FRHIResourceCreateInfo CreateInfo;
VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num()
* sizeof(FVector), BUF_Static, CreateInfo);
void* VertexBufferData =
RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num()
* sizeof(FVector), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, Vertices.GetData(),
Vertices.Num() * sizeof(FVector));
RHIUnlockVertexBuffer(VertexBufferRHI);
}
};
class FMyIndexBuffer : public FIndexBuffer
{
public:
TArray<int32> Indices;
virtual void InitRHI() override
{
FRHIResourceCreateInfo CreateInfo;
IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32),
Indices.Num() * sizeof(int32), BUF_Static, CreateInfo);
void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0,
Indices.Num() * sizeof(int32), RLM_WriteOnly);
FMemory::Memcpy(Buffer, Indices.GetData(),
Indices.Num() * sizeof(int32));
RHIUnlockIndexBuffer(IndexBufferRHI);
}
};

class FMySceneProxy : public FPrimitiveSceneProxy
{
private:
TArray<FDynamicMeshVertex> Vertices;
TArray<int32> Indices;
FMyVertexBuffer VertexBuffer;
FMyIndexBuffer IndexBuffer;
public:
UPROPERTY()
UMaterial* TheMaterial;
FMySceneProxy(UDZCPP_CustomMeshComponent_01* Component) :FPrimitiveSceneProxy(Component), Indices(Component->Indices), TheMaterial(Component->TheMaterial)
{
// VertexBuffer = FMyVertexBuffer();
// IndexBuffer = FMyIndexBuffer();
// for (FVector Vertex : Component->Vertices)
// {
// Vertices.Add(FDynamicMeshVertex(Component
// ->GetComponentLocation() + Vertex));
// }
}
//FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View)
//{
// FPrimitiveViewRelevance Result;
// Result.bDynamicRelevance = true;
// Result.bDrawRelevance = true;
// Result.bNormalTranslucencyRelevance = true;
// return Result;
//}

//void GetDynamicMeshElements(const TArray<const
// FSceneView*>& Views, const FSceneViewFamily& ViewFamily,
// uint32 VisibilityMap, FMeshElementCollector& Collector)
//{
// for (int32 ViewIndex = 0; ViewIndex < Views.Num();
// ViewIndex++)
// {
// FDynamicMeshBuilder MeshBuilder;
// if (Vertices.Num() == 0)
// {
// return;
// }
// MeshBuilder.AddVertices(Vertices);
// MeshBuilder.AddTriangles(Indices);
// }
//}

//void FMySceneProxy::OnActorPositionChanged()
//{
// VertexBuffer.ReleaseResource();
// IndexBuffer.ReleaseResource();
//}

//uint32 FMySceneProxy::GetMemoryFootprint(void)
//{
// return sizeof(*this);
//}
virtual ~FMySceneProxy() {};
};

 


FPrimitiveSceneProxy* UDZCPP_CustomMeshComponent_01::CreateSceneProxy()
{
FPrimitiveSceneProxy* proxy = nullptr;
//fmysceneproxy * childproxy = new fmysceneproxy(this);
//proxy = childproxy;
return proxy;
}

UDZCPP_CustomMeshComponent_01::UDZCPP_CustomMeshComponent_01()
{
/*static ConstructorHelpers::FObjectFinder<UMaterial>Material(TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial'"));
if (Material.Object != NULL)
{
TheMaterial = (UMaterial*)Material.Object;
}
Vertices.Add(FVector(10, 0, 0));
Vertices.Add(FVector(0, 10, 0));
Vertices.Add(FVector(0, 0, 10));
Indices.Add(0);
Indices.Add(1);
Indices.Add(2);*/
}

 

2019-01-29 15:18:51 ywjun0919 阅读数 239
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2488 人正在学习 去看看 杨石兴

上篇中介绍了Unreal使用插件的方式创建编辑器

这里使用构建Module的方式传建编辑器。文件都是一样的,区别在于,手动的添加文件

这里需要注意的是,在工程的Target.cs中,需要添加自定义模块的名称

2019-01-29 15:04:31 ywjun0919 阅读数 546
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2488 人正在学习 去看看 杨石兴

Unreal自定义编辑器有两种方式 :

   1. 插件方式

   2. 自定义编辑器模块

Unreal中的编辑器都是使用Slate进行布局和创建

插件方式

1. 创建项目:选择基础代码

2. 选择 编辑->插件

 

3. 点击 新插件 按钮

4. 选择编辑器Standalone窗口

5. 创建完成,并不会立即显示编辑器菜单,下图并没有添加新的东西

6.  重启编辑器

7. 打开插件窗口看看

8. 分析

前面说过,ShutdownModule并不是关闭窗口的时候调用,因此,要想关闭窗口的时候调用需要注册关闭事件

void FTestEditorModule::PluginButtonClicked()
{
	FGlobalTabmanager::Get()->InvokeTab(TestEditorTabName)->
		SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateLambda([this](TSharedRef<SDockTab> Self) {
		this->OnWindowClose(Self);
	}));
}

void FTestEditorModule::OnWindowClose(TSharedRef<SDockTab> DockTab)
{
    UE_LOG(LogTemp, Display, TEXT("FTestEditorModule Close"))
}

 

2016-12-03 14:33:30 qq_20309931 阅读数 4503
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2488 人正在学习 去看看 杨石兴

Unreal Engine 4 C++ UMG自定义控件

好记性不如烂笔头啊,还是记录一下!


如果你觉得Unreal Engine里面的控件没有达到你的需求,你需要添加自定控件。


创建Slate控件

如果你还不了解如何创建一个Slate控件,请先阅读:

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(一)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(二)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(三)

这里用我自己写的作为参考:

  • SProgressBarEx.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "UI/Slate/ProgressBarExStyle.h"

/**
 *  SProgressBarEx Fill Type 
 */
UENUM(BlueprintType)
namespace EProgressBarExFillType
{
    enum Type
    {
        // will fill up from the left side to the right
        LeftToRight,
        // will fill up from the right side to the left side
        RightToLeft,
        // will fill up from the center to the outer edges
        FillFromCenter,
        // will fill up from the top to the the bottom
        TopToBottom,
        // will fill up from the bottom to the the top
        BottomToTop,
    };
}

/** A progress extend bar widget.*/
class TESTMOBILE_API SProgressBarEx : public SLeafWidget
{

public:
    SLATE_BEGIN_ARGS(SProgressBarEx)
        : _Style( nullptr )
        , _BarFillType(EProgressBarExFillType::LeftToRight)
        , _Percent( TOptional<float>() )
        , _FillColorAndOpacity( FLinearColor::White )
        , _BorderPadding( FVector2D(1,0) )
        , _BackgroundImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").BackgroundImage)
        , _IncreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _DecreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _FillImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _MarqueeImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").MarqueeImage)
        , _RefreshRate(2.0f)
        {}

        /** Style used for the progress bar */
        SLATE_STYLE_ARGUMENT( FProgressBarExStyle, Style )

        /** Defines if this progress bar fills Left to right or right to left*/
        SLATE_ARGUMENT( EProgressBarExFillType::Type, BarFillType )

        /** Used to determine the fill position of the progress bar ranging 0..1 */
        SLATE_ATTRIBUTE( TOptional<float>, Percent )

        /** Fill Color and Opacity */
        SLATE_ATTRIBUTE( FSlateColor, FillColorAndOpacity )

        /** Border Padding around fill bar */
        SLATE_ATTRIBUTE( FVector2D, BorderPadding )
    
        /** The brush to use as the background of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, BackgroundImage)

        /** The brush to use as the increase image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, IncreaseImage)

        /** The brush to use as the decrease image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, DecreaseImage)
    
        /** The brush to use as the fill image */
        SLATE_ARGUMENT(const FSlateBrush*, FillImage)
    
        /** The brush to use as the marquee image */
        SLATE_ARGUMENT(const FSlateBrush*, MarqueeImage)

        /** Rate at which this widget is ticked when sleeping in seconds */
        SLATE_ARGUMENT(float, RefreshRate)

    SLATE_END_ARGS()

    /**
     * Construct the widget
     * 
     * @param InArgs   A declaration from which to construct the widget
     */
    void Construct(const FArguments& InArgs);

    /** Paint Widget */
    virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
    virtual FVector2D ComputeDesiredSize(float) const override;
    virtual bool ComputeVolatility() const override;

    /** See attribute Percent */
    void SetPercent(TAttribute< TOptional<float> > InPercent);

    /** See attribute Style */
    void SetStyle(const FProgressBarExStyle* InStyle);

    /** See attribute BarFillType */
    void SetBarFillType(EProgressBarExFillType::Type InBarFillType);
    
    /** See attribute SetFillColorAndOpacity */
    void SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity);
    
    /** See attribute BorderPadding */
    void SetBorderPadding(TAttribute< FVector2D > InBorderPadding);
    
    /** See attribute BackgroundImage */
    void SetBackgroundImage(const FSlateBrush* InBackgroundImage);

    /** See attribute IncreaseImage */
    void SetIncreaseImage(const FSlateBrush* InIncreaseImage);

    /** See attribute IncreaseImage */
    void SetDecreaseImage(const FSlateBrush* InDecreaseImage);
    
    /** See attribute FillImage */
    void SetFillImage(const FSlateBrush* InFillImage);
    
    /** See attribute MarqueeImage */
    void SetMarqueeImage(const FSlateBrush* InMarqueeImage);

private:

    /** Controls the speed at which the widget is ticked when in slate sleep mode */
    void SetActiveTimerTickRate(float TickRate);

    /** Widgets active tick */
    EActiveTimerReturnType ActiveTick(double InCurrentTime, float InDeltaTime);

    /** Gets the current background image. */
    const FSlateBrush* GetBackgroundImage() const;

    /** Gets the current increase image */
    const FSlateBrush* GetIncreaseImage() const;

    /** Gets the current decrease image */
    const FSlateBrush* GetDecreaseImage() const;

    /** Gets the current fill image */
    const FSlateBrush* GetFillImage() const;

    /** Gets the current marquee image */
    const FSlateBrush* GetMarqueeImage() const;


private:

    /** The style of the progress bar */
    const FProgressBarExStyle* Style;

    /** The text displayed over the progress bar */
    TAttribute< TOptional<float> > CurrentPercent;
    TAttribute< TOptional<float> > TargetPercent;
    TAttribute< TOptional<float> > MiddlePercent;

    /** The fill type for the progress bar */
    EProgressBarExFillType::Type BarFillType;

    /** Background image to use for the progress bar */
    const FSlateBrush* BackgroundImage;

    /** Increase image to use for the progress bar */
    const FSlateBrush* IncreaseImage;

    /** Decrease image to use for the progress bar */
    const FSlateBrush* DecreaseImage;

    /** Foreground image to use for the progress bar */
    const FSlateBrush* FillImage;

    /** Image to use for marquee mode */
    const FSlateBrush* MarqueeImage;

    /** Value to drive progress bar animation */
    float SpeedRate;

    /** Fill Color and Opacity */
    TAttribute<FSlateColor> FillColorAndOpacity;

    /** Border Padding */
    TAttribute<FVector2D> BorderPadding;

    /** Value to drive progress bar animation */
    float MarqueeOffset;

    /** Reference to the widgets current active timer */
    TWeakPtr<FActiveTimerHandle> ActiveTimerHandle;

    /** Rate at which the widget is currently ticked when slate sleep mode is active */
    float CurrentTickRate;

    /** The slowest that this widget can tick when in slate sleep mode */
    float MinimumTickRate;
};

  • SProgressBarEx.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "SProgressBarEx.h"

void SProgressBarEx::Construct(const FArguments& InArgs)
{
    check(InArgs._BackgroundImage);
    check(InArgs._IncreaseImage);
    check(InArgs._DecreaseImage);
    check(InArgs._FillImage);
    check(InArgs._MarqueeImage);


    MarqueeOffset = 0.0f;
    Style = InArgs._Style;

    
    TAttribute< TOptional<float> > Percent = InArgs._Percent.Get().IsSet() ? InArgs._Percent : 0.5f;
    SetPercent(Percent);

    SpeedRate = 30.0f;

    BarFillType = InArgs._BarFillType;
    BackgroundImage = InArgs._BackgroundImage;
    IncreaseImage = InArgs._IncreaseImage;
    DecreaseImage = InArgs._DecreaseImage;
    FillImage = InArgs._FillImage;
    MarqueeImage = InArgs._MarqueeImage;

    FillColorAndOpacity = InArgs._FillColorAndOpacity;
    BorderPadding = InArgs._BorderPadding;

    CurrentTickRate = 0.0f;
    MinimumTickRate = InArgs._RefreshRate;

    ActiveTimerHandle = RegisterActiveTimer(CurrentTickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
}


void SProgressBarEx::SetPercent(TAttribute< TOptional<float> > InPercent)
{
    if (!TargetPercent.IdenticalTo(InPercent))
    {
        CurrentPercent = MiddlePercent = TargetPercent = InPercent;
        Invalidate(EInvalidateWidget::LayoutAndVolatility);
    }
}


void SProgressBarEx::SetStyle(const FProgressBarExStyle* InStyle)
{
    Style = InStyle;

    if (Style == nullptr)
    {
        FArguments Defaults;
        Style = Defaults._Style;
    }

    check(Style);

    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBarFillType(EProgressBarExFillType::Type InBarFillType)
{
    BarFillType = InBarFillType;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity)
{
    FillColorAndOpacity = InFillColorAndOpacity;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBorderPadding(TAttribute< FVector2D > InBorderPadding)
{
    BorderPadding = InBorderPadding;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBackgroundImage(const FSlateBrush* InBackgroundImage)
{
    BackgroundImage = InBackgroundImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetIncreaseImage(const FSlateBrush* InIncreaseImage)
{
    IncreaseImage = InIncreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetDecreaseImage(const FSlateBrush* InDecreaseImage)
{
    DecreaseImage = InDecreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillImage(const FSlateBrush* InFillImage)
{
    FillImage = InFillImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetMarqueeImage(const FSlateBrush* InMarqueeImage)
{
    MarqueeImage = InMarqueeImage;
    Invalidate(EInvalidateWidget::Layout);
}


const FSlateBrush* SProgressBarEx::GetBackgroundImage() const
{
    return &Style->BackgroundImage ? &Style->BackgroundImage : BackgroundImage;
}


const FSlateBrush* SProgressBarEx::GetIncreaseImage() const
{
    return &Style->IncreaseImage ? &Style->IncreaseImage : IncreaseImage;
}


const FSlateBrush* SProgressBarEx::GetDecreaseImage() const
{
    return &Style->DecreaseImage ? &Style->DecreaseImage : DecreaseImage;
}


const FSlateBrush* SProgressBarEx::GetFillImage() const
{
    return &Style->FillImage ? &Style->FillImage : FillImage;
}


const FSlateBrush* SProgressBarEx::GetMarqueeImage() const
{
    return &Style->MarqueeImage ? &Style->MarqueeImage : MarqueeImage;
}


int32 SProgressBarEx::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
    // Used to track the layer ID we will return.
    int32 RetLayerId = LayerId;

    bool bEnabled = ShouldBeEnabled( bParentEnabled );
    const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

    const FSlateBrush* CurrentFillImage = GetFillImage();
    const FLinearColor FillColorAndOpacitySRGB(InWidgetStyle.GetColorAndOpacityTint() * FillColorAndOpacity.Get().GetColor(InWidgetStyle) * CurrentFillImage->GetTint(InWidgetStyle));
    const FLinearColor ColorAndOpacitySRGB = InWidgetStyle.GetColorAndOpacityTint();

    // Paint inside the border only. 
    // Pre-snap the clipping rect to try and reduce common jitter, since the padding is typically only a single pixel.
    FSlateRect SnappedClippingRect = FSlateRect(FMath::RoundToInt(MyClippingRect.Left), FMath::RoundToInt(MyClippingRect.Top), FMath::RoundToInt(MyClippingRect.Right), FMath::RoundToInt(MyClippingRect.Bottom));
    const FSlateRect ForegroundClippingRect = SnappedClippingRect.InsetBy(FMargin(BorderPadding.Get().X, BorderPadding.Get().Y));

    // Paint background image
    const FSlateBrush* CurrentBackgroundImage = GetBackgroundImage();
    FSlateDrawElement::MakeBox(
        OutDrawElements,
        RetLayerId++,
        AllottedGeometry.ToPaintGeometry(),
        CurrentBackgroundImage,
        SnappedClippingRect,
        DrawEffects,
        InWidgetStyle.GetColorAndOpacityTint() * CurrentBackgroundImage->GetTint( InWidgetStyle )
    );

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    TOptional<float> MiddlePercentFraction = MiddlePercent.Get();
    TOptional<float> CurrentPercentFraction = CurrentPercent.Get();

    if ( TargetPercentFraction.IsSet() && MiddlePercentFraction.IsSet() && CurrentPercentFraction.IsSet() )
    {
        // Get percent value
        float TargetPercentValue = FMath::Clamp(TargetPercentFraction.GetValue(), 0.0f, 1.0f);
        float MiddlePercentValue = FMath::Clamp(MiddlePercentFraction.GetValue(), 0.0f, 1.0f);
        float CurrentPercentValue = FMath::Clamp(CurrentPercentFraction.GetValue(), 0.0f, 1.0f);

        // Get paint order
        const FSlateBrush* TopBrush;
        const FSlateBrush* CenterBrush;
        const FSlateBrush* BottomBrush;
        float TopValue;
        float CenterValue;
        float BottomValue;
       

        TopBrush = GetFillImage();
        TopValue = MiddlePercentValue;
        CenterBrush = GetIncreaseImage();
        CenterValue = TargetPercentValue;
        BottomBrush = GetDecreaseImage();
        BottomValue = CurrentPercentValue;


        

        switch (BarFillType)
        {
        case EProgressBarExFillType::RightToLeft:
            break;
        case EProgressBarExFillType::FillFromCenter:
            break;
        case EProgressBarExFillType::TopToBottom:
            break;
        case EProgressBarExFillType::BottomToTop:
            break;
        case EProgressBarExFillType::LeftToRight:
        default:
            // Draw bottom layer
            FSlateRect ClippedAllotedGeometry = FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * BottomValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                BottomBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw center layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * CenterValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                CenterBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw top layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * TopValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                TopBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );
            break;
        }
    }
    else
    {

    }

    return RetLayerId - 1;
}


FVector2D SProgressBarEx::ComputeDesiredSize(float) const
{
    return GetMarqueeImage()->ImageSize;
}


bool SProgressBarEx::ComputeVolatility() const
{
    return SLeafWidget::ComputeVolatility() || TargetPercent.IsBound();
}


void SProgressBarEx::SetActiveTimerTickRate(float TickRate)
{
    if (CurrentTickRate != TickRate || !ActiveTimerHandle.IsValid())
    {
        CurrentTickRate = TickRate;

        TSharedPtr<FActiveTimerHandle> SharedActiveTimerHandle = ActiveTimerHandle.Pin();
        if (SharedActiveTimerHandle.IsValid())
        {
            UnRegisterActiveTimer(SharedActiveTimerHandle.ToSharedRef());
        }

        ActiveTimerHandle = RegisterActiveTimer(TickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
    }
}


EActiveTimerReturnType SProgressBarEx::ActiveTick(double InCurrentTime, float InDeltaTime)
{
    MarqueeOffset = InCurrentTime - FMath::FloorToDouble(InCurrentTime);

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    if (TargetPercentFraction.IsSet())
    {
        SetActiveTimerTickRate(MinimumTickRate);
    }
    else
    {
        SetActiveTimerTickRate(0.0f);
    }

    return EActiveTimerReturnType::Continue;
}

这个是一个多层进度条的Slate控件,紧接着要为他写个Slate样式。

  • ProgressBarExStyle.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "SlateWidgetStyleContainerBase.h"
#include "SlateWidgetStyle.h"
#include "SlateBasics.h"
#include "ProgressBarExStyle.generated.h"


/**
 * Represents the appearance of an SProgressBarEx
 */
USTRUCT(BlueprintType)
struct TESTMOBILE_API FProgressBarExStyle : public FSlateWidgetStyle
{
    GENERATED_USTRUCT_BODY()

    FProgressBarExStyle();

    virtual ~FProgressBarExStyle() {}

    virtual void GetResources( TArray< const FSlateBrush* >& OutBrushes ) const override;

    static const FName TypeName;
    virtual const FName GetTypeName() const override { return TypeName; };

    static const FProgressBarExStyle& GetDefault();

    /** Background image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush BackgroundImage;
    FProgressBarExStyle& SetBackgroundImage( const FSlateBrush& InBackgroundImage ){ BackgroundImage = InBackgroundImage; return *this; }

    /** Increase image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush IncreaseImage;
    FProgressBarExStyle& SetIncreaseImage( const FSlateBrush& InIncreaseImage ){ IncreaseImage = InIncreaseImage; return *this; }

    /** Decrease image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush DecreaseImage;
    FProgressBarExStyle& SetDecreaseImage( const FSlateBrush& InDecreaseImage ){ DecreaseImage = InDecreaseImage; return *this; }

    /** Foreground image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush FillImage;
    FProgressBarExStyle& SetFillImage( const FSlateBrush& InFillImage ){ FillImage = InFillImage; return *this; }

    /** Image to use for marquee mode */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush MarqueeImage;
    FProgressBarExStyle& SetMarqueeImage( const FSlateBrush& InMarqueeImage ){ MarqueeImage = InMarqueeImage; return *this; }
};
  • ProgressBarExStyle.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "ProgressBarExStyle.h"

FProgressBarExStyle::FProgressBarExStyle()
{
}

void FProgressBarExStyle::GetResources( TArray< const FSlateBrush* >& OutBrushes ) const
{
    OutBrushes.Add( &BackgroundImage );
    OutBrushes.Add( &IncreaseImage );
    OutBrushes.Add( &DecreaseImage );
    OutBrushes.Add( &FillImage );
    OutBrushes.Add( &MarqueeImage );
}

const FName FProgressBarExStyle::TypeName( TEXT("FProgressBarExStyle") );

const FProgressBarExStyle& FProgressBarExStyle::GetDefault()
{
    static FProgressBarExStyle Default;
    return Default;
}

到此我们就结束了Slate控件的编写,只是写了个基本的多层进度条。


添加到UMG编辑器中

首先需要给样式加上一个基础容器,并且要反射给UMG的编辑器

  • ProgressExWidgetStyle.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Styling/SlateWidgetStyleContainerBase.h"
#include "UI/Slate/ProgressBarExStyle.h"
#include "ProgressExWidgetStyle.generated.h"

/**
 * 
 */
UCLASS(BlueprintType, hidecategories=Object, MinimalAPI)
class UProgressExWidgetStyle : public USlateWidgetStyleContainerBase
{
    GENERATED_BODY()

public:

    /** The actual data describing the button's appearance. */
    UPROPERTY(Category="Style", EditAnywhere, BlueprintReadWrite, meta=(ShowOnlyInnerProperties))
    FProgressBarExStyle ProgressBarExStyle;
    
    virtual const struct FSlateWidgetStyle* const GetStyle() const override
    {
        return static_cast< const struct FSlateWidgetStyle* >( &ProgressBarExStyle );
    }
};

然后要让编辑器能看到我们的Slate控件:

  • ProgressBarEx.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Widget.h"
#include "ProgressExWidgetStyle.h"
#include "UI/Slate/SProgressBarEx.h"
#include "ProgressBarEx.generated.h"

class USlateBrushAsset;

/**
 *  ProgressBarEx
 */
UCLASS()
class TESTMOBILE_API UProgressBarEx : public UWidget
{
    GENERATED_BODY()

public:

    /** The progress bar ex default setting */
    UProgressBarEx(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
    
    /** The progress bar ex style */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Style", meta=( DisplayName="Style" ))
    FProgressBarExStyle WidgetStyle;

    /** Style used for the progress bar */
    UPROPERTY()
    USlateWidgetStyleAsset* Style_DEPRECATED;

    /** The brush to use as the background of the progress bar */
    UPROPERTY()
    USlateBrushAsset* BackgroundImage_DEPRECATED;

    /** The brush to use as the increase image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* IncreaseImage_DEPRECATED;

    /** The brush to use as the decrease image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* DecreaseImage_DEPRECATED;

    /** The brush to use as the fill image */
    UPROPERTY()
    USlateBrushAsset* FillImage_DEPRECATED;

    /** The brush to use as the marquee image */
    UPROPERTY()
    USlateBrushAsset* MarqueeImage_DEPRECATED;

    /** Used to determine the fill position of the progress bar ranging 0..1 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress, meta=( UIMin = "0", UIMax = "1" ))
    float Percent;

    /** Defines if this progress bar fills Left to right or right to left */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    TEnumAsByte<EProgressBarExFillType::Type> BarFillType;
    
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    bool bIsMarquee;

    /** A bindable delegate to allow logic to drive the text of the widget */
    UPROPERTY()
    FGetFloat PercentDelegate;

    /** Fill Color and Opacity */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Appearance)
    FLinearColor FillColorAndOpacity;

    /** */
    UPROPERTY()
    FGetLinearColor FillColorAndOpacityDelegate;
    
public:
    
    /** Sets the current value of the ProgressBar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetPercent(float InPercent);

    /** Sets the fill color of the progress bar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetFillColorAndOpacity(FLinearColor InColor);

    /** Sets the progress bar to show as a marquee. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetIsMarquee(bool InbIsMarquee);

    //TODO UMG Add Set BarFillType.

public:

    //~ Begin UWidget Interface
    virtual void SynchronizeProperties() override;
    //~ End UWidget Interface

    //~ Begin UVisual Interface
    virtual void ReleaseSlateResources(bool bReleaseChildren) override;
    //~ End UVisual Interface

    //~ Begin UObject Interface
    virtual void PostLoad() override;
    //~ End UObject Interface

#if WITH_EDITOR

    //~ Begin UWidget Interface
    virtual const FText GetPaletteCategory() override;
    virtual void OnCreationFromPalette() override;
    //~ End UWidget Interface

#endif

protected:

    /** Native Slate Widget */
    TSharedPtr<SProgressBarEx> MyProgressBar;

    //~ Begin UWidget Interface
    virtual TSharedRef<SWidget> RebuildWidget() override;
    //~ End UWidget Interface
};

  • ProgressBarEx.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "UMG.h"
#include "UMGStyle.h"
#include "Slate/SlateBrushAsset.h"
#include "ProgressBarEx.h"

#define LOCTEXT_NAMESPACE "UMG"

/////////////////////////////////////////////////////
// UProgressBarEx

UProgressBarEx::UProgressBarEx(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
    // SProgressBarEx::FArguments SlateDefaults;
    // WidgetStyle = *SlateDefaults._Style;
    // WidgetStyle = FMenuStyles::Get().GetWidgetStyle<FProgressBarExStyle>("HPBarStyle");
    // WidgetStyle.FillImage.TintColor = FLinearColor::White;
    
    BarFillType = EProgressBarExFillType::LeftToRight;
    bIsMarquee = false;
    Percent = 0;
    FillColorAndOpacity = FLinearColor::White;
}


void UProgressBarEx::SetIsMarquee(bool InbIsMarquee)
{
    bIsMarquee = InbIsMarquee;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : Percent);
    }
}

void UProgressBarEx::SetFillColorAndOpacity(FLinearColor Color)
{
    FillColorAndOpacity = Color;
    if (MyProgressBar.IsValid())
    {
        MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacity);
    }
}

void UProgressBarEx::SetPercent(float InPercent)
{
    Percent = InPercent;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(InPercent);
    }
}


void UProgressBarEx::SynchronizeProperties()
{
    Super::SynchronizeProperties();

    TAttribute< TOptional<float> > PercentBinding = OPTIONAL_BINDING_CONVERT(float, Percent, TOptional<float>, ConvertFloatToOptionalFloat);
    TAttribute<FSlateColor> FillColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, FillColorAndOpacity);


    // MyProgressBar->SetStyle(&WidgetStyle);

    SProgressBarEx::FArguments SlateDefaults;
    MyProgressBar->SetBackgroundImage(SlateDefaults._BackgroundImage);
    MyProgressBar->SetIncreaseImage(SlateDefaults._IncreaseImage);
    MyProgressBar->SetDecreaseImage(SlateDefaults._DecreaseImage);
    MyProgressBar->SetFillImage(SlateDefaults._FillImage);
    MyProgressBar->SetMarqueeImage(SlateDefaults._MarqueeImage);

    MyProgressBar->SetStyle(&WidgetStyle);

    MyProgressBar->SetBarFillType(BarFillType);
    MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : PercentBinding);
    MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacityBinding);
}

void UProgressBarEx::PostLoad()
{
    Super::PostLoad();

    if ( GetLinkerUE4Version() < VER_UE4_DEPRECATE_UMG_STYLE_ASSETS )
    {
        if ( Style_DEPRECATED != nullptr )
        {
            const FProgressBarExStyle* StylePtr = Style_DEPRECATED->GetStyle<FProgressBarExStyle>();
            if ( StylePtr != nullptr )
            {
                WidgetStyle = *StylePtr;
            }

            Style_DEPRECATED = nullptr;
        }

        if ( BackgroundImage_DEPRECATED != nullptr )
        {
            WidgetStyle.BackgroundImage = BackgroundImage_DEPRECATED->Brush;
            BackgroundImage_DEPRECATED = nullptr;
        }

        if ( IncreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.IncreaseImage = IncreaseImage_DEPRECATED->Brush;
            IncreaseImage_DEPRECATED = nullptr;
        }

        if ( DecreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.DecreaseImage = DecreaseImage_DEPRECATED->Brush;
            DecreaseImage_DEPRECATED = nullptr;
        }

        if ( FillImage_DEPRECATED != nullptr )
        {
            WidgetStyle.FillImage = FillImage_DEPRECATED->Brush;
            FillImage_DEPRECATED = nullptr;
        }

        if ( MarqueeImage_DEPRECATED != nullptr )
        {
            WidgetStyle.MarqueeImage = MarqueeImage_DEPRECATED->Brush;
            MarqueeImage_DEPRECATED = nullptr;
        }
    }
}


void UProgressBarEx::ReleaseSlateResources(bool bReleaseChildren)
{
    Super::ReleaseSlateResources(bReleaseChildren);

    MyProgressBar.Reset();
}


TSharedRef<SWidget> UProgressBarEx::RebuildWidget()
{
    MyProgressBar = SNew(SProgressBarEx)
        .BorderPadding(FVector2D(0.0f, 0.0f));

    return MyProgressBar.ToSharedRef();
}


#if WITH_EDITOR

const FText UProgressBarEx::GetPaletteCategory()
{
    return LOCTEXT("Common", "Common");
}

void UProgressBarEx::OnCreationFromPalette()
{
    FillColorAndOpacity = FLinearColor(0, 0.5f, 1.0f);
}

#endif


/////////////////////////////////////////////////////

#undef LOCTEXT_NAMESPACE

其中RebuildWidgetSynchronizeProperties函数很重要。

编译代码后,打开UMG的编辑器,你会发现Common组件下多了一个Progress Bar Ex的控件:

自定义Slate控件

2019-05-28 09:47:58 qq_38949347 阅读数 547
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2488 人正在学习 去看看 杨石兴

Unreal 4.22 动态创建一个自定义长方体教程

本教程主要是用Custom Mesh组件来完成动态生成长方体。

思路是任意点击两点会连成一个有宽度的线——就是长方形,输入高度后能够动态形成长方体。

先来看一下效果图:

效果图1

效果图2

效果图3

接下来是代码思路:

主要是用CustomMesh这个组件。

组件

这个组件能根据添加进的三个点画出一个三角形

参照图

AddCM

这里新建一个TopDown的初始项目(因为可以用鼠标点击,可以少写点东西)

新建


创建好了之后呢,把地图的所有柱子都删了,再将人物的模型隐藏了,构建一下光照,将阴影去掉。(这里就不截图了,不是什么关键)


首先解决点击获取Location:

在TopDownController蓝图里面编辑如图

控制器

点击

这里主要是要点击两次才调用方法,点击一次储存一次值,有两个值才能连成一个长方形,True后面是调用自己创建的蓝图的画长方形的事件。


创建蓝图,添加CustomMesh组件。

添加自定义事件:

添加点

这里主要是添加一个Data做备份,为了不浪费资源和重复绘图,每次画完都会将Location Array清空,Data数组是备份数组,XY的宏将在下图展示。

XY宏

主要是两个角度公式,参考里也会有详解。

如果不会用Add Custom Mesh Triangles的可以多试试这个蓝图,试试就懂了。


在人物蓝图内编辑UI添加事件。
制作一个UI后添加,UI只有一个输入框和点击按钮,这里就不赘述了,输入的值要传递至拥有CustomMesh这个组件的蓝图内方便创建高度。

添加UI


在拥有CustomMesh蓝图内添加事件,输入高度确定后调用:

高

这里图比较大,也是关键地方,具体就是从Data数组里面一次取两组数据,然后将底部的点添加高度,就拥有了长方体所有的点,一个面由两个三角形组成,拥有点就只要慢慢添加就好。

(如果一个方向画有三角形,返向没有的话,在材质里面选择双面材质就可以解决问题)

如果遗漏,欢迎补充。

2019/5/28 9:30:32

参考:

计算垂直线上的一点

没有更多推荐了,返回首页