// 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(TEXT("Root")); StaticMeshComp = CreateDefaultSubobject(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(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(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(nullptr, TEXT("/Game/Res/Materials/M_Iron")); } if (!DeformBaseMat) { DeformBaseMat = LoadObject(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial")); } if (!DeformCalMat) { DeformCalMat = LoadObject(nullptr, TEXT("/Game/Res/Materials/M_HitCal")); } if (!DeformCalMat) { DeformCalMat = LoadObject(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); }