UE4C++饼状图绘制(EChart)
- 前言
在UE4中实现饼状图,折线图等一系列图可能得采用材质,或者凑一个UMG的方式实现我们想要的图,在这我给大家分享如何去实现一个饼状图。
实现目标:在UMG中添加饼状图
知识要求:基本UEC++,了解图形学的原理。
(学过图形学原理的这段可以跳过)
模型绘制过程中,采用的是传统的点线面的绘制,即从绘制一个像素点,到绘制一条线,到绘制一条面的过程,一般的引擎渲染都是以三角形作为最基础的面的绘制,也有的会采用四边形来作为最基础的图形绘制,这里我们采用的是三角形来讲解原理。而在代码中的体现则是:用一个数组存储顶点信息(位置、UV值、颜色等),再用一个数组存储下标信息,即从下标数组中去三个下标绘制成三角形,循环遍历整个数组即可绘制多个三角形,最好获得由三角形组成的图像或者模型。
首先:扇形是属于圆的一部分,我们如果能绘制圆,择也能绘制扇形,圆我们可以想作由无数个以圆心为中心点,四周无数个三角形构成的图案,而扇形则是有起始角度范围的圆,见下图:
我们将圆分成360份来绘制,代码如下(在此就不具体讲解怎么做的了,代码中都有注释):
编译时候将代码放在自己需要的文件路径,再将SPECIALCHART_API 改成 大写文件夹名字_API,再添加模块即可编译成功:
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"UMG"
// ... add private dependencies that you statically link with here ...
}
);
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "PieWidget.generated.h"
/**
* 饼状图
*/
UCLASS()
class SPECIALCHART_API UPieWidget : public UUserWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
//蓝图中设置基础角度值
void SetValues(TArray<int32>InAngles);
UFUNCTION(BlueprintCallable)
//蓝图中设置基础角度的颜色值
void SetColors(TArray<FLinearColor>InColors);
protected:
UPieWidget(const FObjectInitializer& ObjectInitializer);
//绘制
virtual int32 NativePaint(const FPaintArgs& Args,
const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect, //绘制的矩形
FSlateWindowElementList& OutDrawElements,//返回的信息
int32 LayerId,
const FWidgetStyle& InWidgetStyle, //UMG样式
bool bParentEnabled) const;
private:
void DrawFan(FSlateWindowElementList&OutDrawElements,//Slate窗口元素列表
const FGeometry&AllottedGemoetry,//几何信息
int32 Layer,//层级
const FVector2D& CenterPosition,//圆心坐标位置
float Radius,int32 BeginAngle,//开始角度
int32 EndAngle,//结束角度
FColor Color)const;//绘制扇形的颜色
FColor GetColorByIndex(int32 InIndex)const;//通过数组下标获取颜色值
TArray<int32>Angles;//传入的不同扇形角度
TArray<FLinearColor>Colors;//传入的不同扇形的颜色值
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "PieWidget.h"
UPieWidget::UPieWidget(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
//角度数据计算
void UPieWidget::SetValues(TArray<int32> InAngles)
{
if(InAngles.Num()<1)
return;
Angles.Empty();
Angles.Add(0);
float Total = 0;
for (int32 Index=0;Index<InAngles.Num();Index++)
{
Total += InAngles[Index];
}
float CurrentTotal = 0;
for (int32 Index = 0; Index < InAngles.Num(); Index++)
{
CurrentTotal += InAngles[Index];
int32 Angle = (CurrentTotal / Total) * 360;
Angles.Add(Angle);
}
}
void UPieWidget::SetColors(TArray<FLinearColor> InColors)
{
Colors = InColors;
}
//绘制多个扇形组成一个圆
int32 UPieWidget::NativePaint(const FPaintArgs& Args,
const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect,
FSlateWindowElementList& OutDrawElements, int32 LayerId,
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
for (int32 Index=0;Index<Angles.Num()-1;Index++)
{
int32 BeginAngle = Angles[Index];
int32 EndAngle = Angles[Index+1];
DrawFan(OutDrawElements,
AllottedGeometry,
LayerId,
FVector2D(300.f, 300.f),
250.f,
BeginAngle,
EndAngle,
GetColorByIndex(Index)
);
}
return LayerId++;
}
//扇形绘制
void UPieWidget::DrawFan(FSlateWindowElementList& OutDrawElements,
const FGeometry& AllottedGemoetry,
int32 Layer,
const FVector2D& CenterPosition,
float Radius,
int32 BeginAngle, int32 EndAngle,
FColor Color) const
{
if(EndAngle < BeginAngle||Radius<0.f)
return;
//顶点数组
TArray<FSlateVertex>SlateVertexArray;
//索引数组
TArray<SlateIndex>SlateIndexArray;
for (int32 CurrentAngle=BeginAngle; CurrentAngle <EndAngle; CurrentAngle++)
{
//当前顶点信息
FSlateVertex CurrentSlateVertex;
//下一个顶点信息
FSlateVertex NextSlateVertex;
//中心坐标顶点信息
FSlateVertex CenterSlateVertex;
//当前顶点位置
FVector2D CurrenSlateVertexPosition = FVector2D(
CenterPosition.X+Radius* FMath::Cos(FMath::DegreesToRadians(CurrentAngle)),
CenterPosition.Y + Radius * FMath::Sin(FMath::DegreesToRadians(CurrentAngle))
);
//下一个顶点的位置信息
FVector2D NextSlateVertexPosition = FVector2D(
CenterPosition.X + Radius * FMath::Cos(FMath::DegreesToRadians(CurrentAngle+1)),
CenterPosition.Y + Radius * FMath::Sin(FMath::DegreesToRadians(CurrentAngle+1))
);
//转换成渲染空间
CurrentSlateVertex.Position = AllottedGemoetry.ToPaintGeometry().GetAccumulatedRenderTransform().TransformPoint(CurrenSlateVertexPosition);
NextSlateVertex.Position =AllottedGemoetry.ToPaintGeometry().GetAccumulatedRenderTransform().TransformPoint(NextSlateVertexPosition);
CenterSlateVertex.Position = AllottedGemoetry.ToPaintGeometry().GetAccumulatedRenderTransform().TransformPoint(CenterPosition);
//顶点颜色值
CurrentSlateVertex.Color = Color;
NextSlateVertex.Color = Color;
CenterSlateVertex.Color = Color;
//顶点下标存储
int32 IndexOfCurrentSlateVertex= SlateVertexArray.Add(CurrentSlateVertex);
int32 IndexOfNextSlateVertex = SlateVertexArray.Add(NextSlateVertex);
int32 IndexOfCenterSlateVertex = SlateVertexArray.Add(CenterSlateVertex);
//虚幻引擎是右手法则,用左手添加绘制出来的三角形可能看不见
SlateIndexArray.Add(IndexOfCurrentSlateVertex);
SlateIndexArray.Add(IndexOfNextSlateVertex);
SlateIndexArray.Add(IndexOfCenterSlateVertex);
}
//顶点的UV
for(FSlateVertex&TempSlateVertex:SlateVertexArray)
{
TempSlateVertex.TexCoords[0] = 0.f;
TempSlateVertex.TexCoords[1] = 0.f;
TempSlateVertex.TexCoords[2] = 0.f;
TempSlateVertex.TexCoords[3] = 0.f;
}
//获取Brush(根据的虚幻引擎其他地方调用采用的同样方式获取的)
const FSlateBrush* SlateBrush = FCoreStyle::Get().GetBrush("ColorSpectrum.Spectrum");
//获取资源句柄
FSlateResourceHandle SlateResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(*SlateBrush);
//绘制自定义顶点
FSlateDrawElement::MakeCustomVerts(
OutDrawElements,
Layer,
SlateResourceHandle,
SlateVertexArray,
SlateIndexArray,
nullptr,
0, 0
);
}
//通过下标获取颜色数组
FColor UPieWidget::GetColorByIndex(int32 InIndex) const
{
if (Colors.Num() < 1)
return FColor::White;
//取余防止越界
return Colors[InIndex % Colors.Num()].ToFColor(true);
}
继承此类创建蓝图
蓝图中五组数据添加:
即可看见我们需要的饼状图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)