修改设置碰撞的时候能获取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_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 "Engine/Texture.h"
#include "GenericPlatform/GenericPlatformProcess.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetRenderingLibrary.h"
// Sets default values
@@ -105,15 +107,15 @@ UTextureRenderTarget2D* AIronBlock::CreateDeformRT(const FString& RTName, int32
if (RenderTarget)
{
// **关键修复 1:** 设置为32位浮点数格式,以匹配 FLinearColor 和 CS 的 PF_A32B32G32R32F
//RenderTarget->RenderTargetFormat = RTF_RGBA32f;
RenderTarget->RenderTargetFormat = RTF_RGBA32f;
// **关键修复 2:** 明确告诉引擎我们需要为这个纹理创建UAV
RenderTarget->bCanCreateUAV = true;
//RenderTarget->bCanCreateUAV = true;
RenderTarget->InitCustomFormat(Size, Size, PF_A32B32G32R32F, false);
RenderTarget->bNeedsTwoCopies = true; // 告知引擎这个纹理会被用于Ping-Pong,优化内存
//RenderTarget->SizeX = Size;
//RenderTarget->SizeY = Size;
RenderTarget->SizeX = Size;
RenderTarget->SizeY = Size;
RenderTarget->bAutoGenerateMips = false;
RenderTarget->AddressX = TA_Clamp;
RenderTarget->AddressY = TA_Clamp;
@@ -129,33 +131,33 @@ void AIronBlock::InitializePositionTexture()
{
CalculateLocalBounds();
// 获取顶点位置 (用于计算初始UV->WorldPos)
TArray<FVector3f> VertexPositions;
GetStaticMeshVertexPositions(VertexPositions);
// // 获取顶点位置 (用于计算初始UV->WorldPos)
// TArray<FVector3f> VertexPositions;
// GetStaticMeshVertexPositions(VertexPositions);
// 创建位置纹理
const int32 TextureSize = 256; // 纹理尺寸
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);
}
}
const int32 TextureSize = 1024; // 纹理尺寸
// 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);
@@ -165,39 +167,39 @@ void AIronBlock::InitializePositionTexture()
// 我们需要将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();
}
}
// 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(TempTexture);
SetupDeformationMaterial(nullptr);
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"));
}
if (BaseMaterial)
UMaterial* CalMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Game/Materials/M_HitCal")); // 示例路径
if (!CalMaterial)
{
CalMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
}
if (BaseMaterial && CalMaterial)
{
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
DynCalMaterial = UMaterialInstanceDynamic::Create(CalMaterial, this);
StaticMeshComp->SetMaterial(0, DynMaterial);
//StaticMeshComp->SetMaterial(1, DynCalMaterial);
// 设置初始参数
if (DynMaterial)
{
// 初始时读取 RT0
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), OrigTex);
//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);
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionRenderTarget0);
}
}
else
@@ -267,30 +270,50 @@ void AIronBlock::SetupDeformationMaterial(UTexture2D* OrigTex)
void AIronBlock::OnHammerHit(const FHitResult& HitResult)
{
// 获取锤子冲击力
float ImpactForce = 0.0f;
// 检查 HitResult.GetComponent() 是否有效
if (HitResult.GetComponent() && !HitResult.GetComponent()->GetPhysicsLinearVelocity().IsNearlyZero())
FVector2D HitUV;
UGameplayStatics::FindCollisionUV(HitResult,0,HitUV);
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);
// 默认冲击力
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();
//ExecuteDeformationCS();
}
void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float ImpactForce)
void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector LocalImpactNormal, float _ImpactForce)
{
// 更新碰撞参数
CurrentImpactPoint = LocalImpactPoint;
@@ -313,8 +336,6 @@ void AIronBlock::UpdateComputeShaderParams(FVector LocalImpactPoint, FVector Loc
// 切换纹理缓冲索引
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()
+7
View File
@@ -32,6 +32,13 @@ class BLADESMITH_API AIronBlock : public AActor
UPROPERTY()
UMaterialInstanceDynamic* DynMaterial;
/** 应用于网格的动态材质实例 */
UPROPERTY()
UMaterialInstanceDynamic* DynCalMaterial;
UPROPERTY(EditAnywhere)
float ImpactForce;
public:
// Sets default values for this actor's properties
AIronBlock();