UE5多人MOBA+GAS 39、制作角色上半身UI

文章目录


创建渲染Acotr和显示ActorUI的基类

RenderActor

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "RenderActor.generated.h"

/**
 * 渲染专用Actor类,用于场景捕获和渲染到纹理
 * 
 * 主要功能:
 *  - 创建一个离屏渲染场景
 *  - 捕获指定目标的高质量图像
 *  - 将渲染结果输出到RenderTarget纹理
 */
UCLASS()
class CRUNCH_API ARenderActor : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	ARenderActor();
	/**
	 * 设置渲染目标纹理
	 * @param RenderTarget 要渲染到的目标纹理
	 */
	void SetRenderTarget(class UTextureRenderTarget2D* RenderTarget);
	
	/**
	 * 执行场景捕获操作
	 * 调用后会将当前场景渲染到预设的RenderTarget
	 */
	void UpdateRender();
	
	// 获取场景捕获组件(用于进一步配置)
	FORCEINLINE class USceneCaptureComponent2D* GetCaptureComponent() const { return CaptureComponent; }
protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

private:
	/** 根组件,用于组织场景层次 */
	UPROPERTY(VisibleDefaultsOnly, Category = "Render Actor")
	class USceneComponent* RootComp;

	/**
	 * 场景捕获组件,核心渲染功能
	 * 将3D场景渲染为2D纹理
	 */
	UPROPERTY(VisibleDefaultsOnly, Category = "Render Actor")
	class USceneCaptureComponent2D* CaptureComponent;
};
cpp 复制代码
#include "RenderActor.h"

#include "Components/SceneCaptureComponent2D.h"


// Sets default values
ARenderActor::ARenderActor()
{
	PrimaryActorTick.bCanEverTick = true;

	// 创建场景锚点作为根组件
	RootComp = CreateDefaultSubobject<USceneComponent>("Root Comp");
	SetRootComponent(RootComp);

	// 创建场景捕获组件并添加到根组件
	CaptureComponent = CreateDefaultSubobject<USceneCaptureComponent2D>("Capture Component");
	CaptureComponent->SetupAttachment(RootComp);

	// 配置捕获参数
	CaptureComponent->bCaptureEveryFrame = false;	// 禁用自动捕获,手动控制
	CaptureComponent->FOVAngle = 30.f;				// 窄视角适合头部特写
}

void ARenderActor::SetRenderTarget(UTextureRenderTarget2D* RenderTarget)
{
	CaptureComponent->TextureTarget = RenderTarget;
}

void ARenderActor::UpdateRender()
{
	if (CaptureComponent)
	{
		// 捕获场景
		CaptureComponent->CaptureScene();
	}
}

// Called when the game starts or when spawned
void ARenderActor::BeginPlay()
{
	Super::BeginPlay();

	// 只显示当前Actor的组件到捕获画面
	CaptureComponent->ShowOnlyActorComponents(this);

	// 将Actor移动到远离主场景的位置,避免干扰
	SetActorLocation(FVector{0.f, 0.f, 100000.f});
}

继承基类完善头像渲染功能

RenderActorWidget创建渲染Acotr的UI

PURE_VIRTUAL跟在纯虚函数后面写一个=0差不多

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "RenderActorWidget.generated.h"

class ARenderActor;
class USizeBox;
class UImage;
/**
 * 
 */
UCLASS()
class CRUNCH_API URenderActorWidget : public UUserWidget
{
	GENERATED_BODY()
protected:
	// 构建前回调(可用于初始化参数)
	virtual void NativePreConstruct() override;

	// 构建时回调(用于初始化控件、渲染等)
	virtual void NativeConstruct() override;

	// 销毁时回调(用于清理资源)
	virtual void BeginDestroy() override;
private:
	// 配置渲染Actor(设置渲染目标等)
	void ConfigureRenderActor();

	// 派生类实现:生成渲染Actor
	virtual void SpawnRenderActor() PURE_VIRTUAL(URenderActorWidget::SpawnRenderActor, ); 

	// 派生类实现:获取渲染Actor实例
	virtual ARenderActor* GetRenderActor() const PURE_VIRTUAL(URenderActorWidget::GetRenderActor, return nullptr; );

	// 开始渲染捕获(定时刷新渲染)
	void BeginRenderCapture();

	// 更新渲染内容
	void UpdateRender();

	// 停止渲染捕获
	void StopRenderCapture();
	
	// 显示渲染结果的图片控件
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UImage> DisplayImage;
	
	// 控制渲染区域大小的控件
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<USizeBox> RenderSizeBox;

