修复UAV贴图创建
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"components": [
|
"components": [
|
||||||
"Component.Unreal.Debugger",
|
|
||||||
"Component.Unreal.Ide",
|
|
||||||
"Microsoft.Net.Component.4.6.2.TargetingPack",
|
"Microsoft.Net.Component.4.6.2.TargetingPack",
|
||||||
|
"Microsoft.VisualStudio.Component.Unreal.Workspace",
|
||||||
"Microsoft.VisualStudio.Component.VC.14.38.17.8.ATL",
|
"Microsoft.VisualStudio.Component.VC.14.38.17.8.ATL",
|
||||||
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64",
|
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64",
|
||||||
"Microsoft.VisualStudio.Component.VC.Llvm.Clang",
|
|
||||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||||
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
|
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
|
||||||
"Microsoft.VisualStudio.Workload.CoreEditor",
|
"Microsoft.VisualStudio.Workload.CoreEditor",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"FileVersion": 3,
|
"FileVersion": 3,
|
||||||
"EngineAssociation": "{DE41D031-4C3F-817F-365A-5AAD9A1CE2AD}",
|
"EngineAssociation": "5.5",
|
||||||
"Category": "",
|
"Category": "",
|
||||||
"Description": "",
|
"Description": "",
|
||||||
"Modules": [
|
"Modules": [
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
+371
-546
@@ -3,611 +3,436 @@
|
|||||||
|
|
||||||
#include "IronBlock.h"
|
#include "IronBlock.h"
|
||||||
|
|
||||||
#include "FDeformComputeShader.h"
|
#include "FDeformComputeShader.h" // 确保这个头文件存在且包含了 FDeformationCSDispatchParams
|
||||||
#include "StaticMeshResources.h"
|
#include "StaticMeshResources.h"
|
||||||
#include "TextureResource.h"
|
#include "TextureResource.h"
|
||||||
#include "Engine/TextureRenderTarget2D.h"
|
#include "Engine/TextureRenderTarget2D.h"
|
||||||
#include "Engine/Texture.h"
|
|
||||||
#include "Engine/StaticMesh.h"
|
#include "Engine/StaticMesh.h"
|
||||||
#include "Engine/Texture2D.h"
|
#include "Engine/Texture2D.h"
|
||||||
#include "Materials/MaterialInstanceDynamic.h"
|
#include "Materials/MaterialInstanceDynamic.h"
|
||||||
#include "PhysicsEngine/BodySetup.h"
|
#include "PhysicsEngine/BodySetup.h"
|
||||||
|
#include "RHICommandList.h"
|
||||||
|
#include "RenderGraphBuilder.h" // 包含 FRDGBuilder
|
||||||
|
#include "Engine/Texture.h"
|
||||||
|
#include "GenericPlatform/GenericPlatformProcess.h"
|
||||||
|
|
||||||
|
|
||||||
// Sets default values
|
// Sets default values
|
||||||
AIronBlock::AIronBlock(): StaticMeshComp(nullptr), PositionTexture0(nullptr), PositionTexture1(nullptr),
|
AIronBlock::AIronBlock() : StaticMeshComp(nullptr),
|
||||||
PositionRenderTarget(nullptr),
|
PositionRenderTarget0(nullptr), PositionRenderTarget1(nullptr),
|
||||||
DynMaterial(nullptr),
|
DynMaterial(nullptr),
|
||||||
CurrentImpactPoint(),
|
CurrentImpactPoint(),
|
||||||
CurrentImpactNormal()
|
CurrentImpactNormal()
|
||||||
{
|
{
|
||||||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
// 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;
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
|
||||||
|
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
|
||||||
|
RootComponent = StaticMeshComp;
|
||||||
|
// 设置默认网格(立方体)
|
||||||
|
UStaticMesh* DefaultMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/BasicShapes/Cube"));
|
||||||
|
if (DefaultMesh)
|
||||||
|
{
|
||||||
|
StaticMeshComp->SetStaticMesh(DefaultMesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the game starts or when spawned
|
// Called when the game starts or when spawned
|
||||||
void AIronBlock::BeginPlay()
|
void AIronBlock::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
//CalculateLocalBounds();
|
InitializePositionTexture();
|
||||||
InitializePositionTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
UTexture2D* AIronBlock::CreatePositionTexture(const FString& TexName, int32 Size, const TArray<FLinearColor>& InitialData)
|
|
||||||
{
|
|
||||||
// 创建纹理对象
|
|
||||||
UTexture2D* NewTexture = NewObject<UTexture2D>(
|
|
||||||
this,
|
|
||||||
FName(*TexName),
|
|
||||||
RF_Transient
|
|
||||||
);
|
|
||||||
|
|
||||||
// 设置基本属性
|
|
||||||
//NewTexture->Filter = TF_Nearest;
|
|
||||||
NewTexture->SRGB = false;
|
|
||||||
NewTexture->bNoTiling = true;
|
|
||||||
NewTexture->AddressX = TA_Clamp;
|
|
||||||
NewTexture->AddressY = TA_Clamp;
|
|
||||||
//NewTexture->CompressionSettings = TC_HDR;
|
|
||||||
//NewTexture->MipGenSettings = TMGS_NoMipmaps;
|
|
||||||
//NewTexture->NeverStream = true;
|
|
||||||
//NewTexture->LODGroup = TEXTUREGROUP_RenderTarget; // 关键:标记为渲染目标组
|
|
||||||
|
|
||||||
// 设置纹理尺寸和格式
|
|
||||||
// NewTexture->SetPlatformData(new FTexturePlatformData());
|
|
||||||
// NewTexture->GetPlatformData()->SizeX = Size;
|
|
||||||
// NewTexture->GetPlatformData()->SizeY = Size;
|
|
||||||
// // 使用兼容格式
|
|
||||||
// EPixelFormat SafeFormat = PF_A32B32G32R32F;
|
|
||||||
// NewTexture->GetPlatformData()->PixelFormat = SafeFormat;
|
|
||||||
|
|
||||||
NewTexture->SetPlatformData(new FTexturePlatformData());
|
|
||||||
NewTexture->GetPlatformData()->SizeX = Size;
|
|
||||||
NewTexture->GetPlatformData()->SizeY = Size;
|
|
||||||
NewTexture->GetPlatformData()->PixelFormat = PF_R32_FLOAT;
|
|
||||||
|
|
||||||
// 添加初始Mip
|
|
||||||
FTexture2DMipMap* Mip = new FTexture2DMipMap();
|
|
||||||
//NewTexture->GetPlatformData()->Mips.Reset();
|
|
||||||
Mip->SizeX = Size;
|
|
||||||
Mip->SizeY = Size;
|
|
||||||
const int32 DataSize = Size * Size * sizeof(FLinearColor);
|
|
||||||
Mip->BulkData.Lock(LOCK_READ_WRITE);
|
|
||||||
Mip->BulkData.Realloc(DataSize);
|
|
||||||
Mip->BulkData.Unlock();
|
|
||||||
NewTexture->GetPlatformData()->Mips.Add(Mip);
|
|
||||||
// // 如果有初始数据,填充纹理
|
|
||||||
// if (InitialData.Num() >= Size * Size)
|
|
||||||
// {
|
|
||||||
// const int32 DataSize = Size * Size * sizeof(FLinearColor);
|
|
||||||
// Mip->BulkData.Lock(LOCK_READ_WRITE);
|
|
||||||
// FMemory::Memcpy(Mip->BulkData.Realloc(DataSize), InitialData.GetData(), DataSize);
|
|
||||||
// Mip->BulkData.Unlock();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// UE_LOG(LogTemp, Warning, TEXT("Initial data size mismatch for texture %s"), *TexName);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 标记需要更新资源
|
|
||||||
NewTexture->UpdateResource();
|
|
||||||
//ETextureDimension Dimension = NewTexture->GetResource()->GetTextureRHI()->GetDesc().Dimension;
|
|
||||||
return NewTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIronBlock::OnEndFrameInitializeTextures()
|
|
||||||
{
|
|
||||||
// 确保纹理资源已创建
|
|
||||||
if (PositionTexture0 && PositionTexture0->GetResource() &&
|
|
||||||
PositionTexture1 && PositionTexture1->GetResource()
|
|
||||||
/*&& PositionRenderTarget && PositionRenderTarget->GetResource()*/)
|
|
||||||
{
|
|
||||||
// 等待资源提交完成
|
|
||||||
FRenderCommandFence Fence;
|
|
||||||
Fence.BeginFence();
|
|
||||||
Fence.Wait();
|
|
||||||
// 初始化纹理对
|
|
||||||
InitializeTexturePair(0);
|
|
||||||
InitializeTexturePair(1);
|
|
||||||
//CreateSafeUAV(PositionRenderTarget);
|
|
||||||
// 移除委托
|
|
||||||
FCoreDelegates::OnEndFrame.Remove(TextureInitHandle);
|
|
||||||
TextureInitHandle.Reset();
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AIronBlock::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
void AIronBlock::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||||
{
|
{
|
||||||
// 清理资源
|
// RenderTargets 会被 UPROPERTY 自动 GC,无需手动释放 RHI 资源
|
||||||
if (TextureInitHandle.IsValid())
|
|
||||||
{
|
Super::EndPlay(EndPlayReason);
|
||||||
FCoreDelegates::OnEndFrame.Remove(TextureInitHandle);
|
|
||||||
TextureInitHandle.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 释放 RHI 资源
|
|
||||||
ENQUEUE_RENDER_COMMAND(ReleaseResources)(
|
|
||||||
[this](FRHICommandListImmediate& RHICmdList)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
TexturePairs->ReleaseRHI();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Super::EndPlay(EndPlayReason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void CreateTexture()
|
// 安全的渲染目标获取
|
||||||
// {
|
FTextureRHIRef AIronBlock::GetRenderTargetRHI(UTextureRenderTarget2D* RT)
|
||||||
// const int32 RequestedMipIdx = 0;
|
|
||||||
// const FTexture2DMipMap* RequestedMip = GetPlatformMip(RequestedMipIdx);
|
|
||||||
//
|
|
||||||
// // create texture with ResourceMem data when available
|
|
||||||
// const FRHITextureCreateDesc Desc =
|
|
||||||
// FRHITextureCreateDesc::Create2D(TEXT("FTexture2DResource"), RequestedMip->SizeX, RequestedMip->SizeY, PixelFormat)
|
|
||||||
// .SetNumMips(1)
|
|
||||||
// .SetFlags(CreationFlags)
|
|
||||||
// .SetExtData(PlatformData->GetExtData())
|
|
||||||
// .SetBulkData(ResourceMem)
|
|
||||||
// .SetClassName(Texture2DResourceName)
|
|
||||||
// .SetOwnerName(GetOwnerName());
|
|
||||||
//
|
|
||||||
// TextureRHI = RHICreateTexture(Desc);
|
|
||||||
//
|
|
||||||
// // if( ResourceMem && !State.bReadyForStreaming) // To investigate!
|
|
||||||
// if (ResourceMem)
|
|
||||||
// {
|
|
||||||
// // when using resource memory the RHI texture has already been initialized with data and won't need to have mips copied
|
|
||||||
// check(State.NumRequestedLODs == ResourceMem->GetNumMips());
|
|
||||||
// check(RequestedMip->SizeX == ResourceMem->GetSizeX() && RequestedMip->SizeY == ResourceMem->GetSizeY());
|
|
||||||
// for( int32 MipIndex=0; MipIndex < MipData.Num(); MipIndex++ )
|
|
||||||
// {
|
|
||||||
// MipData[MipIndex] = nullptr;
|
|
||||||
// MipDataSize[MipIndex] = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // Read the resident mip-levels into the RHI texture.
|
|
||||||
// for (int32 RHIMipIdx = 0; RHIMipIdx < State.NumRequestedLODs; ++RHIMipIdx)
|
|
||||||
// {
|
|
||||||
// const int32 ResourceMipIdx = RHIMipIdx + RequestedMipIdx;
|
|
||||||
// if (MipData[ResourceMipIdx])
|
|
||||||
// {
|
|
||||||
// uint32 DestPitch = -1;
|
|
||||||
// uint64 Size = ~0ULL;
|
|
||||||
// void* TheMipData = RHILockTexture2D(TextureRHI, RHIMipIdx, RLM_WriteOnly, DestPitch, false /* bLockWithinMiptail */, true /* bFlushRHIThread */, &Size);
|
|
||||||
// //check(Size != ~0ULL);
|
|
||||||
//
|
|
||||||
// GetData( ResourceMipIdx, TheMipData, DestPitch, Size );
|
|
||||||
// RHIUnlockTexture2D(TextureRHI, RHIMipIdx, false );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
void AIronBlock::InitializeTexturePair(int32 Index)
|
|
||||||
{
|
{
|
||||||
if (Index < 0 || Index > 1) return;
|
if (!RT || !RT->GetResource()) return nullptr;
|
||||||
|
return RT->GetResource()->TextureRHI;
|
||||||
UTexture2D* Texture = (Index == 0) ? PositionTexture0 : PositionTexture1;
|
|
||||||
if (!Texture || !Texture->GetResource()) return;
|
|
||||||
|
|
||||||
// 获取纹理引用
|
|
||||||
FTextureRHIRef RHITexture = Texture->GetResource()->TextureRHI;
|
|
||||||
if (!RHITexture.IsValid()) return;
|
|
||||||
TexturePairs[Index].RHITexture = RHITexture;
|
|
||||||
// 在渲染线程创建 UAV
|
|
||||||
ENQUEUE_RENDER_COMMAND(CreateTextureUAV)(
|
|
||||||
[this, Index](FRHICommandListImmediate& RHICmdList)
|
|
||||||
{
|
|
||||||
// 创建UAV描述
|
|
||||||
FRHITextureDesc Desc = TexturePairs[Index].RHITexture->GetDesc();
|
|
||||||
ensure(Desc.Flags & TexCreate_UAV); // 必须包含UAV标志
|
|
||||||
ensure(Desc.Format == PF_R32_FLOAT); // 匹配格式
|
|
||||||
|
|
||||||
// FRHIViewDesc::FUnorderedAccessView UAVDesc(FRHIViewDesc::FTextureUAV()
|
|
||||||
// .SetTexture2D(TextureRHI)
|
|
||||||
// .SetFormat(Desc.Format)
|
|
||||||
// );
|
|
||||||
//FUnorderedAccessViewRHIRef UAV = RHICreateUnorderedAccessView(TextureRHI, UAVDesc);
|
|
||||||
|
|
||||||
FRHIViewDesc::FTextureUAV::FInitializer ViewDesc = FRHIViewDesc::CreateTextureUAV();
|
|
||||||
ViewDesc.SetFormat(Desc.Format);
|
|
||||||
ViewDesc.SetDimensionFromTexture(TexturePairs[Index].RHITexture);
|
|
||||||
// ViewDesc.SetDimension(ETextureDimension::Texture2D);
|
|
||||||
// ViewDesc.SetPlane(ERHITexturePlane::Primary);
|
|
||||||
// ViewDesc.SetMipLevel(0);
|
|
||||||
// ViewDesc.SetArrayRange(0,1);
|
|
||||||
// 使用RDG安全创建
|
|
||||||
// FRDGBuilder GraphBuilder(RHICmdList);
|
|
||||||
// FRDGTextureRef RDGTexture = GraphBuilder.RegisterExternalTexture(CreateRenderTarget(TexturePairs[Index].RHITexture, TEXT("PositionTexture")));
|
|
||||||
// FRDGTextureUAVDesc UAVDesc(RDGTexture);
|
|
||||||
|
|
||||||
// TexturePairs[Index].UAV = GraphBuilder.CreateUAV(UAVDesc);
|
|
||||||
|
|
||||||
// 立即执行
|
|
||||||
// GraphBuilder.Execute();
|
|
||||||
|
|
||||||
//ViewDesc.SetDimensionFromTexture(TexturePairs[Index].RHITexture);
|
|
||||||
TexturePairs[Index].UAV = RHICmdList.CreateUnorderedAccessView(TexturePairs[Index].RHITexture,ViewDesc);
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Log, TEXT("Created UAV for texture %d"), Index);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions)
|
void AIronBlock::GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions)
|
||||||
{
|
{
|
||||||
OutPositions.Empty();
|
OutPositions.Empty();
|
||||||
|
|
||||||
if (!StaticMeshComp || !StaticMeshComp->GetStaticMesh())
|
if (!StaticMeshComp || !StaticMeshComp->GetStaticMesh())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 获取静态网格资源
|
// 获取静态网格资源
|
||||||
UStaticMesh* StaticMesh = StaticMeshComp->GetStaticMesh();
|
UStaticMesh* StaticMesh = StaticMeshComp->GetStaticMesh();
|
||||||
if (StaticMesh->GetRenderData() && StaticMesh->GetRenderData()->LODResources.Num() > 0)
|
// 确保有有效的 RenderData 和 LOD
|
||||||
{
|
if (StaticMesh->GetRenderData() && StaticMesh->GetRenderData()->LODResources.Num() > 0)
|
||||||
// 获取LOD0的顶点数据
|
{
|
||||||
FStaticMeshLODResources& LOD = StaticMesh->GetRenderData()->LODResources[0];
|
// 获取LOD0的顶点数据
|
||||||
const FPositionVertexBuffer& VertexBuffer = LOD.VertexBuffers.PositionVertexBuffer;
|
FStaticMeshLODResources& LOD = StaticMesh->GetRenderData()->LODResources[0];
|
||||||
|
const FPositionVertexBuffer& VertexBuffer = LOD.VertexBuffers.PositionVertexBuffer;
|
||||||
const int32 VertexCount = VertexBuffer.GetNumVertices();
|
|
||||||
OutPositions.SetNum(VertexCount);
|
const int32 VertexCount = VertexBuffer.GetNumVertices();
|
||||||
|
OutPositions.SetNum(VertexCount);
|
||||||
for (int32 i = 0; i < VertexCount; i++)
|
|
||||||
{
|
for (int32 i = 0; i < VertexCount; i++)
|
||||||
OutPositions[i] = VertexBuffer.VertexPosition(i);
|
{
|
||||||
}
|
OutPositions[i] = VertexBuffer.VertexPosition(i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心修复:创建一个配置好用于变形计算的 RenderTarget
|
||||||
|
*/
|
||||||
|
UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32 Size)
|
||||||
|
{
|
||||||
|
UTextureRenderTarget2D* RenderTarget = NewObject<UTextureRenderTarget2D>(this, FName(*RTName));
|
||||||
|
if (RenderTarget)
|
||||||
|
{
|
||||||
|
// **关键修复 1:** 设置为32位浮点数格式,以匹配 FLinearColor 和 CS 的 PF_A32B32G32R32F
|
||||||
|
RenderTarget->RenderTargetFormat = RTF_RGBA32f;
|
||||||
|
|
||||||
|
// **关键修复 2:** 明确告诉引擎我们需要为这个纹理创建UAV
|
||||||
|
RenderTarget->bCanCreateUAV = true;
|
||||||
|
|
||||||
|
RenderTarget->bNeedsTwoCopies = true; // 告知引擎这个纹理会被用于Ping-Pong,优化内存
|
||||||
|
RenderTarget->SizeX = Size;
|
||||||
|
RenderTarget->SizeY = Size;
|
||||||
|
RenderTarget->bAutoGenerateMips = false;
|
||||||
|
RenderTarget->AddressX = TA_Clamp;
|
||||||
|
RenderTarget->AddressY = TA_Clamp;
|
||||||
|
|
||||||
|
// 立即创建RHI资源
|
||||||
|
RenderTarget->UpdateResource();
|
||||||
|
}
|
||||||
|
return RenderTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AIronBlock::InitializePositionTexture()
|
void AIronBlock::InitializePositionTexture()
|
||||||
{
|
{
|
||||||
// 创建静态网格组件
|
CalculateLocalBounds();
|
||||||
if (!StaticMeshComp)
|
|
||||||
{
|
|
||||||
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
|
|
||||||
RootComponent = StaticMeshComp;
|
|
||||||
|
|
||||||
// 设置默认网格(立方体)
|
|
||||||
UStaticMesh* DefaultMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/BasicShapes/Cube"));
|
|
||||||
if (DefaultMesh)
|
|
||||||
{
|
|
||||||
StaticMeshComp->SetStaticMesh(DefaultMesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算本地边界
|
|
||||||
CalculateLocalBounds();
|
|
||||||
|
|
||||||
// 获取顶点位置
|
|
||||||
TArray<FVector3f> VertexPositions;
|
|
||||||
GetStaticMeshVertexPositions(VertexPositions);
|
|
||||||
|
|
||||||
// 创建位置纹理
|
|
||||||
const int32 TextureSize = 256; // 纹理尺寸
|
|
||||||
TArray<FLinearColor> InitialData;
|
|
||||||
InitialData.SetNum(TextureSize * TextureSize);
|
|
||||||
|
|
||||||
// 初始化纹理数据
|
|
||||||
for (int32 Y = 0; Y < TextureSize; ++Y)
|
|
||||||
{
|
|
||||||
for (int32 X = 0; X < TextureSize; ++X)
|
|
||||||
{
|
|
||||||
int32 Index = Y * TextureSize + X;
|
|
||||||
FVector2D UV(FVector2D(X, Y) / (TextureSize - 1));
|
|
||||||
|
|
||||||
// 将UV坐标转换为本地空间位置
|
|
||||||
FVector LocalPos(
|
|
||||||
FMath::Lerp(LocalBounds.Min.X, LocalBounds.Max.X, UV.X),
|
|
||||||
FMath::Lerp(LocalBounds.Min.Y, LocalBounds.Max.Y, UV.Y),
|
|
||||||
LocalBounds.Min.Z
|
|
||||||
);
|
|
||||||
|
|
||||||
InitialData[Index] = FLinearColor(LocalPos.X, LocalPos.Y, LocalPos.Z, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建纹理对
|
|
||||||
PositionTexture0 = CreatePositionTexture(TEXT("PositionTexture0"), TextureSize, InitialData);
|
|
||||||
PositionTexture1 = CreatePositionTexture(TEXT("PositionTexture1"), TextureSize, InitialData);
|
|
||||||
|
|
||||||
// 创建渲染目标
|
|
||||||
PositionRenderTarget = NewObject<UTextureRenderTarget2D>(this);
|
|
||||||
PositionRenderTarget->SizeX = TextureSize;
|
|
||||||
PositionRenderTarget->SizeY = TextureSize;
|
|
||||||
PositionRenderTarget->RenderTargetFormat = RTF_RGBA16f;
|
|
||||||
PositionRenderTarget->bAutoGenerateMips = false;
|
|
||||||
PositionRenderTarget->UpdateResource();
|
|
||||||
|
|
||||||
// 设置变形材质
|
|
||||||
SetupDeformationMaterial();
|
|
||||||
|
|
||||||
// 初始化纹理对
|
|
||||||
InitializeTexturePair(0);
|
|
||||||
InitializeTexturePair(1);
|
|
||||||
|
|
||||||
// 延迟初始化纹理资源
|
|
||||||
TextureInitHandle = FDelegateHandle();
|
|
||||||
GetWorld()->GetTimerManager().SetTimerForNextTick([this]()
|
|
||||||
{
|
|
||||||
OnEndFrameInitializeTextures();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建UAV的安全方法
|
// 获取顶点位置 (用于计算初始UV->WorldPos)
|
||||||
FUnorderedAccessViewRHIRef AIronBlock::CreateSafeUAV(UTextureRenderTarget2D* RenderTarget)
|
TArray<FVector3f> VertexPositions;
|
||||||
{
|
GetStaticMeshVertexPositions(VertexPositions);
|
||||||
if (!RenderTarget || !RenderTarget->GetResource())
|
|
||||||
return nullptr;
|
// 创建位置纹理
|
||||||
|
const int32 TextureSize = 256; // 纹理尺寸
|
||||||
FTextureRHIRef TextureRHI = RenderTarget->GetResource()->GetTexture2DRHI();
|
TArray<FLinearColor> InitialData;
|
||||||
if (!TextureRHI.IsValid())
|
InitialData.SetNum(TextureSize * TextureSize);
|
||||||
return nullptr;
|
|
||||||
|
// 初始化纹理数据 (将UV映射到本地包围盒的XY平面)
|
||||||
// 创建UAV描述
|
for (int32 Y = 0; Y < TextureSize; ++Y)
|
||||||
FUnorderedAccessViewRHIRef UAV;
|
{
|
||||||
ENQUEUE_RENDER_COMMAND(CreateUAVCommand)(
|
for (int32 X = 0; X < TextureSize; ++X)
|
||||||
[TextureRHI, &UAV](FRHICommandListImmediate& RHICmdList)
|
{
|
||||||
{
|
int32 Index = Y * TextureSize + X;
|
||||||
FRHIViewDesc::FTextureUAV::FInitializer ViewDesc = FRHIViewDesc::CreateTextureUAV();
|
FVector2D UV(FVector2D(X, Y) / (TextureSize - 1.0f)); // 使用 255.0 或 (Size-1)
|
||||||
ViewDesc.SetMipLevel(0);
|
|
||||||
ViewDesc.SetPlane(ERHITexturePlane::Primary);
|
// 将UV坐标转换为本地空间位置 (XY平面)
|
||||||
ViewDesc.SetFormat(PF_A32B32G32R32F);
|
FVector LocalPos(
|
||||||
|
FMath::Lerp(LocalBounds.Min.X, LocalBounds.Max.X, UV.X),
|
||||||
UAV = RHICmdList.CreateUnorderedAccessView(TextureRHI, ViewDesc);
|
FMath::Lerp(LocalBounds.Min.Y, LocalBounds.Max.Y, UV.Y),
|
||||||
}
|
LocalBounds.Min.Z // 假设初始是一个平面
|
||||||
);
|
);
|
||||||
|
|
||||||
// 等待渲染命令完成
|
InitialData[Index] = FLinearColor(LocalPos.X, LocalPos.Y, LocalPos.Z, 1.0f);
|
||||||
FlushRenderingCommands();
|
}
|
||||||
|
}
|
||||||
return UAV;
|
|
||||||
|
// --- 关键修复: 创建两个 RenderTarget ---
|
||||||
|
PositionRenderTarget0 = CreateDeformRT(TEXT("PositionRT0"), TextureSize);
|
||||||
|
PositionRenderTarget1 = CreateDeformRT(TEXT("PositionRT1"), TextureSize);
|
||||||
|
|
||||||
|
// --- 将初始数据写入GPU ---
|
||||||
|
// 我们需要将CPU端的 InitialData 写入到GPU纹理中
|
||||||
|
// 最简单的方法是创建一个临时的UTexture2D,用BulkData上传,然后拷贝到RT
|
||||||
|
|
||||||
|
UTexture2D* TempTexture = UTexture2D::CreateTransient(TextureSize, TextureSize, PF_A32B32G32R32F); // 必须匹配格式
|
||||||
|
if (TempTexture && PositionRenderTarget0 && PositionRenderTarget1)
|
||||||
|
{
|
||||||
|
// 锁定 Mip 并拷贝数据
|
||||||
|
FTexture2DMipMap& Mip = TempTexture->GetPlatformData()->Mips[0];
|
||||||
|
void* MipData = Mip.BulkData.Lock(LOCK_READ_WRITE);
|
||||||
|
FMemory::Memcpy(MipData, InitialData.GetData(), InitialData.Num() * sizeof(FLinearColor));
|
||||||
|
Mip.BulkData.Unlock();
|
||||||
|
TempTexture->UpdateResource(); // 提交到GPU
|
||||||
|
|
||||||
|
// 获取RHI资源
|
||||||
|
FTextureRHIRef DestRT0_RHI = GetRenderTargetRHI(PositionRenderTarget0);
|
||||||
|
FTextureRHIRef DestRT1_RHI = GetRenderTargetRHI(PositionRenderTarget1);
|
||||||
|
FTextureRHIRef SrcTex_RHI = TempTexture->GetResource() ? TempTexture->GetResource()->TextureRHI : nullptr;
|
||||||
|
|
||||||
|
if (DestRT0_RHI && DestRT1_RHI && SrcTex_RHI)
|
||||||
|
{
|
||||||
|
// 在渲染线程上执行拷贝
|
||||||
|
ENQUEUE_RENDER_COMMAND(InitializeDeformRTs)(
|
||||||
|
[DestRT0_RHI, DestRT1_RHI, SrcTex_RHI](FRHICommandListImmediate& RHICmdList)
|
||||||
|
{
|
||||||
|
// 将初始数据拷贝到两个RT
|
||||||
|
RHICmdList.CopyTexture(SrcTex_RHI, DestRT0_RHI, {});
|
||||||
|
RHICmdList.CopyTexture(SrcTex_RHI, DestRT1_RHI, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 确保拷贝完成
|
||||||
|
FlushRenderingCommands();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置变形材质
|
||||||
|
SetupDeformationMaterial();
|
||||||
|
UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::CalculateLocalBounds()
|
void AIronBlock::CalculateLocalBounds()
|
||||||
{
|
{
|
||||||
if (!StaticMeshComp)
|
if (!StaticMeshComp)
|
||||||
{
|
{
|
||||||
StaticMeshComp = GetComponentByClass<UStaticMeshComponent>();
|
StaticMeshComp = GetComponentByClass<UStaticMeshComponent>();
|
||||||
}
|
}
|
||||||
if (StaticMeshComp && StaticMeshComp->GetStaticMesh())
|
if (StaticMeshComp && StaticMeshComp->GetStaticMesh())
|
||||||
{
|
{
|
||||||
// 获取本地空间包围盒
|
// 获取本地空间包围盒
|
||||||
LocalBounds = StaticMeshComp->GetStaticMesh()->GetBoundingBox();
|
LocalBounds = StaticMeshComp->GetStaticMesh()->GetBoundingBox();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 智能默认值
|
// 智能默认值
|
||||||
float Extent = 50.0f;
|
float Extent = 50.0f;
|
||||||
LocalBounds = FBox(
|
LocalBounds = FBox(
|
||||||
FVector(-Extent, -Extent, 0),
|
FVector(-Extent, -Extent, 0),
|
||||||
FVector(Extent, Extent, Extent * 0.2f)
|
FVector(Extent, Extent, Extent * 0.2f)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保包围盒有效
|
// 确保包围盒有效
|
||||||
if (LocalBounds.GetVolume() <= 0)
|
if (LocalBounds.GetVolume() <= 0)
|
||||||
{
|
{
|
||||||
LocalBounds = FBox(FVector(-50, -50, 0), FVector(50, 50, 10));
|
LocalBounds = FBox(FVector(-50, -50, 0), FVector(50, 50, 10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::SetupDeformationMaterial()
|
void AIronBlock::SetupDeformationMaterial()
|
||||||
{
|
{
|
||||||
// 创建动态材质实例
|
// 创建动态材质实例
|
||||||
if (StaticMeshComp)
|
if (StaticMeshComp)
|
||||||
{
|
{
|
||||||
// 加载基础材质
|
// 加载基础材质 (请确保你的材质支持读取 PositionTexture)
|
||||||
UMaterial* BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
|
UMaterial* BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Game/YourMaterialFolder/M_DeformableIron")); // 示例路径
|
||||||
if (BaseMaterial)
|
if (!BaseMaterial)
|
||||||
{
|
{
|
||||||
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
|
BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
|
||||||
StaticMeshComp->SetMaterial(0, DynMaterial);
|
}
|
||||||
|
|
||||||
// 设置初始参数
|
if (BaseMaterial)
|
||||||
if (DynMaterial)
|
{
|
||||||
{
|
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
|
||||||
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionTexture0);
|
StaticMeshComp->SetMaterial(0, DynMaterial);
|
||||||
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
|
|
||||||
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
|
// 设置初始参数
|
||||||
DynMaterial->SetScalarParameterValue(TEXT("DeformationStrength"), 1.0f);
|
if (DynMaterial)
|
||||||
}
|
{
|
||||||
}
|
// 初始时读取 RT0
|
||||||
else
|
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionRenderTarget0);
|
||||||
{
|
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
|
||||||
UE_LOG(LogTemp, Warning, TEXT("Failed to load base material for iron block"));
|
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
|
||||||
}
|
DynMaterial->SetScalarParameterValue(TEXT("DeformationStrength"), 1.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Failed to load base material for iron block"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
||||||
{
|
{
|
||||||
// 获取锤子冲击力
|
// 获取锤子冲击力
|
||||||
float ImpactForce = 0.0f;
|
float ImpactForce = 0.0f;
|
||||||
if (HitResult.GetComponent() && HitResult.GetComponent()->GetPhysicsLinearVelocity().IsNearlyZero())
|
// 检查 HitResult.GetComponent() 是否有效
|
||||||
{
|
if (HitResult.GetComponent() && !HitResult.GetComponent()->GetPhysicsLinearVelocity().IsNearlyZero())
|
||||||
ImpactForce = HitResult.GetComponent()->GetPhysicsLinearVelocity().Size();
|
{
|
||||||
}
|
ImpactForce = HitResult.GetComponent()->GetPhysicsLinearVelocity().Size();
|
||||||
|
}
|
||||||
// 默认冲击力
|
|
||||||
if (ImpactForce < 10.0f) ImpactForce = 500.0f;
|
// 默认冲击力
|
||||||
|
if (ImpactForce < 10.0f) ImpactForce = 500.0f;
|
||||||
// 转换到本地空间
|
|
||||||
FVector ImpactPoint = HitResult.ImpactPoint;
|
// 转换到本地空间
|
||||||
FVector ImpactNormal = HitResult.ImpactNormal;
|
FVector ImpactPoint = HitResult.ImpactPoint;
|
||||||
FVector LocalImpactPoint = GetTransform().InverseTransformPosition(ImpactPoint);
|
FVector ImpactNormal = HitResult.ImpactNormal;
|
||||||
FVector LocalImpactNormal = GetTransform().InverseTransformVector(ImpactNormal);
|
FVector LocalImpactPoint = GetTransform().InverseTransformPosition(ImpactPoint);
|
||||||
|
FVector LocalImpactNormal = GetTransform().InverseTransformVector(ImpactNormal);
|
||||||
UpdateComputeShaderParams(LocalImpactPoint, LocalImpactNormal, ImpactForce);
|
|
||||||
|
UpdateComputeShaderParams(LocalImpactPoint, LocalImpactNormal, ImpactForce);
|
||||||
ExecuteDeformationCS();
|
|
||||||
|
ExecuteDeformationCS();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安全的纹理资源获取
|
|
||||||
FTextureRHIRef AIronBlock::GetTextureRHI(UTexture2D* Texture)
|
|
||||||
{
|
|
||||||
return Texture && Texture->GetResource() ? Texture->GetResource()->TextureRHI : nullptr;
|
|
||||||
}
|
|
||||||
// 安全的渲染目标获取
|
|
||||||
FTextureRHIRef AIronBlock::GetRenderTargetRHI(UTextureRenderTarget2D* RT)
|
|
||||||
{
|
|
||||||
if (!RT || !RT->GetResource()) return nullptr;
|
|
||||||
return RT->GetResource()->TextureRHI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce)
|
void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce)
|
||||||
{
|
{
|
||||||
// 更新碰撞参数
|
// 更新碰撞参数
|
||||||
CurrentImpactPoint = LocalImpactPoint;
|
CurrentImpactPoint = LocalImpactPoint;
|
||||||
CurrentImpactNormal = LocalImpactNormal.GetSafeNormal();
|
CurrentImpactNormal = LocalImpactNormal.GetSafeNormal();
|
||||||
CurrentImpactForce = FMath::Clamp(ImpactForce, 0.0f, 5000.0f);
|
CurrentImpactForce = FMath::Clamp(ImpactForce, 0.0f, 5000.0f);
|
||||||
|
|
||||||
// 根据冲击力计算动态变形半径
|
// 根据冲击力计算动态变形半径
|
||||||
CurrentDeformationRadius = FMath::Lerp(5.0f, 30.0f, CurrentImpactForce / 2000.0f);
|
CurrentDeformationRadius = FMath::Lerp(5.0f, 30.0f, CurrentImpactForce / 2000.0f);
|
||||||
|
|
||||||
// 根据材质类型调整塑性系数
|
// 根据材质类型调整塑性系数 (示例)
|
||||||
UMaterialInterface* Material = StaticMeshComp->GetMaterial(0);
|
UMaterialInterface* Material = StaticMeshComp->GetMaterial(0);
|
||||||
if(Material && Material->GetName().Contains("Steel"))
|
if (Material && Material->GetName().Contains("Steel"))
|
||||||
{
|
{
|
||||||
CurrentPlasticity = 0.4f; // 钢材塑性较低
|
CurrentPlasticity = 0.4f; // 钢材塑性较低
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentPlasticity = 0.8f; // 默认高塑性
|
CurrentPlasticity = 0.8f; // 默认高塑性
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换纹理缓冲
|
// 切换纹理缓冲索引
|
||||||
CurrentTextureIndex = 1 - CurrentTextureIndex;
|
CurrentTextureIndex = 1 - CurrentTextureIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::ExecuteDeformationCS()
|
void AIronBlock::ExecuteDeformationCS()
|
||||||
{
|
{
|
||||||
// 确保纹理资源有效
|
// 确保纹理资源有效
|
||||||
if (!PositionTexture0 || !PositionTexture0->GetResource() ||
|
if (!PositionRenderTarget0 || !PositionRenderTarget0->GetResource() ||
|
||||||
!PositionTexture1 || !PositionTexture1->GetResource())
|
!PositionRenderTarget1 || !PositionRenderTarget1->GetResource())
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Error, TEXT("Position textures not initialized!"));
|
UE_LOG(LogTemp, Error, TEXT("Position render targets not initialized!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前纹理资源
|
|
||||||
UTexture2D* CurrentTex = (CurrentTextureIndex == 0) ? PositionTexture0 : PositionTexture1;
|
|
||||||
UTexture2D* PrevTex = (CurrentTextureIndex == 0) ? PositionTexture1 : PositionTexture0;
|
|
||||||
|
|
||||||
// 获取纹理RHI资源
|
|
||||||
FTextureRHIRef InputRHI = GetTextureRHI(PrevTex);
|
|
||||||
FTextureRHIRef OutputRHI = GetRenderTargetRHI(PositionRenderTarget);
|
|
||||||
|
|
||||||
if (!InputRHI || !OutputRHI)
|
// --- 关键修复: 决定哪个是读取RT,哪个是写入RT ---
|
||||||
{
|
UTextureRenderTarget2D* ReadTarget = (CurrentTextureIndex == 0) ? PositionRenderTarget0 : PositionRenderTarget1;
|
||||||
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!"));
|
UTextureRenderTarget2D* WriteTarget = (CurrentTextureIndex == 1) ? PositionRenderTarget0 : PositionRenderTarget1; // Flipped
|
||||||
return;
|
|
||||||
}
|
// --- 关键修复: 直接获取 RT 的 RHI 和 UAV ---
|
||||||
|
FTextureRHIRef InputRHI = GetRenderTargetRHI(ReadTarget);
|
||||||
// 计算纹理UV坐标
|
// 从 WriteTarget 获取 UAV。因为我们创建时设置了 bCanCreateUAV=true,所以这个UAV是有效的。
|
||||||
const int32 TexSize = PositionRenderTarget->SizeX;
|
FUnorderedAccessViewRHIRef OutputUAV = nullptr;
|
||||||
FVector2D ImpactUV(
|
if (WriteTarget && WriteTarget->GetResource())
|
||||||
(CurrentImpactPoint.X - LocalBounds.Min.X) / LocalBounds.GetSize().X,
|
{
|
||||||
(CurrentImpactPoint.Y - LocalBounds.Min.Y) / LocalBounds.GetSize().Y
|
FTextureResource* RTResource = WriteTarget->GetResource();
|
||||||
);
|
FTextureRenderTargetResource* WriteRTResource = static_cast<FTextureRenderTargetResource*>(RTResource);
|
||||||
|
if (WriteRTResource)
|
||||||
// 计算更新区域 (只更新受影响部分)
|
{
|
||||||
const float RadiusRatio = CurrentDeformationRadius / LocalBounds.GetExtent().GetMax();
|
OutputUAV = WriteRTResource->GetRenderTargetUAV();
|
||||||
FIntRect UpdateRegion;
|
}
|
||||||
UpdateRegion.Min.X = FMath::Clamp((ImpactUV.X - RadiusRatio) * TexSize, 0, TexSize);
|
}
|
||||||
UpdateRegion.Min.Y = FMath::Clamp((ImpactUV.Y - RadiusRatio) * TexSize, 0, TexSize);
|
|
||||||
UpdateRegion.Max.X = FMath::Min((ImpactUV.X + RadiusRatio) * TexSize, (float)TexSize);
|
if (!InputRHI || !OutputUAV)
|
||||||
UpdateRegion.Max.Y = FMath::Min((ImpactUV.Y + RadiusRatio) * TexSize, (float)TexSize);
|
{
|
||||||
|
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources or UAV!"));
|
||||||
// 准备参数
|
return;
|
||||||
FDeformationCSDispatchParams Params;
|
}
|
||||||
Params.ImpactPoint = CurrentImpactPoint;
|
|
||||||
Params.ImpactNormal = CurrentImpactNormal;
|
// 计算纹理UV坐标
|
||||||
Params.ImpactForce = CurrentImpactForce;
|
const int32 TexSize = ReadTarget->SizeX;
|
||||||
Params.DeformationRadius = CurrentDeformationRadius;
|
FVector2D ImpactUV(
|
||||||
Params.Plasticity = CurrentPlasticity;
|
(CurrentImpactPoint.X - LocalBounds.Min.X) / LocalBounds.GetSize().X,
|
||||||
Params.InputTexture = InputRHI;
|
(CurrentImpactPoint.Y - LocalBounds.Min.Y) / LocalBounds.GetSize().Y
|
||||||
|
);
|
||||||
// 创建UAV用于输出
|
|
||||||
FUnorderedAccessViewRHIRef OutputUAV;
|
// 计算更新区域 (只更新受影响部分)
|
||||||
ENQUEUE_RENDER_COMMAND(CreateOutputUAV)(
|
const float RadiusRatio = CurrentDeformationRadius / LocalBounds.GetExtent().GetMax();
|
||||||
[OutputRHI, &OutputUAV](FRHICommandListImmediate& RHICmdList)
|
FIntRect UpdateRegion;
|
||||||
{
|
UpdateRegion.Min.X = FMath::Clamp(FMath::FloorToInt((ImpactUV.X - RadiusRatio) * TexSize), 0, TexSize - 1);
|
||||||
FRHIViewDesc::FTextureUAV::FInitializer ViewDesc = FRHIViewDesc::CreateTextureUAV();
|
UpdateRegion.Min.Y = FMath::Clamp(FMath::FloorToInt((ImpactUV.Y - RadiusRatio) * TexSize), 0, TexSize - 1);
|
||||||
ViewDesc.SetMipLevel(0);
|
UpdateRegion.Max.X = FMath::Clamp(FMath::CeilToInt((ImpactUV.X + RadiusRatio) * TexSize), 1, TexSize);
|
||||||
ViewDesc.SetPlane(ERHITexturePlane::Primary);
|
UpdateRegion.Max.Y = FMath::Clamp(FMath::CeilToInt((ImpactUV.Y + RadiusRatio) * TexSize), 1, TexSize);
|
||||||
ViewDesc.SetFormat(PF_A32B32G32R32F);
|
|
||||||
|
// 确保 Min < Max
|
||||||
OutputUAV = RHICmdList.CreateUnorderedAccessView(OutputRHI, ViewDesc);
|
if (UpdateRegion.Min.X >= UpdateRegion.Max.X) UpdateRegion.Max.X = UpdateRegion.Min.X + 1;
|
||||||
}
|
if (UpdateRegion.Min.Y >= UpdateRegion.Max.Y) UpdateRegion.Max.Y = UpdateRegion.Min.Y + 1;
|
||||||
);
|
|
||||||
FlushRenderingCommands();
|
// 准备参数
|
||||||
Params.OutputTexture = OutputUAV;
|
FDeformationCSDispatchParams Params;
|
||||||
|
Params.ImpactPoint = CurrentImpactPoint; // 确保类型匹配 (FVector -> FVector3f)
|
||||||
Params.UpdateRegion = UpdateRegion;
|
Params.ImpactNormal = CurrentImpactNormal;
|
||||||
Params.TextureSize = FIntVector(TexSize, TexSize, 1);
|
Params.ImpactForce = CurrentImpactForce;
|
||||||
|
Params.DeformationRadius = CurrentDeformationRadius;
|
||||||
// 在渲染线程中执行Compute Shader
|
Params.Plasticity = CurrentPlasticity;
|
||||||
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS)(
|
Params.InputTexture = InputRHI;
|
||||||
[Params](FRHICommandListImmediate& RHICmdList)
|
Params.OutputTexture = OutputUAV; // **直接使用RT的UAV**
|
||||||
{
|
Params.UpdateRegion = UpdateRegion;
|
||||||
FDeformationCS::Dispatch(RHICmdList, Params);
|
Params.TextureSize = FIntVector(TexSize, TexSize, 1);
|
||||||
});
|
|
||||||
|
// 在渲染线程中执行Compute Shader
|
||||||
// 更新材质参数
|
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS)(
|
||||||
if (DynMaterial)
|
[Params](FRHICommandListImmediate& RHICmdList)
|
||||||
{
|
{
|
||||||
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), CurrentTex);
|
// 在这里调用你的 Compute Shader 调度逻辑
|
||||||
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
|
FDeformationCS::Dispatch(RHICmdList, Params);
|
||||||
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
|
});
|
||||||
}
|
|
||||||
|
// 等待渲染命令完成,以便在CPU上读取 (如果需要立即更新碰撞体)
|
||||||
|
// 注意:这是一个同步点,会影响性能。
|
||||||
|
// FlushRenderingCommands();
|
||||||
|
// UpdateCollisionAsync(UpdateRegion, WriteTarget); // 异步更新碰撞体
|
||||||
|
|
||||||
|
// --- 关键修复: 更新材质参数,使其下一帧读取我们刚刚写入的纹理 ---
|
||||||
|
if (DynMaterial)
|
||||||
|
{
|
||||||
|
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), WriteTarget);
|
||||||
|
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
|
||||||
|
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 异步更新物理碰撞体
|
|
||||||
void AIronBlock::UpdateCollisionAsync(const FIntRect& UpdateRegion)
|
// 异步更新物理碰撞体 (示例,未优化)
|
||||||
|
void AIronBlock::UpdateCollisionAsync(const FIntRect& UpdateRegion, UTextureRenderTarget2D* FromTarget)
|
||||||
{
|
{
|
||||||
if (!PositionRenderTarget || !PositionRenderTarget->GetResource())
|
// 注意:ReadPixels 是一项非常慢的操作 (GPU->CPU 同步)
|
||||||
{
|
// 更好的方法是使用另一个Compute Shader将顶点数据简化并读回到一个小的StructuredBuffer中
|
||||||
return;
|
|
||||||
}
|
if (!FromTarget || !FromTarget->GetResource())
|
||||||
// 从GPU读取关键区域数据
|
{
|
||||||
TArray<FColor> SampledData;
|
return;
|
||||||
FReadSurfaceDataFlags Flags;
|
}
|
||||||
Flags.SetLinearToGamma(false);
|
// 从GPU读取关键区域数据
|
||||||
|
TArray<FLinearColor> SampledData; // 使用 FLinearColor
|
||||||
PositionRenderTarget->GameThread_GetRenderTargetResource()->ReadPixels(
|
FReadSurfaceDataFlags Flags;
|
||||||
SampledData,
|
Flags.SetLinearToGamma(false);
|
||||||
Flags,
|
|
||||||
FIntRect(UpdateRegion.Min.X, UpdateRegion.Min.Y,
|
FRenderTarget* RTResource = FromTarget->GameThread_GetRenderTargetResource();
|
||||||
UpdateRegion.Max.X, UpdateRegion.Max.Y)
|
if (!RTResource) return;
|
||||||
);
|
|
||||||
|
RTResource->ReadLinearColorPixels(
|
||||||
// 创建临时碰撞体
|
SampledData,
|
||||||
TArray<FVector> CollisionVerts;
|
Flags,
|
||||||
for(FColor& Pixel : SampledData)
|
UpdateRegion // FIntRect
|
||||||
{
|
);
|
||||||
FVector Pos(
|
|
||||||
Pixel.R * 255.0f / 10.0f, // 根据实际范围调整
|
// 创建临时碰撞体
|
||||||
Pixel.G * 255.0f / 10.0f,
|
TArray<FVector> CollisionVerts;
|
||||||
Pixel.B * 255.0f / 10.0f
|
for (const FLinearColor& Pixel : SampledData)
|
||||||
);
|
{
|
||||||
CollisionVerts.Add(Pos);
|
// 像素数据已经是 FLinearColor (即 FVector)
|
||||||
}
|
CollisionVerts.Add(FVector(Pixel.R, Pixel.G, Pixel.B));
|
||||||
|
}
|
||||||
// 更新简单碰撞体
|
|
||||||
UBodySetup* BodySetup = StaticMeshComp->GetBodySetup();
|
if (CollisionVerts.Num() == 0) return;
|
||||||
BodySetup->AggGeom.ConvexElems[0].VertexData = CollisionVerts;
|
|
||||||
BodySetup->CreatePhysicsMeshes();
|
// 更新简单碰撞体
|
||||||
|
UBodySetup* BodySetup = StaticMeshComp->GetBodySetup();
|
||||||
|
if (BodySetup && BodySetup->AggGeom.ConvexElems.Num() > 0)
|
||||||
|
{
|
||||||
|
BodySetup->AggGeom.ConvexElems[0].VertexData = CollisionVerts;
|
||||||
|
BodySetup->CreatePhysicsMeshes(); // 重新创建物理网格体
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called every frame
|
// Called every frame
|
||||||
void AIronBlock::Tick(float DeltaTime)
|
void AIronBlock::Tick(float DeltaTime)
|
||||||
{
|
{
|
||||||
Super::Tick(DeltaTime);
|
Super::Tick(DeltaTime);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@@ -4,90 +4,92 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
// FDeformComputeShader.h 假定包含了 FDeformationCSDispatchParams 结构
|
||||||
|
#include "FDeformComputeShader.h"
|
||||||
|
|
||||||
#include "IronBlock.generated.h"
|
#include "IronBlock.generated.h"
|
||||||
|
|
||||||
|
class UTextureRenderTarget2D;
|
||||||
|
class UMaterialInstanceDynamic;
|
||||||
|
class UStaticMeshComponent;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class BLADESMITH_API AIronBlock : public AActor
|
class BLADESMITH_API AIronBlock : public AActor
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere)
|
UPROPERTY(EditAnywhere)
|
||||||
UStaticMeshComponent* StaticMeshComp;
|
UStaticMeshComponent* StaticMeshComp;
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
UTexture2D* PositionTexture0;
|
|
||||||
|
|
||||||
|
/** 用于Ping-Pong缓冲的渲染目标 A */
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
UTexture2D* PositionTexture1;
|
UTextureRenderTarget2D* PositionRenderTarget0;
|
||||||
|
|
||||||
UPROPERTY()
|
/** 用于Ping-Pong缓冲的渲染目标 B */
|
||||||
UTextureRenderTarget2D* PositionRenderTarget;
|
UPROPERTY()
|
||||||
|
UTextureRenderTarget2D* PositionRenderTarget1;
|
||||||
UPROPERTY()
|
|
||||||
UMaterialInstanceDynamic* DynMaterial;
|
/** 应用于网格的动态材质实例 */
|
||||||
public:
|
UPROPERTY()
|
||||||
|
UMaterialInstanceDynamic* DynMaterial;
|
||||||
|
|
||||||
|
public:
|
||||||
// Sets default values for this actor's properties
|
// Sets default values for this actor's properties
|
||||||
AIronBlock();
|
AIronBlock();
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void OnHammerHit(const FHitResult& HitResult);
|
void OnHammerHit(const FHitResult& HitResult);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Called when the game starts or when spawned
|
// Called when the game starts or when spawned
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||||
void InitializeTexturePair(int32 Index);
|
|
||||||
|
/** 初始化两个渲染目标和它们的初始数据 */
|
||||||
|
void InitializePositionTexture();
|
||||||
|
|
||||||
|
/** 创建一个配置好用于变形计算的 RenderTarget */
|
||||||
|
UTextureRenderTarget2D* CreateDeformRT(const FString& RTName, int32 Size);
|
||||||
|
|
||||||
|
/** 获取静态网格体的顶点位置 (用于计算初始纹理) */
|
||||||
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
|
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
|
||||||
UTexture2D* CreatePositionTexture(const FString& TexName, int32 Size, const TArray<FLinearColor>& InitialData);
|
|
||||||
void InitializePositionTexture();
|
/** 设置动态材质实例和参数 */
|
||||||
FUnorderedAccessViewRHIRef CreateSafeUAV(UTextureRenderTarget2D* RenderTarget);
|
void SetupDeformationMaterial();
|
||||||
void OnEndFrameInitializeTextures();
|
|
||||||
void SetupDeformationMaterial();
|
/** 安全地获取 RenderTarget 的 RHI 资源 */
|
||||||
FTextureRHIRef GetTextureRHI(UTexture2D* Texture);
|
|
||||||
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
|
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** 更新 Compute Shader 所需的参数 */
|
||||||
void UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce);
|
void UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce);
|
||||||
|
|
||||||
|
/** 在渲染线程上执行 Compute Shader */
|
||||||
void ExecuteDeformationCS();
|
void ExecuteDeformationCS();
|
||||||
void UpdateCollisionAsync(const FIntRect& UpdateRegion);
|
|
||||||
|
/** (可选) 异步更新物理碰撞体 */
|
||||||
|
void UpdateCollisionAsync(const FIntRect& UpdateRegion, UTextureRenderTarget2D* FromTarget);
|
||||||
|
|
||||||
|
/** 计算网格体的本地包围盒 */
|
||||||
void CalculateLocalBounds();
|
void CalculateLocalBounds();
|
||||||
|
|
||||||
// 双缓冲纹理对结构体
|
// 网格体的本地包围盒
|
||||||
struct FDeformationTexturePair
|
|
||||||
{
|
|
||||||
// 纹理资源引用
|
|
||||||
FTextureRHIRef RHITexture;
|
|
||||||
|
|
||||||
// UAV 资源引用
|
|
||||||
FUnorderedAccessViewRHIRef UAV;
|
|
||||||
//FRDGTextureUAVRef UAV;
|
|
||||||
// 安全释放资源
|
|
||||||
void ReleaseRHI()
|
|
||||||
{
|
|
||||||
UAV.SafeRelease();
|
|
||||||
//UAV->GetRHI()->Release();
|
|
||||||
RHITexture.SafeRelease();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 双缓冲纹理对数组 [0] = 第一对, [1] = 第二对
|
|
||||||
FDeformationTexturePair TexturePairs[2];
|
|
||||||
|
|
||||||
// 当前使用的纹理对索引
|
|
||||||
int32 CurrentPairIndex = 0;
|
|
||||||
FBox LocalBounds;
|
FBox LocalBounds;
|
||||||
// 纹理资源初始化委托
|
|
||||||
FDelegateHandle TextureInitHandle;
|
// --- 碰撞参数 ---
|
||||||
// 当前碰撞参数
|
|
||||||
FVector CurrentImpactPoint;
|
FVector CurrentImpactPoint;
|
||||||
FVector CurrentImpactNormal;
|
FVector CurrentImpactNormal;
|
||||||
float CurrentImpactForce = 0.0f;
|
float CurrentImpactForce = 0.0f;
|
||||||
float CurrentDeformationRadius = 10.0f;
|
float CurrentDeformationRadius = 10.0f;
|
||||||
float CurrentPlasticity = 0.7f;
|
float CurrentPlasticity = 0.7f;
|
||||||
|
|
||||||
// 双缓冲纹理索引
|
/** * 双缓冲纹理索引
|
||||||
|
* 0: 读 RT0, 写 RT1
|
||||||
|
* 1: 读 RT1, 写 RT0
|
||||||
|
*/
|
||||||
int32 CurrentTextureIndex = 0;
|
int32 CurrentTextureIndex = 0;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
// Called every frame
|
// Called every frame
|
||||||
virtual void Tick(float DeltaTime) override;
|
virtual void Tick(float DeltaTime) override;
|
||||||
|
};
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user