【虚幻引擎UE】UE5 蓝图/C++绘制图形(球体绘制为例)

本文介绍了如何在虚幻引擎UE5中使用C++代码和蓝图进行球体绘制,包括网格球体和球体模型的创建过程,并提供拓展学习内容,如UE4的屏幕绘制技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、网格球体绘制

在这里插入图片描述
在这里插入图片描述
center 中心点向量
segments参数越大,线条越多
radius是球体半径
thickness 厚度可以不用管
Depth Priority 是渲染深度可以不用管
F Life Time 是持续时间

C++代码如下——

.cpp

#include "drawBallFunc.h"
#include "Components/LineBatchComponent.h"
#include "Engine/World.h"
#include "EngineGlobals.h"
#include "PrimitiveViewRelevance.h"
#include "PrimitiveSceneProxy.h"
#include "Engine/Engine.h"
#include "MaterialShared.h"
#include "Materials/Material.h"
#include "Engine/CollisionProfile.h"
#include "SceneManagement.h"
#include "DynamicMeshBuilder.h"

void UdrawBallFunc::drawCustomBallFunc(UObject* WorldContextObject, const FVector& Center, int32 Segments, float Radius, const FColor& Color, uint8 DepthPriority, float fLifeTime, float Thickness)
{

	ULineBatchComponent* const LineBatcher = WorldContextObject->GetWorld()->PersistentLineBatcher;
	//LineBatcher->DrawCircle(Center, X, Y, Color, Radius, Segments, DepthPriority);
	//LineBatcher->DrawPoint(Center, Color, Radius, DepthPriority, fLifeTime);
	// Need at least 4 segments
	Segments = FMath::Max(Segments, 4);

	FVector Vertex1, Vertex2, Vertex3, Vertex4;
	const float AngleInc = 2.f * PI / float(Segments);
	int32 NumSegmentsY = Segments;
	float Latitude = AngleInc;
	int32 NumSegmentsX;
	float Longitude;
	float SinY1 = 0.0f, CosY1 = 1.0f, SinY2, CosY2;
	float SinX, CosX;

	TArray<FBatchedLine> Lines;
	Lines.Empty(NumSegmentsY * Segments * 2);
	while (NumSegmentsY--)
	{
		SinY2 = FMath::Sin(Latitude);
		CosY2 = FMath::Cos(Latitude);

		Vertex1 = FVector(SinY1, 0.0f, CosY1) * Radius + Center;
		Vertex3 = FVector(SinY2, 0.0f, CosY2) * Radius + Center;
		Longitude = AngleInc;

		NumSegmentsX = Segments;
		while (NumSegmentsX--)
		{
			SinX = FMath::Sin(Longitude);
			CosX = FMath::Cos(Longitude);

			Vertex2 = FVector((CosX * SinY1), (SinX * SinY1), CosY1) * Radius + Center;
			Vertex4 = FVector((CosX * SinY2), (SinX * SinY2), CosY2) * Radius + Center;

			Lines.Add(FBatchedLine(Vertex1, Vertex2, Color, fLifeTime, Thickness, DepthPriority));
			Lines.Add(FBatchedLine(Vertex1, Vertex3, Color, fLifeTime, Thickness, DepthPriority));

			Vertex1 = Vertex2;
			Vertex3 = Vertex4;
			Longitude += AngleInc;
		}
		SinY1 = SinY2;
		CosY1 = CosY2;
		Latitude += AngleInc;
	}
	LineBatcher->DrawLines(Lines);
}

.h

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

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "drawBallFunc.generated.h"

/**
 *
 */
UCLASS()
class DRAWBALL_API UdrawBallFunc : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
		UFUNCTION(BlueprintCallable, Category = "Custom", meta = (Keywords = "draw"))
		static void drawCustomBallFunc(UObject* WorldContextObject, const FVector& Center, int32 Segments, float Radius, const FColor& Color, uint8 DepthPriority, float fLifeTime, float Thickness);
};

二、球体模型绘制

在这里插入图片描述

1、创建一个默认球体
在这里插入图片描述
2、创建球体对象生成器,并输入缩放向量(后面根据需要,也可以补充一下材质替换的代码)
在这里插入图片描述3、传入半径*2是最终尺寸 在这里插入图片描述

三、拓展学习

UE4 C++ 在屏幕上绘制线和文字的方法

拓展绘制方法!!!

绘制函数 Debug drawing functions相关方法 (仅限于开发调试和参考):

