基础点绘制
1 思路
在Unreal Engine中单纯的绘制点图元,需要使用UPrimitiveComponent来实现
2 步骤
2.1 创建一个自定义组件
需要创建一个继承自UPrimitiveComponent的自定义组件类。在这个类中,将实现绘制点的逻辑
2.2 重写CreateSceneProxy方法
需要重写CreateSceneProxy方法来创建一个自定义的场景代理(FPrimitiveSceneProxy)。这个代理将包含绘制点的具体实现
2.3 实现自定义的场景代理类
需要创建一个自定义的场景代理类,继承自FPrimitiveSceneProxy在这个类中,将实现实际的绘制逻辑
2.4 在场景代理类中实现绘制逻辑
在自定义的场景代理类中,重写GetDynamicMeshElements方法来绘制点
2.5 使用自定义组件
将这个自定义组件添加到你的Actor中,像使用其他组件一样使用它即可
3 代码实现
3.1 c++代码
3.1.1 自定义组件代码
MyPrimitivePointComponent.h
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#pragma once
#include "CoreMinimal.h"
#include "Components/PrimitiveComponent.h"
#include "MyPointStruct.h"
#include "MyPrimitivePointComponent.generated.h"
/**
* 自定义的点组件,用于绘制点的基本功能
*/
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class CESIUMFORUNREALDESKTOP_API UMyPrimitivePointComponent : public UPrimitiveComponent
{
GENERATED_BODY()
public:
/**
* 创建场景代理以实现自定义的点绘制
*/
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
/**
* 对组件进行线性碰撞检测
*/
virtual bool LineTraceComponent(FHitResult& OutHit, const FVector Start, const FVector End, const FCollisionQueryParams& Params) override;
/**
* 计算组件的包围盒和球体边界
*/
virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;
/** 组件中保存的点的数组 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FMyPointStruct> Points;
/**
* 添加一个点到组件中
* @param Location 点的位置
* @param Color 点的颜色
* @param Size 点的大小
* @param DepthPriority 点的深度优先级
*/
UFUNCTION(BlueprintCallable)
void AddPoint(const FVector& Location, const FLinearColor& Color, float Size, TEnumAsByte<ESceneDepthPriorityGroup> DepthPriority);
};
MyPrimitivePointComponent.cpp
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#include "MyPrimitivePointSceneProxy.h"
#include "PrimitiveViewRelevance.h"
#include "SceneManagement.h"
#include "MyPrimitivePointComponent.h"
FMyPrimitivePointSceneProxy::FMyPrimitivePointSceneProxy(const UPrimitiveComponent* InComponent)
: FPrimitiveSceneProxy(InComponent),
// 从传入的组件中获取点的数组
Points(static_cast<const UMyPrimitivePointComponent*>(InComponent)->Points)
{
// 构造函数初始化场景代理和点数组
}
void FMyPrimitivePointSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
// 遍历所有视图
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
// 遍历并绘制所有点
for (const FMyPointStruct& Point : Points)
{
PDI->DrawPoint(Point.Location, Point.Color, Point.Size, Point.DepthPriority);
}
}
}
}
FPrimitiveViewRelevance FMyPrimitivePointSceneProxy::GetViewRelevance(const FSceneView* View) const
{
FPrimitiveViewRelevance Result;
// 确定是否显示
Result.bDrawRelevance = IsShown(View);
// 动态相关性
Result.bDynamicRelevance = true;
// 阴影相关性,设置为false,因为不需要阴影
Result.bShadowRelevance = false;
// 编辑器相关性,用于在编辑器中正确显示
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
// 自定义深度渲染相关性
Result.bRenderCustomDepth = ShouldRenderCustomDepth();
return Result;
}
SIZE_T FMyPrimitivePointSceneProxy::GetTypeHash() const
{
// 返回当前对象的哈希值
return reinterpret_cast<SIZE_T>(this);
}
uint32 FMyPrimitivePointSceneProxy::GetMemoryFootprint() const
{
// 返回对象占用的内存大小
return sizeof(*this) + GetAllocatedSize();
}
3.1.2 代理类代码
MyPrimitivePointSceneProxy.h
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#pragma once
#include "CoreMinimal.h"
#include "PrimitiveSceneProxy.h"
#include "MyPointStruct.h"
/**
* 自定义的点场景代理,用于渲染 MyPrimitivePointComponent 组件中的点
*/
class CESIUMFORUNREALDESKTOP_API FMyPrimitivePointSceneProxy : public FPrimitiveSceneProxy
{
public:
/**
* 构造函数,初始化场景代理
* @param InComponent 指向所属组件的指针
*/
FMyPrimitivePointSceneProxy(const UPrimitiveComponent* InComponent);
/**
* 获取动态网格元素,用于渲染
*/
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override;
/**
* 获取场景视图相关性,用于确定渲染时的相关性
*/
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override;
/**
* 获取类型哈希值
*/
virtual SIZE_T GetTypeHash() const override;
/**
* 获取内存占用
*/
virtual uint32 GetMemoryFootprint() const override;
private:
/** 保存要渲染的点的数组 */
const TArray<FMyPointStruct>& Points;
};
MyPrimitivePointSceneProxy.cpp
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#include "MyPrimitivePointSceneProxy.h"
#include "PrimitiveViewRelevance.h"
#include "SceneManagement.h"
#include "MyPrimitivePointComponent.h"
FMyPrimitivePointSceneProxy::FMyPrimitivePointSceneProxy(const UPrimitiveComponent* InComponent)
: FPrimitiveSceneProxy(InComponent),
// 从传入的组件中获取点的数组
Points(static_cast<const UMyPrimitivePointComponent*>(InComponent)->Points)
{
// 构造函数初始化场景代理和点数组
}
void FMyPrimitivePointSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
// 遍历所有视图
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
// 遍历并绘制所有点
for (const FMyPointStruct& Point : Points)
{
PDI->DrawPoint(Point.Location, Point.Color, Point.Size, Point.DepthPriority);
}
}
}
}
FPrimitiveViewRelevance FMyPrimitivePointSceneProxy::GetViewRelevance(const FSceneView* View) const
{
FPrimitiveViewRelevance Result;
// 确定是否显示
Result.bDrawRelevance = IsShown(View);
// 动态相关性
Result.bDynamicRelevance = true;
// 阴影相关性,设置为false,因为不需要阴影
Result.bShadowRelevance = false;
// 编辑器相关性,用于在编辑器中正确显示
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
// 自定义深度渲染相关性
Result.bRenderCustomDepth = ShouldRenderCustomDepth();
return Result;
}
SIZE_T FMyPrimitivePointSceneProxy::GetTypeHash() const
{
// 返回当前对象的哈希值
return reinterpret_cast<SIZE_T>(this);
}
uint32 FMyPrimitivePointSceneProxy::GetMemoryFootprint() const
{
// 返回对象占用的内存大小
return sizeof(*this) + GetAllocatedSize();
}
3.1.3 演员类代码
MyPointActor.h
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyPointActor.generated.h"
UCLASS()
class CESIUMFORUNREALDESKTOP_API AMyPointActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyPointActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintCallable, Category = "Custom")
void AddPoint(const FVector& Location, const FLinearColor& Color, float Size, TEnumAsByte<ESceneDepthPriorityGroup> DepthPriority);
private:
UPROPERTY(VisibleAnywhere)
class UMyPrimitivePointComponent* CustomPrimitivePointComponent;
};
MyPointActor.cpp
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#include "MyPointActor.h"
#include "MyPrimitivePointComponent.h"
// Sets default values
AMyPointActor::AMyPointActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CustomPrimitivePointComponent = CreateDefaultSubobject<UMyPrimitivePointComponent>(TEXT("MyPrimitivePointComponent"));
RootComponent = CustomPrimitivePointComponent;
}
// Called when the game starts or when spawned
void AMyPointActor::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AMyPointActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AMyPointActor::AddPoint(const FVector& Location, const FLinearColor& Color, float Size, TEnumAsByte<ESceneDepthPriorityGroup> DepthPriority)
{
if (CustomPrimitivePointComponent)
{
CustomPrimitivePointComponent->AddPoint(Location, Color, Size, DepthPriority);
}
}
3.1.4 点结构代码
MyPointStruct.h
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Engine/EngineTypes.h"
#include "MyPointStruct.generated.h"
/**
* 结构体,用于表示一个点的位置、颜色、大小和深度优先级
*/
USTRUCT(BlueprintType)
struct FMyPointStruct
{
GENERATED_BODY()
public:
/** 点的位置 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector Location;
/** 点的颜色 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FLinearColor Color;
/** 点的大小 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Size;
/** 点的深度优先级 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TEnumAsByte<enum ESceneDepthPriorityGroup> DepthPriority;
/** 默认构造函数 */
FMyPointStruct()
: Location(FVector::ZeroVector), Color(FLinearColor::White), Size(1.0f), DepthPriority(SDPG_MAX)
{}
/** 构造函数,初始化位置、颜色、大小和深度优先级 */
FMyPointStruct(const FVector& InLocation, const FLinearColor& InColor, float InSize, TEnumAsByte<ESceneDepthPriorityGroup> InDepthPriority)
: Location(InLocation), Color(InColor), Size(InSize), DepthPriority(InDepthPriority)
{}
};