修改设置碰撞的时候能获取UV,模型用复杂碰撞。修改不用计算Shader而是直接用材质,直接在UV空间模拟计算形变并累积

This commit is contained in:
zhangqing
2025-11-13 18:48:35 +08:00
parent c58581180b
commit fcc1641189
8 changed files with 119 additions and 88 deletions
+3
View File
@@ -102,3 +102,6 @@ AppliedDefaultGraphicsPerformance=Maximum
+ActiveClassRedirects=(OldClassName="TP_FirstPersonGameMode",NewClassName="BladeSmithGameMode") +ActiveClassRedirects=(OldClassName="TP_FirstPersonGameMode",NewClassName="BladeSmithGameMode")
+ActiveClassRedirects=(OldClassName="TP_FirstPersonCharacter",NewClassName="BladeSmithCharacter") +ActiveClassRedirects=(OldClassName="TP_FirstPersonCharacter",NewClassName="BladeSmithCharacter")
[/Script/Engine.PhysicsSettings]
bSupportUVFromHitResults=True
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+109 -88
View File
@@ -16,6 +16,8 @@
#include "RHICommandList.h" #include "RHICommandList.h"
#include "Engine/Texture.h" #include "Engine/Texture.h"
#include "GenericPlatform/GenericPlatformProcess.h" #include "GenericPlatform/GenericPlatformProcess.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetRenderingLibrary.h"
// Sets default values // Sets default values
@@ -105,15 +107,15 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
if (RenderTarget) if (RenderTarget)
{ {
// **关键修复 1:** 设置为32位浮点数格式,以匹配 FLinearColor 和 CS 的 PF_A32B32G32R32F // **关键修复 1:** 设置为32位浮点数格式,以匹配 FLinearColor 和 CS 的 PF_A32B32G32R32F
//RenderTarget->RenderTargetFormat = RTF_RGBA32f; RenderTarget->RenderTargetFormat = RTF_RGBA32f;
// **关键修复 2:** 明确告诉引擎我们需要为这个纹理创建UAV // **关键修复 2:** 明确告诉引擎我们需要为这个纹理创建UAV
RenderTarget->bCanCreateUAV = true; //RenderTarget->bCanCreateUAV = true;
RenderTarget->InitCustomFormat(Size, Size, PF_A32B32G32R32F, false); RenderTarget->InitCustomFormat(Size, Size, PF_A32B32G32R32F, false);
RenderTarget->bNeedsTwoCopies = true; // 告知引擎这个纹理会被用于Ping-Pong,优化内存 RenderTarget->bNeedsTwoCopies = true; // 告知引擎这个纹理会被用于Ping-Pong,优化内存
//RenderTarget->SizeX = Size; RenderTarget->SizeX = Size;
//RenderTarget->SizeY = Size; RenderTarget->SizeY = Size;
RenderTarget->bAutoGenerateMips = false; RenderTarget->bAutoGenerateMips = false;
RenderTarget->AddressX = TA_Clamp; RenderTarget->AddressX = TA_Clamp;
RenderTarget->AddressY = TA_Clamp; RenderTarget->AddressY = TA_Clamp;
@@ -129,33 +131,33 @@ void AIronBlock::InitializePositionTexture()
{ {
CalculateLocalBounds(); CalculateLocalBounds();
// 获取顶点位置 (用于计算初始UV->WorldPos) // // 获取顶点位置 (用于计算初始UV->WorldPos)
TArray<FVector3f> VertexPositions; // TArray<FVector3f> VertexPositions;
GetStaticMeshVertexPositions(VertexPositions); // GetStaticMeshVertexPositions(VertexPositions);
// 创建位置纹理 // 创建位置纹理
const int32 TextureSize = 256; // 纹理尺寸 const int32 TextureSize = 1024; // 纹理尺寸
TArray<FLinearColor> InitialData; // TArray<FLinearColor> InitialData;
InitialData.SetNum(TextureSize * TextureSize); // InitialData.SetNum(TextureSize * TextureSize);
//
// 初始化纹理数据 (将UV映射到本地包围盒的XY平面) // // 初始化纹理数据 (将UV映射到本地包围盒的XY平面)
for (int32 Y = 0; Y < TextureSize; ++Y) // for (int32 Y = 0; Y < TextureSize; ++Y)
{ // {
for (int32 X = 0; X < TextureSize; ++X) // for (int32 X = 0; X < TextureSize; ++X)
{ // {
int32 Index = Y * TextureSize + X; // int32 Index = Y * TextureSize + X;
FVector2D UV(FVector2D(X, Y) / (TextureSize - 1.0f)); // 使用 255.0 或 (Size-1) // FVector2D UV(FVector2D(X, Y) / (TextureSize - 1.0f)); // 使用 255.0 或 (Size-1)
//
// 将UV坐标转换为本地空间位置 (XY平面) // // 将UV坐标转换为本地空间位置 (XY平面)
FVector LocalPos( // FVector LocalPos(
FMath::Lerp(LocalBounds.Min.X, LocalBounds.Max.X, UV.X), // FMath::Lerp(LocalBounds.Min.X, LocalBounds.Max.X, UV.X),
FMath::Lerp(LocalBounds.Min.Y, LocalBounds.Max.Y, UV.Y), // FMath::Lerp(LocalBounds.Min.Y, LocalBounds.Max.Y, UV.Y),
LocalBounds.Min.Z // 假设初始是一个平面 // LocalBounds.Min.Z // 假设初始是一个平面
); // );
//
InitialData[Index] = FLinearColor(LocalPos.X * 1000, LocalPos.Y * 1000, LocalPos.Z * 1000, 1.0f); // 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);
@@ -165,39 +167,39 @@ void AIronBlock::InitializePositionTexture()
// 我们需要将CPU端的 InitialData 写入到GPU纹理中 // 我们需要将CPU端的 InitialData 写入到GPU纹理中
// 最简单的方法是创建一个临时的UTexture2D,用BulkData上传,然后拷贝到RT // 最简单的方法是创建一个临时的UTexture2D,用BulkData上传,然后拷贝到RT
UTexture2D* TempTexture = UTexture2D::CreateTransient(TextureSize, TextureSize, PF_A32B32G32R32F); // 必须匹配格式 // UTexture2D* TempTexture = UTexture2D::CreateTransient(TextureSize, TextureSize, PF_A32B32G32R32F); // 必须匹配格式
if (TempTexture && PositionRenderTarget0 && PositionRenderTarget1) // if (TempTexture && PositionRenderTarget0 && PositionRenderTarget1)
{ // {
// 锁定 Mip 并拷贝数据 // // 锁定 Mip 并拷贝数据
FTexture2DMipMap& Mip = TempTexture->GetPlatformData()->Mips[0]; // FTexture2DMipMap& Mip = TempTexture->GetPlatformData()->Mips[0];
void* MipData = Mip.BulkData.Lock(LOCK_READ_WRITE); // void* MipData = Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, InitialData.GetData(), InitialData.Num() * sizeof(FLinearColor)); // FMemory::Memcpy(MipData, InitialData.GetData(), InitialData.Num() * sizeof(FLinearColor));
Mip.BulkData.Unlock(); // Mip.BulkData.Unlock();
TempTexture->UpdateResource(); // 提交到GPU // TempTexture->UpdateResource(); // 提交到GPU
//
// 获取RHI资源 // // 获取RHI资源
FTextureRHIRef DestRT0_RHI = GetRenderTargetRHI(PositionRenderTarget0); // FTextureRHIRef DestRT0_RHI = GetRenderTargetRHI(PositionRenderTarget0);
FTextureRHIRef DestRT1_RHI = GetRenderTargetRHI(PositionRenderTarget1); // FTextureRHIRef DestRT1_RHI = GetRenderTargetRHI(PositionRenderTarget1);
FTextureRHIRef SrcTex_RHI = TempTexture->GetResource() ? TempTexture->GetResource()->TextureRHI : nullptr; // FTextureRHIRef SrcTex_RHI = TempTexture->GetResource() ? TempTexture->GetResource()->TextureRHI : nullptr;
//
if (DestRT0_RHI && DestRT1_RHI && SrcTex_RHI) // if (DestRT0_RHI && DestRT1_RHI && SrcTex_RHI)
{ // {
// 在渲染线程上执行拷贝 // // 在渲染线程上执行拷贝
ENQUEUE_RENDER_COMMAND(InitializeDeformRTs)( // ENQUEUE_RENDER_COMMAND(InitializeDeformRTs)(
[DestRT0_RHI, DestRT1_RHI, SrcTex_RHI](FRHICommandListImmediate& RHICmdList) // [DestRT0_RHI, DestRT1_RHI, SrcTex_RHI](FRHICommandListImmediate& RHICmdList)
{ // {
// 将初始数据拷贝到两个RT // // 将初始数据拷贝到两个RT
RHICmdList.CopyTexture(SrcTex_RHI, DestRT0_RHI, {}); // RHICmdList.CopyTexture(SrcTex_RHI, DestRT0_RHI, {});
RHICmdList.CopyTexture(SrcTex_RHI, DestRT1_RHI, {}); // RHICmdList.CopyTexture(SrcTex_RHI, DestRT1_RHI, {});
}); // });
//
// 确保拷贝完成 // // 确保拷贝完成
FlushRenderingCommands(); // FlushRenderingCommands();
} // }
} // }
// 设置变形材质 // 设置变形材质
SetupDeformationMaterial(TempTexture); SetupDeformationMaterial(nullptr);
UE_LOG(LogTemp, Log, TEXT("Position textures initialized")); UE_LOG(LogTemp, Log, TEXT("Position textures initialized"));
} }
@@ -240,21 +242,22 @@ void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
{ {
BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial")); BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
} }
UMaterial* CalMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Game/Materials/M_HitCal")); // 示例路径
if (BaseMaterial) if (!CalMaterial)
{
CalMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
}
if (BaseMaterial && CalMaterial)
{ {
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this); DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
DynCalMaterial = UMaterialInstanceDynamic::Create(CalMaterial, this);
StaticMeshComp->SetMaterial(0, DynMaterial); StaticMeshComp->SetMaterial(0, DynMaterial);
//StaticMeshComp->SetMaterial(1, DynCalMaterial);
// 设置初始参数 // 设置初始参数
if (DynMaterial) if (DynMaterial)
{ {
// 初始时读取 RT0 // 初始时读取 RT0
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), OrigTex); DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionRenderTarget0);
//DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionRenderTarget0);
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
DynMaterial->SetScalarParameterValue(TEXT("DeformationStrength"), 1.0f);
} }
} }
else else
@@ -267,30 +270,50 @@ void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
void AIronBlock::OnHammerHit(const FHitResult& HitResult) void AIronBlock::OnHammerHit(const FHitResult& HitResult)
{ {
// 获取锤子冲击力 // 获取锤子冲击力
float ImpactForce = 0.0f; FVector2D HitUV;
// 检查 HitResult.GetComponent() 是否有效 UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
if (HitResult.GetComponent() && !HitResult.GetComponent()->GetPhysicsLinearVelocity().IsNearlyZero()) FVector ImpactNormal = -HitResult.ImpactNormal;
CurrentDeformationRadius = 10.0f/1024.0f;
UTextureRenderTarget2D* LastTex = nullptr;
UTextureRenderTarget2D* CurTex = nullptr;
if(CurrentTextureIndex == 0)
{ {
ImpactForce = HitResult.GetComponent()->GetPhysicsLinearVelocity().Size(); 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"),CurrentDeformationRadius);
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;
}
// // 转换到本地空间
// 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();
if (ImpactForce < 10.0f) ImpactForce = 500.0f;
// 转换到本地空间
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) void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float _ImpactForce)
{ {
// 更新碰撞参数 // 更新碰撞参数
CurrentImpactPoint = LocalImpactPoint; CurrentImpactPoint = LocalImpactPoint;
@@ -313,8 +336,6 @@ void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector Loc
// 切换纹理缓冲索引 // 切换纹理缓冲索引
CurrentTextureIndex = 1 - CurrentTextureIndex; CurrentTextureIndex = 1 - CurrentTextureIndex;
UE_LOG(LogTemp,Display,TEXT("[AIronBlock::OnHammerHitUpdateComputeShaderParams]CurrentImpactForce:%f, CurrentImpactPoint:%s,CurrentImpactNormal:%s,CurrentDeformationRadius:%f,CurrentPlasticity:%f")
,CurrentImpactForce,*CurrentImpactPoint.ToString(),*CurrentImpactNormal.ToString(),CurrentDeformationRadius,CurrentPlasticity);
} }
void AIronBlock::ExecuteDeformationCS() void AIronBlock::ExecuteDeformationCS()
+7
View File
@@ -32,6 +32,13 @@ class BLADESMITH_API AIronBlock : public AActor
UPROPERTY() UPROPERTY()
UMaterialInstanceDynamic* DynMaterial; UMaterialInstanceDynamic* DynMaterial;
/** 应用于网格的动态材质实例 */
UPROPERTY()
UMaterialInstanceDynamic* DynCalMaterial;
UPROPERTY(EditAnywhere)
float ImpactForce;
public: public:
// Sets default values for this actor's properties // Sets default values for this actor's properties
AIronBlock(); AIronBlock();