FORCEINLINE void FlushPersistentDebugLines(const UWorld* InWorld) {}
FORCEINLINE void DrawDebugLine(const UWorld* InWorld, FVector const& LineStart, FVector const& LineEnd, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugPoint(const UWorld* InWorld, FVector const& Position, float Size, FColor const& PointColor, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugDirectionalArrow(const UWorld* InWorld, FVector const& LineStart, FVector const& LineEnd, float ArrowSize, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugBox(const UWorld* InWorld, FVector const& Center, FVector const& Extent, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugBox(const UWorld* InWorld, FVector const& Center, FVector const& Extent, const FQuat& Rotation, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugCoordinateSystem(const UWorld* InWorld, FVector const& AxisLoc, FRotator const& AxisRot, float Scale, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugCrosshairs(const UWorld* InWorld, FVector const& AxisLoc, FRotator const& AxisRot, float Scale, const FColor& Color = FColor::White, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugCircle(const UWorld* InWorld, const FMatrix& TransformMatrix, float Radius, int32 Segments, const FColor& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f, bool bDrawAxis = true) {}
FORCEINLINE void DrawDebugCircle(const UWorld* InWorld, FVector Center, float Radius, int32 Segments, const FColor& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f, FVector YAxis = FVector(0.f, 1.f, 0.f), FVector ZAxis = FVector(0.f, 0.f, 1.f), bool bDrawAxis = true) {}
FORCEINLINE void DrawDebugCircleArc(const UWorld* InWorld, FVector const& Center, float Radius, FVector const& Direction, float AngleWidth, int32 Segments, const FColor& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebug2DDonut(const UWorld* InWorld, const FMatrix& TransformMatrix, float InnerRadius, float OuterRadius, int32 Segments, const FColor& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugSphere(const UWorld* InWorld, FVector const& Center, float Radius, int32 Segments, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugCylinder(const UWorld* InWorld, FVector const& Start, FVector const& End, float Radius, int32 Segments, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugCone(const UWorld* InWorld, FVector const& Origin, FVector const& Direction, float Length, float AngleWidth, float AngleHeight, int32 NumSides, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugAltCone(const UWorld* InWorld, FVector const& Origin, FRotator const& Rotation, float Length, float AngleWidth, float AngleHeight, FColor const& DrawColor, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawDebugString(const UWorld* InWorld, FVector const& TextLocation, const FString& Text, class AActor* TestBaseActor = NULL, FColor const& TextColor = FColor::White, float Duration = -1.000000, bool bDrawShadow = false, float FontScale = 1.f) {}
FORCEINLINE void DrawDebugFrustum(const UWorld* InWorld, const FMatrix& FrustumToWorld, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0.f) {}
FORCEINLINE void DrawCircle(const UWorld* InWorld, const FVector& Base, const FVector& X, const FVector& Y, const FColor& Color, float Radius, int32 NumSides, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0) {}
FORCEINLINE void DrawDebugCapsule(const UWorld* InWorld, FVector const& Center, float HalfHeight, float Radius, const FQuat& Rotation, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0, float Thickness = 0) {}
FORCEINLINE void DrawDebugCamera(const UWorld* InWorld, FVector const& Location, FRotator const& Rotation, float FOVDeg, float Scale = 1.f, FColor const& Color = FColor::White, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void FlushDebugStrings(const UWorld* InWorld) {}
FORCEINLINE void DrawDebugSolidBox(const UWorld* InWorld, FBox const& Box, FColor const& Color, const FTransform& Transform = FTransform::Identity, bool bPersistent = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugSolidBox(const UWorld* InWorld, FVector const& Center, FVector const& Extent, FColor const& Color, bool bPersistent = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugSolidBox(const UWorld* InWorld, FVector const& Center, FVector const& Extent, FQuat const& Rotation, FColor const& Color, bool bPersistent = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugMesh(const UWorld* InWorld, TArray<FVector> const& Verts, TArray<int32> const& Indices, FColor const& Color, bool bPersistent = false, float LifeTime = -1.f, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugSolidPlane(const UWorld* InWorld, FPlane const& P, FVector const& Loc, float Size, FColor const& Color, bool bPersistent = false, float LifeTime = -1, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugSolidPlane(const UWorld* InWorld, FPlane const& P, FVector const& Loc, FVector2D const& Extents, FColor const& Color, bool bPersistent = false, float LifeTime = -1, uint8 DepthPriority = 0) {}
FORCEINLINE void DrawDebugFloatHistory(UWorld const & WorldRef, FDebugFloatHistory const & FloatHistory, FTransform const & DrawTransform, FVector2D const & DrawSize, FColor const & DrawColor, bool const & bPersistent = false, float const & LifeTime = -1.f, uint8 const & DepthPriority = 0) {}
FORCEINLINE void DrawDebugFloatHistory(UWorld const & WorldRef, FDebugFloatHistory const & FloatHistory, FVector const & DrawLocation, FVector2D const & DrawSize, FColor const & DrawColor, bool const & bPersistent = false, float const & LifeTime = -1.f, uint8 const & DepthPriority = 0) {}
FORCEINLINE void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector& Start, const FVector& End, const FLinearColor& LineColor) {}
FORCEINLINE void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector2D& StartPosition, const FVector2D& EndPosition, const FLinearColor& LineColor, const float& LineThickness = 1.f) {}
FORCEINLINE void DrawDebugCanvas2DCircle(UCanvas* Canvas, const FVector2D& Center, float Radius, int32 NumSides, const FLinearColor& LineColor, const float& LineThickness = 1.f) {}
FORCEINLINE void DrawDebugCanvas2DBox(UCanvas* Canvas, const FBox2D& Box, const FLinearColor& LineColor, const float& LineThickness = 1.f) {}
FORCEINLINE void DrawDebugCanvasLine(UCanvas* Canvas, const FVector& Start, const FVector& End, const FLinearColor& LineColor) {}
FORCEINLINE void DrawDebugCanvasCircle(UCanvas* Canvas, const FVector& Base, const FVector& X, const FVector& Y, FColor Color, float Radius, int32 NumSides) {}
FORCEINLINE void DrawDebugCanvasWireSphere(UCanvas* Canvas, const FVector& Base, FColor Color, float Radius, int32 NumSides) {}
FORCEINLINE void DrawDebugCanvasWireCone(UCanvas* Canvas, const FTransform& Transform, float ConeRadius, float ConeAngle, int32 ConeSides, FColor Color) {}

绘制函数LineBatcher drawing functions相关方法:

void ULineBatchComponent::DrawLines(const TArray<FBatchedLine>& InLines)
void ULineBatchComponent::DrawLine(const FVector& Start, const FVector& End, const FLinearColor& Color, uint8 DepthPriority, const float Thickness, const float LifeTime)

void ULineBatchComponent::DrawPoint(const FVector& Position,const FLinearColor& Color,float PointSize,
 uint8 DepthPriority,float LifeTime)
 
void ULineBatchComponent::DrawMesh(TArray<FVector> const& Verts, TArray<int32> const& Indices, FColor const& Color, uint8 DepthPriority, float LifeTime)

void ULineBatchComponent::DrawDirectionalArrow(const FMatrix& ArrowToWorld,FColor InColor,float Length,float ArrowSize,uint8 DepthPriority)

void ULineBatchComponent::DrawSolidBox(const FBox& Box, const FTransform& Xform, const FColor& Color, uint8 DepthPriority, float LifeTime)

void ULineBatchComponent::DrawBox(const FBox& Box, const FMatrix& TM, const FColor& Color, uint8 InDepthPriorityGroup)

<think>好的,用户现在的问题是想要知道如何在UE5 C++中为QueryCylinderAttachedAsync函数绑定触发事件。之前他已经问过如何将结果存储到FAntContactInfo结构体中,我的回答是建议使用回调函数,通过委托来处理异步结果。现在他可能对具体的实现步骤还有疑问,特别是代码如何编写。 首先,我需要确认用户对UE5C++和委托机制的理解程度。他提到自己是小白,所以可能需要更详细的步骤和示。之前的回答已经涉及了声明委托和绑定回调,但用户可能在实际编码中遇到了问题,或者需要更具体的代码示。 接下来,用户的问题可能集中在如何正确声明委托,如何将回调函数绑定到异步函数,以及如何在蓝图中调用这个函数。需要注意的是,UE5中的委托有多种类型,比如动态委托可以在蓝图中使用,而普通委托可能不行。用户可能需要动态委托来支持蓝图调用。 另外,用户可能没有正确地将回调参数添加到QueryCylinderAttachedAsync函数中,或者在绑定lambda表达式时出现了错误。需要检查函数参数是否包含委托,以及委托的声明是否正确。 可能的误区包括:忘记在UFUNCTION宏中添加必要的说明,导致蓝图无法识别;委托声明不正确,参数类型不匹配;或者在绑定回调时没有正确创建委托实。这些都是需要详细解释的地方。 此外,需要确保用户了解异步操作的处理流程,即调用函数后立即返回句柄,但结果需要等待回调触发。可能需要强调异步编程的特点,避免用户期望立即获取结果。 最后,用户可能需要验证数据是否正确获取,建议添加调试输出或可视化调试手段,如绘制调试图形,来确认回调是否被正确触发,并且数据结构有效。 总结来说,回答需要分步骤详细说明委托的声明、函数的修改、回调的绑定,以及调试方法,同时注意用户的小白身份,使用简单明了的语言和示代码,避免过于复杂的术语,并指出常见错误和注意事项。</think>--- ### **分步实现:为 `QueryCylinderAttachedAsync` 绑定事件(UE5 C++ 版)** 以下是 **完整的代码实现步骤**,包含委托声明、函数修改和事件绑定。针对新手优化,直接复制粘贴即可使用: --- #### **第一步:声明委托类型(类头文件中)** 在声明函数的类头文件(如 `YourClass.h`)顶部添加委托类型: ```cpp // 自定义委托类型(用于接收异步结果) DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAntQueryCompletedDelegate, const FAntContactInfo&, ContactInfo); ``` - **为什么需要这个?** UE 的异步操作需要通过委托(Delegate)回调传递结果,类似“订阅-通知”机制。 --- #### **第二步:修改函数参数(添加回调)** 修改 `QueryCylinderAttachedAsync` 的函数声明,添加回调参数: ```cpp // 在类头文件中修改函数声明 UFUNCTION(BlueprintCallable, Category = "Ant Movement", meta = (WorldContext = "WorldContextObject")) static FAntHandle QueryCylinderAttachedAsync( const UObject* WorldContextObject, FAntHandle AgentHandle, float Radius, float Height, UPARAM(meta = (Bitmask, BitmaskEnum = "/Script/Ant.EAntGroups")) int32 Flags, bool MustIncludeCenter, float Interval = -1.0f, const FOnAntQueryCompletedDelegate& OnCompleted = FOnAntQueryCompletedDelegate() // 新增回调参数 ); ``` --- #### **第三步:在 C++ 中绑定事件(示)** 在调用该函数的地方(如某个 Actor 或 Component 中)绑定回调: ```cpp // 示:在某个函数内调用并绑定事件 void AMyActor::SearchEnemies() { FAntHandle QueryHandle = UYourClass::QueryCylinderAttachedAsync( GetWorld(), // 传递WorldContext MyAgentHandle, // 你的Agent句柄 1000.0f, // 半径 300.0f, // 高度 (int32)EAntGroups::Enemy, true, // 必须包含中心 -1.0f, // 间隔时间 // 绑定Lambda回调(实际处理数据的逻辑) FOnAntQueryCompletedDelegate::CreateLambda([this](const FAntContactInfo& ContactInfo) { // 当异步查询完成时,这里会自动执行! if (ContactInfo.IsValid()) { UE_LOG(LogTemp, Warning, TEXT("发现目标:%s"), *ContactInfo.TargetActor->GetName()); // 可以在这里将ContactInfo存储到成员变量 this->LastContactInfo = ContactInfo; } }) ); // 可选:保存句柄以便后续管理(如取消查询) ActiveQueryHandle = QueryHandle; } ``` --- #### **第四步:蓝图调用(可选)** 如果想在蓝图中绑定事件,需要额外步骤: 1. **将委托标记为 `BlueprintAssignable`** 修改委托声明: ```cpp DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAntQueryCompletedDelegate, const FAntContactInfo&, ContactInfo); ``` 改为: ```cpp DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAntQueryCompletedDelegate, const FAntContactInfo&, ContactInfo); ``` 2. **在蓝图中绑定事件** ```plaintext +-------------------------+ | 调用 QueryCylinder... | --> OnCompleted 引脚 +-------------------------+ | v [自定义事件:处理 ContactInfo] ``` --- #### **关键注意事项** 1. **异步特性**:回调函数不会立刻执行,可能需要等待几帧(取决于查询耗时)。 2. **内存安全**:如果对象被销毁前异步操作未完成,需手动取消查询(通过 `FAntHandle`)。 3. **参数匹配**:确保 `FAntContactInfo` 的成员与你预期的数据一致(检查插件文档)。 --- ### **调试技巧** 在回调中添加可视化调试: ```cpp // 在Lambda回调中添加: DrawDebugSphere( GetWorld(), ContactInfo.Location, 100.0f, 12, FColor::Green, false, 5.0f ); ``` 这会在查询到的位置绘制一个绿色球体,持续5秒。 --- 如果需要更具体的帮助,请提供 `FAntHandle` 和 `FAntContactInfo` 的具体定义(通常来自插件头文件)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

灵境引路人

感谢投喂 ~ ❤

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

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

打赏作者

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

抵扣说明:

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

余额充值