简化代码,修正固定模式之后切换不回来bug,调整计算偏移阈值为0.5
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -23,9 +23,7 @@
|
|||||||
// Sets default values
|
// Sets default values
|
||||||
AIronBlock::AIronBlock() : StaticMeshComp(nullptr),
|
AIronBlock::AIronBlock() : StaticMeshComp(nullptr),
|
||||||
PositionRenderTarget0(nullptr), PositionRenderTarget1(nullptr),
|
PositionRenderTarget0(nullptr), PositionRenderTarget1(nullptr),
|
||||||
DynMaterial(nullptr),
|
DynMaterial(nullptr)
|
||||||
CurrentImpactPoint(),
|
|
||||||
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;
|
||||||
@@ -57,47 +55,6 @@ void AIronBlock::BeginPlay()
|
|||||||
InitializePositionTexture();
|
InitializePositionTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AIronBlock::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
||||||
{
|
|
||||||
// RenderTargets 会被 UPROPERTY 自动 GC,无需手动释放 RHI 资源
|
|
||||||
|
|
||||||
Super::EndPlay(EndPlayReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安全的渲染目标获取
|
|
||||||
FTextureRHIRef AIronBlock::GetRenderTargetRHI(UTextureRenderTarget2D* RT)
|
|
||||||
{
|
|
||||||
if (!RT || !RT->GetResource()) return nullptr;
|
|
||||||
return RT->GetResource()->TextureRHI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIronBlock::GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions)
|
|
||||||
{
|
|
||||||
OutPositions.Empty();
|
|
||||||
|
|
||||||
if (!StaticMeshComp || !StaticMeshComp->GetStaticMesh())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 获取静态网格资源
|
|
||||||
UStaticMesh* StaticMesh = StaticMeshComp->GetStaticMesh();
|
|
||||||
// 确保有有效的 RenderData 和 LOD
|
|
||||||
if (StaticMesh->GetRenderData() && StaticMesh->GetRenderData()->LODResources.Num() > 0)
|
|
||||||
{
|
|
||||||
// 获取LOD0的顶点数据
|
|
||||||
FStaticMeshLODResources& LOD = StaticMesh->GetRenderData()->LODResources[0];
|
|
||||||
const FPositionVertexBuffer& VertexBuffer = LOD.VertexBuffers.PositionVertexBuffer;
|
|
||||||
|
|
||||||
const int32 VertexCount = VertexBuffer.GetNumVertices();
|
|
||||||
OutPositions.SetNum(VertexCount);
|
|
||||||
|
|
||||||
for (int32 i = 0; i < VertexCount; i++)
|
|
||||||
{
|
|
||||||
OutPositions[i] = VertexBuffer.VertexPosition(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 核心修复:创建一个配置好用于变形计算的 RenderTarget
|
* 核心修复:创建一个配置好用于变形计算的 RenderTarget
|
||||||
*/
|
*/
|
||||||
@@ -119,7 +76,7 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
|
|||||||
RenderTarget->bAutoGenerateMips = false;
|
RenderTarget->bAutoGenerateMips = false;
|
||||||
RenderTarget->AddressX = TA_Clamp;
|
RenderTarget->AddressX = TA_Clamp;
|
||||||
RenderTarget->AddressY = TA_Clamp;
|
RenderTarget->AddressY = TA_Clamp;
|
||||||
FLinearColor ClearColor = FLinearColor(0.25f, 0.25f, 0.25f, 1.0f);
|
FLinearColor ClearColor = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
RenderTarget->ClearColor = ClearColor;
|
RenderTarget->ClearColor = ClearColor;
|
||||||
// 立即创建RHI资源
|
// 立即创建RHI资源
|
||||||
RenderTarget->UpdateResource();
|
RenderTarget->UpdateResource();
|
||||||
@@ -141,108 +98,18 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
|
|||||||
|
|
||||||
void AIronBlock::InitializePositionTexture()
|
void AIronBlock::InitializePositionTexture()
|
||||||
{
|
{
|
||||||
CalculateLocalBounds();
|
|
||||||
|
|
||||||
// // 获取顶点位置 (用于计算初始UV->WorldPos)
|
|
||||||
// TArray<FVector3f> VertexPositions;
|
|
||||||
// GetStaticMeshVertexPositions(VertexPositions);
|
|
||||||
|
|
||||||
// 创建位置纹理
|
// 创建位置纹理
|
||||||
const int32 TextureSize = TexSize; // 纹理尺寸
|
const int32 TextureSize = TexSize; // 纹理尺寸
|
||||||
// TArray<FLinearColor> InitialData;
|
|
||||||
// InitialData.SetNum(TextureSize * TextureSize);
|
|
||||||
//
|
|
||||||
// // 初始化纹理数据 (将UV映射到本地包围盒的XY平面)
|
|
||||||
// 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.0f)); // 使用 255.0 或 (Size-1)
|
|
||||||
//
|
|
||||||
// // 将UV坐标转换为本地空间位置 (XY平面)
|
|
||||||
// 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 * 1000, LocalPos.Y * 1000, LocalPos.Z * 1000, 1.0f);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// --- 关键修复: 创建两个 RenderTarget ---
|
// --- 关键修复: 创建两个 RenderTarget ---
|
||||||
PositionRenderTarget0 = CreateDeformRT(TEXT("PositionRT0"), TextureSize);
|
PositionRenderTarget0 = CreateDeformRT(TEXT("PositionRT0"), TextureSize);
|
||||||
PositionRenderTarget1 = CreateDeformRT(TEXT("PositionRT1"), 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(nullptr);
|
SetupDeformationMaterial(nullptr);
|
||||||
UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
|
UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIronBlock::CalculateLocalBounds()
|
|
||||||
{
|
|
||||||
if (!StaticMeshComp)
|
|
||||||
{
|
|
||||||
StaticMeshComp = GetComponentByClass<UStaticMeshComponent>();
|
|
||||||
}
|
|
||||||
if (StaticMeshComp && StaticMeshComp->GetStaticMesh())
|
|
||||||
{
|
|
||||||
// 获取本地空间包围盒
|
|
||||||
LocalBounds = StaticMeshComp->GetStaticMesh()->GetBoundingBox();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 智能默认值
|
|
||||||
float Extent = 50.0f;
|
|
||||||
LocalBounds = FBox(
|
|
||||||
FVector(-Extent, -Extent, 0),
|
|
||||||
FVector(Extent, Extent, Extent * 0.2f)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保包围盒有效
|
|
||||||
if (LocalBounds.GetVolume() <= 0)
|
|
||||||
{
|
|
||||||
LocalBounds = FBox(FVector(-50, -50, 0), FVector(50, 50, 10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
|
void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
|
||||||
{
|
{
|
||||||
// 创建动态材质实例
|
// 创建动态材质实例
|
||||||
@@ -285,7 +152,7 @@ void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
|||||||
FVector2D HitUV;
|
FVector2D HitUV;
|
||||||
UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
|
UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
|
||||||
FVector ImpactNormal = -HitResult.ImpactNormal;
|
FVector ImpactNormal = -HitResult.ImpactNormal;
|
||||||
CurrentDeformationRadius = ImpactAffectRange/TexSize;
|
float DeformationRadius = ImpactAffectRange/TexSize;
|
||||||
UTextureRenderTarget2D* LastTex = nullptr;
|
UTextureRenderTarget2D* LastTex = nullptr;
|
||||||
UTextureRenderTarget2D* CurTex = nullptr;
|
UTextureRenderTarget2D* CurTex = nullptr;
|
||||||
if(CurrentTextureIndex == 0)
|
if(CurrentTextureIndex == 0)
|
||||||
@@ -302,7 +169,7 @@ void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
|||||||
{
|
{
|
||||||
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactUV"), FLinearColor(HitUV.X,HitUV.Y,0,0));
|
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactUV"), FLinearColor(HitUV.X,HitUV.Y,0,0));
|
||||||
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactForce"),ImpactForce);
|
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactForce"),ImpactForce);
|
||||||
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactRadius"),CurrentDeformationRadius);
|
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactRadius"), DeformationRadius);
|
||||||
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactNormal"),ImpactNormal);
|
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactNormal"),ImpactNormal);
|
||||||
DynCalMaterial->SetTextureParameterValue(TEXT("LastPosition"),LastTex);
|
DynCalMaterial->SetTextureParameterValue(TEXT("LastPosition"),LastTex);
|
||||||
UKismetRenderingLibrary::DrawMaterialToRenderTarget(this->GetWorld(),CurTex,DynCalMaterial);
|
UKismetRenderingLibrary::DrawMaterialToRenderTarget(this->GetWorld(),CurTex,DynCalMaterial);
|
||||||
@@ -312,243 +179,6 @@ void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
|||||||
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"),CurTex);
|
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"),CurTex);
|
||||||
CurrentTextureIndex = 1 - CurrentTextureIndex;
|
CurrentTextureIndex = 1 - CurrentTextureIndex;
|
||||||
}
|
}
|
||||||
// // 转换到本地空间
|
|
||||||
// FVector ImpactPoint = HitResult.ImpactPoint;
|
|
||||||
// FVector ImpactNormal = HitResult.ImpactNormal;
|
|
||||||
// FVector LocalImpactPoint = GetTransform().InverseTransformPosition(ImpactPoint);
|
|
||||||
// FVector LocalImpactNormal = GetTransform().InverseTransformVector(ImpactNormal);
|
|
||||||
// UE_LOG(LogTemp,Display,TEXT("[AIronBlock::OnHammerHit] ImpactForce:%f,ImpactPoint:%s,ImpactNormal:%s,LocalImpactPoint:%s,LocalImpactNormal:%s")
|
|
||||||
// ,ImpactForce,*ImpactPoint.ToString(),*ImpactNormal.ToString(),*LocalImpactPoint.ToString(),*LocalImpactNormal.ToString());
|
|
||||||
// UpdateComputeShaderParams(LocalImpactPoint, LocalImpactNormal, ImpactForce);
|
|
||||||
|
|
||||||
//ExecuteDeformationCS();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float _ImpactForce)
|
|
||||||
{
|
|
||||||
// 更新碰撞参数
|
|
||||||
CurrentImpactPoint = LocalImpactPoint;
|
|
||||||
CurrentImpactNormal = LocalImpactNormal.GetSafeNormal();
|
|
||||||
CurrentImpactForce = FMath::Clamp(ImpactForce, 0.0f, 5000.0f);
|
|
||||||
|
|
||||||
// 根据冲击力计算动态变形半径
|
|
||||||
CurrentDeformationRadius = FMath::Lerp(5.0f, 30.0f, CurrentImpactForce / 2000.0f);
|
|
||||||
|
|
||||||
// 根据材质类型调整塑性系数 (示例)
|
|
||||||
UMaterialInterface* Material = StaticMeshComp->GetMaterial(0);
|
|
||||||
if (Material && Material->GetName().Contains("Steel"))
|
|
||||||
{
|
|
||||||
CurrentPlasticity = 0.4f; // 钢材塑性较低
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CurrentPlasticity = 0.8f; // 默认高塑性
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换纹理缓冲索引
|
|
||||||
CurrentTextureIndex = 1 - CurrentTextureIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIronBlock::ExecuteDeformationCS()
|
|
||||||
{
|
|
||||||
// 确保纹理资源有效
|
|
||||||
if (!PositionRenderTarget0 || !PositionRenderTarget0->GetResource() ||
|
|
||||||
!PositionRenderTarget1 || !PositionRenderTarget1->GetResource())
|
|
||||||
{
|
|
||||||
UE_LOG(LogTemp, Error, TEXT("Position render targets not initialized!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 关键修复: 决定哪个是读取RT,哪个是写入RT ---
|
|
||||||
UTextureRenderTarget2D* ReadTarget = (CurrentTextureIndex == 0) ? PositionRenderTarget0 : PositionRenderTarget1;
|
|
||||||
UTextureRenderTarget2D* WriteTarget = (CurrentTextureIndex == 1) ? PositionRenderTarget0 : PositionRenderTarget1; // Flipped
|
|
||||||
|
|
||||||
// --- 关键修复: 在游戏线程只获取 Input RHI Texture 句柄 ---
|
|
||||||
FTextureRHIRef InputRHI = GetRenderTargetRHI(ReadTarget);
|
|
||||||
FTextureRHIRef WriteRHI = GetRenderTargetRHI(WriteTarget); // 必须获取写入目标的RHI
|
|
||||||
|
|
||||||
if (!InputRHI.IsValid() || !WriteRHI.IsValid())
|
|
||||||
{
|
|
||||||
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算纹理UV坐标
|
|
||||||
const int32 _TexSize = ReadTarget->SizeX;
|
|
||||||
FVector2D ImpactUV(
|
|
||||||
(CurrentImpactPoint.X - LocalBounds.Min.X) / LocalBounds.GetSize().X,
|
|
||||||
(CurrentImpactPoint.Y - LocalBounds.Min.Y) / LocalBounds.GetSize().Y
|
|
||||||
);
|
|
||||||
UE_LOG(LogTemp,Display,TEXT("[AIronBlock::ExecuteDeformationCS]LocalBounds:%s")
|
|
||||||
,*LocalBounds.ToString());
|
|
||||||
|
|
||||||
// 假设 LocalBounds 仍然是未缩放的原始包围盒
|
|
||||||
// 获得 Actor 的缩放
|
|
||||||
FVector ComponentScale = StaticMeshComp->GetComponentScale();
|
|
||||||
|
|
||||||
// 1. 计算缩放后包围盒的最大延伸 (在 X/Y 平面上)
|
|
||||||
// 假设您的形变发生在 XY 平面
|
|
||||||
float MaxLocalExtentX = LocalBounds.GetExtent().X * ComponentScale.X;
|
|
||||||
float MaxLocalExtentY = LocalBounds.GetExtent().Y * ComponentScale.Y;
|
|
||||||
float MaxScaledExtent = FMath::Max(MaxLocalExtentX, MaxLocalExtentY);
|
|
||||||
|
|
||||||
// 2. 使用这个缩放后的最大延伸进行比例计算
|
|
||||||
// 这里的 CurrentDeformationRadius 应该是一个世界空间的值。
|
|
||||||
const float RadiusRatio = CurrentDeformationRadius / MaxScaledExtent;
|
|
||||||
// 计算更新区域 (只更新受影响部分)
|
|
||||||
//const float RadiusRatio = CurrentDeformationRadius / LocalBounds.GetExtent().GetMax();
|
|
||||||
FIntRect UpdateRegion;
|
|
||||||
UpdateRegion.Min.X = FMath::Clamp(FMath::FloorToInt((ImpactUV.X - RadiusRatio) * _TexSize), 0, _TexSize - 1);
|
|
||||||
UpdateRegion.Min.Y = FMath::Clamp(FMath::FloorToInt((ImpactUV.Y - RadiusRatio) * _TexSize), 0, _TexSize - 1);
|
|
||||||
UpdateRegion.Max.X = FMath::Clamp(FMath::CeilToInt((ImpactUV.X + RadiusRatio) * _TexSize), 1, _TexSize);
|
|
||||||
UpdateRegion.Max.Y = FMath::Clamp(FMath::CeilToInt((ImpactUV.Y + RadiusRatio) * _TexSize), 1, _TexSize);
|
|
||||||
|
|
||||||
// 确保 Min < Max
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 临时代码,先更新全部区域
|
|
||||||
UpdateRegion.Min.X = 0;
|
|
||||||
UpdateRegion.Min.Y = 0;
|
|
||||||
UpdateRegion.Max.X = _TexSize;
|
|
||||||
UpdateRegion.Max.Y = _TexSize;
|
|
||||||
|
|
||||||
// --- 关键修改:使用 RDG ---
|
|
||||||
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS_RDG)(
|
|
||||||
[
|
|
||||||
// 捕获所有需要的参数
|
|
||||||
InputRHI,
|
|
||||||
WriteRHI,
|
|
||||||
CurrentImpactPoint = this->CurrentImpactPoint, // 拷贝一份
|
|
||||||
CurrentImpactNormal = this->CurrentImpactNormal,
|
|
||||||
CurrentImpactForce = this->CurrentImpactForce,
|
|
||||||
CurrentDeformationRadius = this->CurrentDeformationRadius,
|
|
||||||
CurrentPlasticity = this->CurrentPlasticity,
|
|
||||||
UpdateRegion, //
|
|
||||||
_TexSize //
|
|
||||||
](FRHICommandListImmediate& RHICmdList)
|
|
||||||
{
|
|
||||||
// 1. 创建 RDG Builder
|
|
||||||
FRDGBuilder builder(RHICmdList);
|
|
||||||
|
|
||||||
// 2. 将我们的外部 RT 注册到 RDG 中
|
|
||||||
// 注意:我们使用 WriteRHI->GetDesc() 来获取纹理描述
|
|
||||||
FRDGTextureRef RDGReadTexture = builder.RegisterExternalTexture(
|
|
||||||
CreateRenderTarget(InputRHI, TEXT("DeformInputTex"))
|
|
||||||
);
|
|
||||||
FRDGTextureRef RDGWriteTexture = builder.RegisterExternalTexture(
|
|
||||||
CreateRenderTarget(WriteRHI, TEXT("DeformOutputTex"))
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. 分配着色器参数
|
|
||||||
FDeformComputeShader::FParameters* Params = builder.AllocParameters<FDeformComputeShader::FParameters>();
|
|
||||||
|
|
||||||
// 4. 填充 CPU 参数
|
|
||||||
Params->ImpactPoint = FVector3f(CurrentImpactPoint); // 注意:从 FVector 转为 FVector3f
|
|
||||||
Params->ImpactNormal = FVector3f(CurrentImpactNormal);
|
|
||||||
Params->ImpactForce = CurrentImpactForce;
|
|
||||||
Params->DeformationRadius = CurrentDeformationRadius;
|
|
||||||
Params->Plasticity = CurrentPlasticity;
|
|
||||||
Params->UpdateRegionParam = FIntVector4(UpdateRegion.Min.X, UpdateRegion.Min.Y, UpdateRegion.Max.X, UpdateRegion.Max.Y);
|
|
||||||
Params->TextureSize = FIntVector(_TexSize, _TexSize, 1);
|
|
||||||
UE_LOG(LogTemp,Display,TEXT("[AIronBlock::ExecuteDeformationCS]ImpactForce:%f, ImpactPoint:%s,ImpactNormal:%s,DeformationRadius:%f,Plasticity:%f,UpdateRegion:%s")
|
|
||||||
,Params->ImpactForce,*Params->ImpactPoint.ToString(),*Params->ImpactNormal.ToString(),Params->DeformationRadius,Params->Plasticity,*Params->UpdateRegionParam.ToString());
|
|
||||||
|
|
||||||
|
|
||||||
// 5. ✨ 魔法发生的地方:RDG 为我们创建 SRV 和 UAV
|
|
||||||
// 这就是解决你 nullptr 问题的核心
|
|
||||||
Params->InputTexture = builder.CreateSRV(RDGReadTexture);
|
|
||||||
Params->OutputTexture = builder.CreateUAV(RDGWriteTexture);
|
|
||||||
|
|
||||||
// 6. 获取着色器实例
|
|
||||||
TShaderMapRef<FDeformComputeShader> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
|
|
||||||
if (!ComputeShader.IsValid())
|
|
||||||
{
|
|
||||||
UE_LOG(LogTemp, Error, TEXT("FDeformComputeShader is not valid!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. 计算线程组数量
|
|
||||||
// (注意:你的USF需要处理 UpdateRegion,这里我们调度整个区域)
|
|
||||||
FIntVector NumGroups = FIntVector::DivideAndRoundUp(
|
|
||||||
FIntVector(UpdateRegion.Width(), UpdateRegion.Height(), 1),
|
|
||||||
FDeformComputeShader::GetGroupSize()
|
|
||||||
);
|
|
||||||
// 如果你的shader总是处理整个纹理,请使用:
|
|
||||||
// FIntVector NumGroups = FIntVector::DivideAndRoundUp(
|
|
||||||
// Params->TextureSize, FDeformComputeShader::GetGroupSize()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// 8. 添加 Compute Pass
|
|
||||||
FComputeShaderUtils::AddPass(
|
|
||||||
builder,
|
|
||||||
RDG_EVENT_NAME("ExecuteDeformationCS"),
|
|
||||||
ComputeShader,
|
|
||||||
Params,
|
|
||||||
NumGroups
|
|
||||||
);
|
|
||||||
|
|
||||||
// 9. 执行 RDG (这会处理所有屏障和调度)
|
|
||||||
builder.Execute();
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- 结束 RDG 修改 ---
|
|
||||||
|
|
||||||
// 确保渲染命令完成 (如果你需要立即更新碰撞体)
|
|
||||||
// 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, UTextureRenderTarget2D* FromTarget)
|
|
||||||
{
|
|
||||||
// 注意:ReadPixels 是一项非常慢的操作 (GPU->CPU 同步)
|
|
||||||
// 更好的方法是使用另一个Compute Shader将顶点数据简化并读回到一个小的StructuredBuffer中
|
|
||||||
|
|
||||||
if (!FromTarget || !FromTarget->GetResource())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 从GPU读取关键区域数据
|
|
||||||
TArray<FLinearColor> SampledData; // 使用 FLinearColor
|
|
||||||
FReadSurfaceDataFlags Flags;
|
|
||||||
Flags.SetLinearToGamma(false);
|
|
||||||
|
|
||||||
FRenderTarget* RTResource = FromTarget->GameThread_GetRenderTargetResource();
|
|
||||||
if (!RTResource) return;
|
|
||||||
|
|
||||||
RTResource->ReadLinearColorPixels(
|
|
||||||
SampledData,
|
|
||||||
Flags,
|
|
||||||
UpdateRegion // FIntRect
|
|
||||||
);
|
|
||||||
|
|
||||||
// 创建临时碰撞体
|
|
||||||
TArray<FVector> CollisionVerts;
|
|
||||||
for (const FLinearColor& Pixel : SampledData)
|
|
||||||
{
|
|
||||||
// 像素数据已经是 FLinearColor (即 FVector)
|
|
||||||
CollisionVerts.Add(FVector(Pixel.R, Pixel.G, Pixel.B));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CollisionVerts.Num() == 0) return;
|
|
||||||
|
|
||||||
// 更新简单碰撞体
|
|
||||||
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
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ public:
|
|||||||
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 PostInitProperties();
|
virtual void PostInitProperties();
|
||||||
/** 初始化两个渲染目标和它们的初始数据 */
|
/** 初始化两个渲染目标和它们的初始数据 */
|
||||||
void InitializePositionTexture();
|
void InitializePositionTexture();
|
||||||
@@ -61,38 +60,10 @@ protected:
|
|||||||
/** 创建一个配置好用于变形计算的 RenderTarget */
|
/** 创建一个配置好用于变形计算的 RenderTarget */
|
||||||
UTextureRenderTarget2D* CreateDeformRT(const FString& RTName, int32 Size);
|
UTextureRenderTarget2D* CreateDeformRT(const FString& RTName, int32 Size);
|
||||||
|
|
||||||
/** 获取静态网格体的顶点位置 (用于计算初始纹理) */
|
|
||||||
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
|
|
||||||
|
|
||||||
/** 设置动态材质实例和参数 */
|
/** 设置动态材质实例和参数 */
|
||||||
void SetupDeformationMaterial(UTexture2D* OrigTex);
|
void SetupDeformationMaterial(UTexture2D* OrigTex);
|
||||||
|
|
||||||
/** 安全地获取 RenderTarget 的 RHI 资源 */
|
|
||||||
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** 更新 Compute Shader 所需的参数 */
|
|
||||||
void UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce);
|
|
||||||
|
|
||||||
/** 在渲染线程上执行 Compute Shader */
|
|
||||||
void ExecuteDeformationCS();
|
|
||||||
|
|
||||||
/** (可选) 异步更新物理碰撞体 */
|
|
||||||
void UpdateCollisionAsync(const FIntRect& UpdateRegion, UTextureRenderTarget2D* FromTarget);
|
|
||||||
|
|
||||||
/** 计算网格体的本地包围盒 */
|
|
||||||
void CalculateLocalBounds();
|
|
||||||
|
|
||||||
// 网格体的本地包围盒
|
|
||||||
FBox LocalBounds;
|
|
||||||
|
|
||||||
// --- 碰撞参数 ---
|
|
||||||
FVector CurrentImpactPoint;
|
|
||||||
FVector CurrentImpactNormal;
|
|
||||||
float CurrentImpactForce = 0.0f;
|
|
||||||
float CurrentDeformationRadius = 10.0f;
|
|
||||||
float CurrentPlasticity = 0.7f;
|
|
||||||
|
|
||||||
/** * 双缓冲纹理索引
|
/** * 双缓冲纹理索引
|
||||||
* 0: 读 RT0, 写 RT1
|
* 0: 读 RT0, 写 RT1
|
||||||
* 1: 读 RT1, 写 RT0
|
* 1: 读 RT1, 写 RT0
|
||||||
|
|||||||
Reference in New Issue
Block a user