Files
BladeSmith/Source/BladeSmith/IronBlock.cpp
T
2025-11-16 00:40:42 +08:00

183 lines
6.0 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "IronBlock.h"
// 确保包含了 RDG 所需的头文件
#include "RenderGraphBuilder.h"
#include "RenderGraphUtils.h" // FComputeShaderUtils::AddPass
#include "FDeformComputeShader.h" // 确保这个头文件存在且包含了 FDeformationCSDispatchParams
#include "StaticMeshResources.h"
#include "TextureResource.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Engine/StaticMesh.h"
#include "Engine/Texture2D.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "PhysicsEngine/BodySetup.h"
#include "RHICommandList.h"
#include "Engine/Texture.h"
#include "GenericPlatform/GenericPlatformProcess.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetRenderingLibrary.h"
// Sets default values
AIronBlock::AIronBlock() : StaticMeshComp(nullptr), DeformBaseMat(nullptr), DeformCalMat(nullptr),
PositionRenderTarget0(nullptr), PositionRenderTarget1(nullptr),
DynMaterial(nullptr), DynCalMaterial(nullptr)
{
// 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;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
StaticMeshComp->AttachToComponent(RootComponent,FAttachmentTransformRules::SnapToTargetIncludingScale);
//RootComponent = StaticMeshComp;
}
void AIronBlock::PostInitProperties()
{
// 必须调用父类实现
Super::PostInitProperties();
// 检查:如果 StaticMeshComp 没有被赋予任何网格(即在编辑器中没有设置)
// 并且我们正在处理 Class Default Object (CDO),通常用来设置类级的默认值
if (StaticMeshComp && !StaticMeshComp->GetStaticMesh())
{
// 只有当网格为空时,才加载并设置默认的 Cube
UStaticMesh* DefaultMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/BasicShapes/Cube"));
if (DefaultMesh)
{
StaticMeshComp->SetStaticMesh(DefaultMesh);
}
}
}
// Called when the game starts or when spawned
void AIronBlock::BeginPlay()
{
Super::BeginPlay();
InitializePositionTexture();
}
/**
* 核心修复:创建一个配置好用于变形计算的 RenderTarget
*/
UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32 Size)
{
UTextureRenderTarget2D* RenderTarget = NewObject<UTextureRenderTarget2D>(this, FName(*RTName));
if (RenderTarget)
{
RenderTarget->InitCustomFormat(Size, Size, PF_A32B32G32R32F, false);
RenderTarget->bNeedsTwoCopies = true; // 告知引擎这个纹理会被用于Ping-Pong,优化内存
RenderTarget->SizeX = Size;
RenderTarget->SizeY = Size;
RenderTarget->bAutoGenerateMips = false;
RenderTarget->AddressX = TA_Clamp;
RenderTarget->AddressY = TA_Clamp;
FLinearColor ClearColor = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
RenderTarget->ClearColor = ClearColor;
// 立即创建RHI资源
RenderTarget->UpdateResource();
// 调用 Kismet Rendering Library 的清除函数
UKismetRenderingLibrary::ClearRenderTarget2D(
this->GetWorld(), // 通常传入你的 World 或 Actor
RenderTarget,
ClearColor
);
//FlushRenderingCommands();
//RenderTarget->UpdateResourceImmediate(true);
}
return RenderTarget;
}
void AIronBlock::InitializePositionTexture()
{
// --- 关键修复: 创建两个 RenderTarget ---
PositionRenderTarget0 = CreateDeformRT(TEXT("PositionRT0"), TexSize);
PositionRenderTarget1 = CreateDeformRT(TEXT("PositionRT1"), TexSize);
// 设置变形材质
SetupDeformationMaterial(nullptr);
UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
}
void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
{
// 创建动态材质实例
if (StaticMeshComp)
{
if (!DeformBaseMat)
{
DeformBaseMat = LoadObject<UMaterial>(nullptr, TEXT("/Game/Res/Materials/M_Iron"));
}
if (!DeformBaseMat)
{
DeformBaseMat = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
}
if (!DeformCalMat)
{
DeformCalMat = LoadObject<UMaterial>(nullptr, TEXT("/Game/Res/Materials/M_HitCal"));
}
if (!DeformCalMat)
{
DeformCalMat = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
}
if (DeformBaseMat && DeformCalMat)
{
DynMaterial = UMaterialInstanceDynamic::Create(DeformBaseMat, this);
DynCalMaterial = UMaterialInstanceDynamic::Create(DeformCalMat, this);
StaticMeshComp->SetMaterial(0, DynMaterial);
// 设置初始参数
if (DynMaterial)
{
// 初始时读取 RT0
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionRenderTarget0);
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to load base material for iron block"));
}
}
}
void AIronBlock::OnHammerHit(const FHitResult& HitResult)
{
// 获取锤子冲击力
FVector2D HitUV;
UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
FVector ImpactNormal = -HitResult.ImpactNormal;
float DeformationRadius = ImpactAffectRange/TexSize;
UTextureRenderTarget2D* LastTex = nullptr;
UTextureRenderTarget2D* CurTex = nullptr;
if(CurrentTextureIndex == 0)
{
LastTex = PositionRenderTarget0;
CurTex = PositionRenderTarget1;
}
else
{
LastTex = PositionRenderTarget1;
CurTex = PositionRenderTarget0;
}
if(DynCalMaterial)
{
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactUV"), FLinearColor(HitUV.X,HitUV.Y,0,0));
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactForce"),ImpactForce);
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactRadius"), DeformationRadius);
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactNormal"),ImpactNormal);
DynCalMaterial->SetTextureParameterValue(TEXT("LastPosition"),LastTex);
UKismetRenderingLibrary::DrawMaterialToRenderTarget(this->GetWorld(),CurTex,DynCalMaterial);
}
if(DynMaterial)
{
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"),CurTex);
CurrentTextureIndex = 1 - CurrentTextureIndex;
}
}
// Called every frame
void AIronBlock::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}