简化代码,修正固定模式之后切换不回来bug,调整计算偏移阈值为0.5
This commit is contained in:
@@ -23,9 +23,7 @@
|
||||
// Sets default values
|
||||
AIronBlock::AIronBlock() : StaticMeshComp(nullptr),
|
||||
PositionRenderTarget0(nullptr), PositionRenderTarget1(nullptr),
|
||||
DynMaterial(nullptr),
|
||||
CurrentImpactPoint(),
|
||||
CurrentImpactNormal()
|
||||
DynMaterial(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;
|
||||
@@ -57,47 +55,6 @@ void AIronBlock::BeginPlay()
|
||||
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
|
||||
*/
|
||||
@@ -119,7 +76,7 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
|
||||
RenderTarget->bAutoGenerateMips = false;
|
||||
RenderTarget->AddressX = 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;
|
||||
// 立即创建RHI资源
|
||||
RenderTarget->UpdateResource();
|
||||
@@ -141,108 +98,18 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
|
||||
|
||||
void AIronBlock::InitializePositionTexture()
|
||||
{
|
||||
CalculateLocalBounds();
|
||||
|
||||
// // 获取顶点位置 (用于计算初始UV->WorldPos)
|
||||
// TArray<FVector3f> VertexPositions;
|
||||
// GetStaticMeshVertexPositions(VertexPositions);
|
||||
|
||||
// 创建位置纹理
|
||||
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 ---
|
||||
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(nullptr);
|
||||
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)
|
||||
{
|
||||
// 创建动态材质实例
|
||||
@@ -285,7 +152,7 @@ void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
||||
FVector2D HitUV;
|
||||
UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
|
||||
FVector ImpactNormal = -HitResult.ImpactNormal;
|
||||
CurrentDeformationRadius = ImpactAffectRange/TexSize;
|
||||
float DeformationRadius = ImpactAffectRange/TexSize;
|
||||
UTextureRenderTarget2D* LastTex = nullptr;
|
||||
UTextureRenderTarget2D* CurTex = nullptr;
|
||||
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->SetScalarParameterValue(TEXT("ImpactForce"),ImpactForce);
|
||||
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactRadius"),CurrentDeformationRadius);
|
||||
DynCalMaterial->SetScalarParameterValue(TEXT("ImpactRadius"), DeformationRadius);
|
||||
DynCalMaterial->SetVectorParameterValue(TEXT("ImpactNormal"),ImpactNormal);
|
||||
DynCalMaterial->SetTextureParameterValue(TEXT("LastPosition"),LastTex);
|
||||
UKismetRenderingLibrary::DrawMaterialToRenderTarget(this->GetWorld(),CurTex,DynCalMaterial);
|
||||
@@ -312,243 +179,6 @@ void AIronBlock::OnHammerHit(const FHitResult& HitResult)
|
||||
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"),CurTex);
|
||||
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
|
||||
|
||||
@@ -53,7 +53,6 @@ public:
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
virtual void PostInitProperties();
|
||||
/** 初始化两个渲染目标和它们的初始数据 */
|
||||
void InitializePositionTexture();
|
||||
@@ -61,38 +60,10 @@ protected:
|
||||
/** 创建一个配置好用于变形计算的 RenderTarget */
|
||||
UTextureRenderTarget2D* CreateDeformRT(const FString& RTName, int32 Size);
|
||||
|
||||
/** 获取静态网格体的顶点位置 (用于计算初始纹理) */
|
||||
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
|
||||
|
||||
/** 设置动态材质实例和参数 */
|
||||
void SetupDeformationMaterial(UTexture2D* OrigTex);
|
||||
|
||||
/** 安全地获取 RenderTarget 的 RHI 资源 */
|
||||
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
|
||||
|
||||
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
|
||||
* 1: 读 RT1, 写 RT0
|
||||
|
||||
Reference in New Issue
Block a user