	// 材质参数名,用于绑定渲染目标纹理
	UPROPERTY(EditDefaultsOnly, Category = "Render Actor")
	FName DisplayImageRenderTargetParamName = "RenderTarget";

	// 渲染区域尺寸
	UPROPERTY(EditDefaultsOnly, Category = "Render Actor")
	FVector2D RenderSize;

	// 渲染帧率
	UPROPERTY(EditDefaultsOnly, Category = "Render Actor")
	int32 FrameRate = 24;

	// 渲染定时器间隔
	float RenderTickInterval;

	// 渲染定时器句柄
	FTimerHandle RenderTimerHandle;

	// 渲染目标纹理
	UPROPERTY()
	TObjectPtr<UTextureRenderTarget2D> RenderTarget;
};
cpp 复制代码
#include "RenderActorWidget.h"

#include "RenderActor.h"
#include "Components/Image.h"
#include "Components/SizeBox.h"
#include "Engine/TextureRenderTarget2D.h"

void URenderActorWidget::NativePreConstruct()
{
	Super::NativePreConstruct();
	// 设置大小
	RenderSizeBox->SetWidthOverride(RenderSize.X);
	RenderSizeBox->SetHeightOverride(RenderSize.Y);
}

void URenderActorWidget::NativeConstruct()
{
	Super::NativeConstruct();
	// 创建特定类型的渲染Actor(由子类实现)
	SpawnRenderActor();
	
	// 配置渲染Actor和渲染目标
	ConfigureRenderActor();
	
	// 启动渲染循环
	BeginRenderCapture();
}

void URenderActorWidget::BeginDestroy()
{
	// 停止渲染循环(避免内存泄漏)
	StopRenderCapture();
	Super::BeginDestroy();
}

void URenderActorWidget::ConfigureRenderActor()
{
	if (!GetRenderActor())
	{
		UE_LOG(LogTemp, Error, TEXT("没有渲染Actor,将不会渲染任何内容"));
		return;
	}

	// 创建渲染目标纹理
	RenderTarget = NewObject<UTextureRenderTarget2D>(this);

	// 设置格式和尺寸
	RenderTarget->InitAutoFormat(static_cast<uint32>(RenderSize.X), static_cast<uint32>(RenderSize.Y));
	RenderTarget->RenderTargetFormat = ETextureRenderTargetFormat::RTF_RGBA8_SRGB; // 使用sRGB格式保证颜色准确

	// 将渲染目标设置给Actor
	GetRenderActor()->SetRenderTarget(RenderTarget);

	// 获取显示图像的动态材质实例
	UMaterialInstanceDynamic* DisplayImageDynamicMaterial = DisplayImage->GetDynamicMaterial();

	if (DisplayImageDynamicMaterial)
	{
		// 绑定渲染目标纹理
		DisplayImageDynamicMaterial->SetTextureParameterValue(DisplayImageRenderTargetParamName, RenderTarget);
	}
}

void URenderActorWidget::BeginRenderCapture()
{
	// 计算渲染间隔(秒/帧)
	RenderTickInterval = 1.f / static_cast<float>(FrameRate);
	
	// 获取世界上下文
	UWorld* World = GetWorld();
	if (World)
	{
		// 设置定时器按指定帧率调用渲染更新
		World->GetTimerManager().SetTimer(
			RenderTimerHandle, 
			this, 
			&URenderActorWidget::UpdateRender,
			RenderTickInterval, 
			true // 循环执行
		);
	}
}

void URenderActorWidget::UpdateRender()
{
	// 安全检查后执行渲染更新
	if (GetRenderActor())
	{
		GetRenderActor()->UpdateRender();
	}
}

void URenderActorWidget::StopRenderCapture()
{
	UWorld* World = GetWorld();
	if (World)
	{
		// 停止定时器
		World->GetTimerManager().ClearTimer(RenderTimerHandle);
	}
}

继承RenderActor创建SkeletalMeshRenderActor渲染骨骼网格体

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "UI/Common/Rendering/RenderActor.h"
#include "SkeletalMeshRenderActor.generated.h"

/**
 * 用于在UI中渲染骨骼网格体的Actor
 * 继承自通用渲染Actor,可设置骨骼网格和动画蓝图
 */
UCLASS()
class CRUNCH_API ASkeletalMeshRenderActor : public ARenderActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	ASkeletalMeshRenderActor();
	// 配置骨骼网格和动画蓝图
	void ConfigureSkeletalMesh(USkeletalMesh* MeshAsset, TSubclassOf<UAnimInstance> AnimBlueprint);

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

