Cesium4Unreal - #001 点图元绘制

16 篇文章 5 订阅 ¥299.90 ¥399.90
本文档详细介绍了如何在Unreal Engine中利用C++自定义组件和场景代理来实现基础点图元的绘制。通过创建继承自UPrimitiveComponent的组件,重写CreateSceneProxy方法并实现自定义场景代理类,最终在代理类中实现绘制逻辑,实现了在Unreal Engine中绘制点的功能。
摘要由CSDN通过智能技术生成


基础点绘制

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

3.2 蓝图代码

在这里插入图片描述

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

满天飞飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值