private:
	// 渲染的骨骼网格体组件
	UPROPERTY(VisibleAnywhere, Category = "Skeletal Mesh Renderer")
	TObjectPtr<USkeletalMeshComponent> MeshComp;
};
cpp 复制代码
#include "SkeletalMeshRenderActor.h"
#include "Components/SkeletalMeshComponent.h"

// Sets default values
ASkeletalMeshRenderActor::ASkeletalMeshRenderActor()
{
	MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh Comp"));
	MeshComp->SetupAttachment(GetRootComponent());

	// 禁用碰撞
	MeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	// 设置光照通道,仅使用第二通道(通常用于UI渲染优化)
	MeshComp->SetLightingChannels(false, true, false);
}

void ASkeletalMeshRenderActor::ConfigureSkeletalMesh(USkeletalMesh* MeshAsset, TSubclassOf<UAnimInstance> AnimBlueprint)
{
	// 设置骨骼网格资源
	MeshComp->SetSkeletalMeshAsset(MeshAsset);

	// 设置动画蓝图
	MeshComp->SetAnimInstanceClass(AnimBlueprint);
}

// Called when the game starts or when spawned
void ASkeletalMeshRenderActor::BeginPlay()
{
	Super::BeginPlay();
	
	// 仅在场景捕获时可见(用于UI渲染,不显示在主场景)
	MeshComp->SetVisibleInSceneCaptureOnly(true);
}

创建其蓝图

设置一下骨骼网格体

调一下位置

不知道这个有啥用

继承RenderActorWidget创建SkeletalMeshRenderWidget

cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "UI/Common/Rendering/RenderActorWidget.h"
#include "SkeletalMeshRenderWidget.generated.h"

class ASkeletalMeshRenderActor;
/**
 * 用于在UI中渲染骨骼网格体的Widget
 * 负责生成和管理骨骼网格渲染Actor
 */
UCLASS()
class CRUNCH_API USkeletalMeshRenderWidget : public URenderActorWidget
{
	GENERATED_BODY()
public:
	// 构建时回调(初始化控件和渲染Actor)
	virtual void NativeConstruct() override;

private:
	// 生成骨骼网格渲染Actor实例
	virtual void SpawnRenderActor() override; 

	// 获取骨骼网格渲染Actor实例
	virtual ARenderActor* GetRenderActor() const override;
	
	// 骨骼网格渲染Actor的类(可在编辑器中指定)
	UPROPERTY(EditDefaultsOnly, Category = "SKeletal Mesh Render")
	TSubclassOf<ASkeletalMeshRenderActor> SkeletalMeshRenderActorClass;

	// 当前生成的骨骼网格渲染Actor实例
	UPROPERTY()
	TObjectPtr<ASkeletalMeshRenderActor> SkeletalMeshRenderActor;
};
cpp 复制代码
#include "SkeletalMeshRenderWidget.h"

#include "SkeletalMeshRenderActor.h"
#include "GameFramework/Character.h"

void USkeletalMeshRenderWidget::NativeConstruct()
{
	Super::NativeConstruct();
	
	// 获取拥有该UI的玩家角色
	ACharacter* PlayerCharacter = GetOwningPlayerPawn<ACharacter>();

	if (PlayerCharacter && SkeletalMeshRenderActor)
	{
		// 配置骨骼网格和动画类
		SkeletalMeshRenderActor->ConfigureSkeletalMesh(
			PlayerCharacter->GetMesh()->GetSkeletalMeshAsset(), 
			PlayerCharacter->GetMesh()->GetAnimClass()
		);
	}
	
}

void USkeletalMeshRenderWidget::SpawnRenderActor()
{
	if (!SkeletalMeshRenderActorClass) return;

	UWorld* World = GetWorld();
	if (!World) return;

	// 设置生成参数
	FActorSpawnParameters SpawnParams;
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;

	// 生成渲染Actor
	SkeletalMeshRenderActor = World->SpawnActor<ASkeletalMeshRenderActor>(SkeletalMeshRenderActorClass, SpawnParams);
}

ARenderActor* USkeletalMeshRenderWidget::GetRenderActor() const
{
	return SkeletalMeshRenderActor;
}

GameplayWidget中添加头像UI

cpp 复制代码
	// 头像UI
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<USkeletalMeshRenderWidget> HeadshotWidget;

创建头像UI

创建一个材质设置为用户界面以及半透明

创建一个材质实例后放到UI的图像中去

最后把这个UI放进GameplayWidget中去

然后就可以渲染出人头了

然后会看到角色的脸色不是很好,可以加点灯泡

加了灯泡后,看起来就亮多了