使用cursor修正代码

This commit is contained in:
2025-08-06 23:47:59 +08:00
parent 6b3260f35d
commit 94a19cbdf4
14 changed files with 735 additions and 251 deletions
+14 -1
View File
@@ -8,6 +8,19 @@ public class BladeSmith : ModuleRules
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput","RenderCore","RHI" });
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore",
"EnhancedInput",
"RenderCore",
"RHI",
"Renderer",
"PhysicsCore",
"AudioExtensions",
"AudioMixer",
"AudioPlatformConfiguration"
});
}
}
+16 -1
View File
@@ -2,6 +2,7 @@
#include "BladeSmithCharacter.h"
#include "BladeSmithProjectile.h"
#include "BladeSmithWeaponComponent.h"
#include "Animation/AnimInstance.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
@@ -35,6 +36,9 @@ ABladeSmithCharacter::ABladeSmithCharacter()
Mesh1P->CastShadow = false;
Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f));
// Create hammer component
HammerComponent = CreateDefaultSubobject<UBladeSmithWeaponComponent>(TEXT("HammerComponent"));
HammerComponent->SetupAttachment(Mesh1P);
}
//////////////////////////////////////////////////////////////////////////// Input
@@ -67,6 +71,9 @@ void ABladeSmithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInpu
// Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ABladeSmithCharacter::Look);
// Hammer
EnhancedInputComponent->BindAction(HammerAction, ETriggerEvent::Started, this, &ABladeSmithCharacter::Hammer);
}
else
{
@@ -74,7 +81,6 @@ void ABladeSmithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInpu
}
}
void ABladeSmithCharacter::Move(const FInputActionValue& Value)
{
// input is a Vector2D
@@ -99,4 +105,13 @@ void ABladeSmithCharacter::Look(const FInputActionValue& Value)
AddControllerYawInput(LookAxisVector.X);
AddControllerPitchInput(LookAxisVector.Y);
}
}
void ABladeSmithCharacter::Hammer(const FInputActionValue& Value)
{
// 执行锤击
if (HammerComponent)
{
HammerComponent->SwingHammer();
}
}
+14
View File
@@ -12,6 +12,7 @@ class USkeletalMeshComponent;
class UCameraComponent;
class UInputAction;
class UInputMappingContext;
class UBladeSmithWeaponComponent;
struct FInputActionValue;
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
@@ -29,6 +30,10 @@ class ABladeSmithCharacter : public ACharacter
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
UCameraComponent* FirstPersonCameraComponent;
/** 锤子组件 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Weapon, meta = (AllowPrivateAccess = "true"))
UBladeSmithWeaponComponent* HammerComponent;
/** MappingContext */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputMappingContext* DefaultMappingContext;
@@ -44,6 +49,10 @@ class ABladeSmithCharacter : public ACharacter
/** Look Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* LookAction;
/** Hammer Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* HammerAction;
public:
ABladeSmithCharacter();
@@ -55,6 +64,9 @@ protected:
/** Called for looking input */
void Look(const FInputActionValue& Value);
/** Called for hammer input */
void Hammer(const FInputActionValue& Value);
protected:
// APawn interface
virtual void NotifyControllerChanged() override;
@@ -66,6 +78,8 @@ public:
USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
/** Returns FirstPersonCameraComponent subobject **/
UCameraComponent* GetFirstPersonCameraComponent() const { return FirstPersonCameraComponent; }
/** Returns HammerComponent subobject **/
UBladeSmithWeaponComponent* GetHammerComponent() const { return HammerComponent; }
};
+142 -76
View File
@@ -3,117 +3,183 @@
#include "BladeSmithWeaponComponent.h"
#include "BladeSmithCharacter.h"
#include "BladeSmithProjectile.h"
#include "GameFramework/PlayerController.h"
#include "Camera/PlayerCameraManager.h"
#include "Kismet/GameplayStatics.h"
#include "IronBlock.h"
#include "Animation/AnimInstance.h"
#include "Components/SkeletalMeshComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Animation/AnimInstance.h"
#include "InputActionValue.h"
#include "Engine/LocalPlayer.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/World.h"
#include "DrawDebugHelpers.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "Camera/CameraComponent.h"
// Sets default values for this component's properties
UBladeSmithWeaponComponent::UBladeSmithWeaponComponent()
{
// Default offset from the character location for projectiles to spawn
MuzzleOffset = FVector(100.0f, 0.0f, 10.0f);
// 设置默认值
HammerHeadOffset = FVector(0.0f, 0.0f, -50.0f);
HammerForce = 1000.0f;
HammerRange = 200.0f;
}
void UBladeSmithWeaponComponent::Fire()
{
if (Character == nullptr || Character->GetController() == nullptr)
{
return;
}
// Try and fire a projectile
if (ProjectileClass != nullptr)
{
UWorld* const World = GetWorld();
if (World != nullptr)
{
APlayerController* PlayerController = Cast<APlayerController>(Character->GetController());
const FRotator SpawnRotation = PlayerController->PlayerCameraManager->GetCameraRotation();
// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
const FVector SpawnLocation = GetOwner()->GetActorLocation() + SpawnRotation.RotateVector(MuzzleOffset);
//Set Spawn Collision Handling Override
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
// Spawn the projectile at the muzzle
World->SpawnActor<ABladeSmithProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
}
}
// Try and play the sound if specified
if (FireSound != nullptr)
{
UGameplayStatics::PlaySoundAtLocation(this, FireSound, Character->GetActorLocation());
}
// Try and play a firing animation if specified
if (FireAnimation != nullptr)
{
// Get the animation object for the arms mesh
UAnimInstance* AnimInstance = Character->GetMesh1P()->GetAnimInstance();
if (AnimInstance != nullptr)
{
AnimInstance->Montage_Play(FireAnimation, 1.f);
}
}
}
bool UBladeSmithWeaponComponent::AttachWeapon(ABladeSmithCharacter* TargetCharacter)
bool UBladeSmithWeaponComponent::AttachHammer(ABladeSmithCharacter* TargetCharacter)
{
Character = TargetCharacter;
// Check that the character is valid, and has no weapon component yet
if (Character == nullptr || Character->GetInstanceComponents().FindItemByClass<UBladeSmithWeaponComponent>())
if (Character == nullptr)
{
return false;
}
// Attach the weapon to the First Person Character
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
AttachToComponent(Character->GetMesh1P(), AttachmentRules, FName(TEXT("GripPoint")));
// 附加到角色的第一人称网格
USkeletalMeshComponent* CharacterMesh = Character->GetMesh1P();
if (CharacterMesh)
{
AttachToComponent(CharacterMesh, FAttachmentTransformRules::KeepRelativeTransform);
SetOnlyOwnerSee(true);
SetOwnerNoSee(false);
CastShadow = false;
}
// Set up action bindings
// 设置输入映射
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
// Set the priority of the mapping to 1, so that it overrides the Jump action with the Fire action when using touch input
Subsystem->AddMappingContext(FireMappingContext, 1);
}
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent))
{
// Fire
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Triggered, this, &UBladeSmithWeaponComponent::Fire);
if (HammerMappingContext)
{
Subsystem->AddMappingContext(HammerMappingContext, 1);
}
}
}
return true;
}
void UBladeSmithWeaponComponent::SwingHammer()
{
// 播放锤击动画
if (HammerSwingAnimation && Character)
{
USkeletalMeshComponent* CharacterMesh = Character->GetMesh1P();
if (CharacterMesh)
{
CharacterMesh->PlayAnimation(HammerSwingAnimation, false);
}
}
// 延迟执行锤击检测,等待动画播放
GetWorld()->GetTimerManager().SetTimerForNextTick([this]()
{
PerformHammerHit();
});
}
FVector UBladeSmithWeaponComponent::GetHammerHeadLocation() const
{
if (Character)
{
FVector CameraLocation = Character->GetFirstPersonCameraComponent()->GetComponentLocation();
FVector CameraForward = Character->GetFirstPersonCameraComponent()->GetForwardVector();
// 计算锤子头部位置
return CameraLocation + CameraForward * HammerRange + HammerHeadOffset;
}
return FVector::ZeroVector;
}
void UBladeSmithWeaponComponent::PerformHammerHit()
{
if (!Character)
{
return;
}
// 获取锤子头部位置
FVector HammerHeadLocation = GetHammerHeadLocation();
FVector StartLocation = Character->GetFirstPersonCameraComponent()->GetComponentLocation();
// 执行射线检测
FHitResult HitResult;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(Character);
QueryParams.bTraceComplex = true;
bool bHit = GetWorld()->LineTraceSingleByChannel(
HitResult,
StartLocation,
HammerHeadLocation,
ECC_Visibility,
QueryParams
);
// 绘制调试线
FColor DebugColor = bHit ? FColor::Red : FColor::Green;
DrawDebugLine(GetWorld(), StartLocation, HammerHeadLocation, DebugColor, false, 2.0f);
if (bHit)
{
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10.0f, 8, FColor::Yellow, false, 2.0f);
}
// 处理碰撞结果
if (bHit)
{
// 播放锤击音效
if (HammerHitSound)
{
UGameplayStatics::PlaySoundAtLocation(this, HammerHitSound, HitResult.ImpactPoint, FRotator::ZeroRotator);
}
// 检查是否击中铁块
AIronBlock* IronBlock = Cast<AIronBlock>(HitResult.GetActor());
if (IronBlock)
{
HandleIronBlockHit(IronBlock, HitResult);
}
}
}
void UBladeSmithWeaponComponent::HandleIronBlockHit(AIronBlock* IronBlock, const FHitResult& HitResult)
{
if (!IronBlock)
{
return;
}
// 计算锤击力度(基于角色移动速度)
float ImpactForce = HammerForce;
if (Character)
{
FVector CharacterVelocity = Character->GetVelocity();
float SpeedMultiplier = FMath::Clamp(CharacterVelocity.Size() / 500.0f, 0.5f, 2.0f);
ImpactForce *= SpeedMultiplier;
}
// 调用铁块的锤击处理函数
IronBlock->OnHammerHit(HitResult);
UE_LOG(LogTemp, Log, TEXT("Hammer hit iron block with force: %f"), ImpactForce);
}
void UBladeSmithWeaponComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// ensure we have a character owner
if (Character != nullptr)
Super::EndPlay(EndPlayReason);
// 清理输入映射
if (Character)
{
// remove the input mapping context from the Player Controller
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->RemoveMappingContext(FireMappingContext);
if (HammerMappingContext)
{
Subsystem->RemoveMappingContext(HammerMappingContext);
}
}
}
}
// maintain the EndPlay call chain
Super::EndPlay(EndPlayReason);
}
+38 -23
View File
@@ -7,6 +7,7 @@
#include "BladeSmithWeaponComponent.generated.h"
class ABladeSmithCharacter;
class AIronBlock;
UCLASS(Blueprintable, BlueprintType, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BLADESMITH_API UBladeSmithWeaponComponent : public USkeletalMeshComponent
@@ -14,47 +15,61 @@ class BLADESMITH_API UBladeSmithWeaponComponent : public USkeletalMeshComponent
GENERATED_BODY()
public:
/** Projectile class to spawn */
UPROPERTY(EditDefaultsOnly, Category=Projectile)
TSubclassOf<class ABladeSmithProjectile> ProjectileClass;
/** Sound to play each time we fire */
/** 锤击音效 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
USoundBase* FireSound;
USoundBase* HammerHitSound;
/** AnimMontage to play each time we fire */
/** 锤击动画 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
UAnimMontage* FireAnimation;
UAnimMontage* HammerSwingAnimation;
/** Gun muzzle's offset from the characters location */
/** 锤子头部偏移 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
FVector MuzzleOffset;
FVector HammerHeadOffset;
/** MappingContext */
/** 锤击力度 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
float HammerForce = 1000.0f;
/** 锤击范围 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
float HammerRange = 200.0f;
/** 输入映射上下文 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputMappingContext* FireMappingContext;
class UInputMappingContext* HammerMappingContext;
/** Fire Input Action */
/** 锤击输入动作 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* FireAction;
class UInputAction* HammerAction;
/** Sets default values for this component's properties */
/** 设置默认值 */
UBladeSmithWeaponComponent();
/** Attaches the actor to a FirstPersonCharacter */
UFUNCTION(BlueprintCallable, Category="Weapon")
bool AttachWeapon(ABladeSmithCharacter* TargetCharacter);
/** 将锤子附加到角色 */
UFUNCTION(BlueprintCallable, Category="Hammer")
bool AttachHammer(ABladeSmithCharacter* TargetCharacter);
/** Make the weapon Fire a Projectile */
UFUNCTION(BlueprintCallable, Category="Weapon")
void Fire();
/** 执行锤击 */
UFUNCTION(BlueprintCallable, Category="Hammer")
void SwingHammer();
/** 获取锤子头部位置 */
UFUNCTION(BlueprintCallable, Category="Hammer")
FVector GetHammerHeadLocation() const;
protected:
/** Ends gameplay for this component. */
/** 组件结束游戏时的处理 */
UFUNCTION()
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
/** The Character holding this weapon*/
/** 持有此锤子的角色 */
ABladeSmithCharacter* Character;
/** 执行锤击检测 */
void PerformHammerHit();
/** 处理与铁块的碰撞 */
void HandleIronBlockHit(AIronBlock* IronBlock, const FHitResult& HitResult);
};
+55 -66
View File
@@ -1,79 +1,68 @@
#include "FDeformComputeShader.h"
// DeformationCS.cpp
#include "RenderGraphUtils.h"
#include "ShaderParameterUtils.h"
#include "GlobalShader.h"
#include "ShaderParameterStruct.h"
#include "RHIStaticStates.h"
#include "Shader.h"
#include "GlobalShader.h"
#include "RHICommandList.h"
IMPLEMENT_GLOBAL_SHADER(FDeformationCS, "/CustomShaders/DeformationCS.usf", "MainCS", SF_Compute);
#include "RHIResources.h"
#include "ShaderParameterUtils.h"
// 全局参数存储
FThreadSafeDeformationParams GDeformationParams;
// 实现Compute Shader
IMPLEMENT_GLOBAL_SHADER(FDeformationCS, "/Shaders/Private/DeformationCS.usf", "MainCS", SF_Compute);
// 分派函数实现
void FDeformationCS::Dispatch(
FRHICommandListImmediate& RHICmdList,
const FDeformationCSDispatchParams& Params)
{
// 获取Shader引用
// 创建参数结构
FParameters Parameters;
Parameters.ImpactPoint = FVector3f(Params.ImpactPoint);
Parameters.ImpactNormal = FVector3f(Params.ImpactNormal);
Parameters.ImpactForce = Params.ImpactForce;
Parameters.DeformationRadius = Params.DeformationRadius;
Parameters.Plasticity = Params.Plasticity;
Parameters.InputTexture = Params.InputTexture;
Parameters.OutputTexture = Params.OutputTexture;
Parameters.TextureSize = Params.TextureSize;
Parameters.UpdateRegionMin = FIntVector(Params.UpdateRegion.Min.X, Params.UpdateRegion.Min.Y, 0);
Parameters.UpdateRegionSize = FIntVector(Params.UpdateRegion.Width(), Params.UpdateRegion.Height(), 1);
// 计算线程组数量
const int32 ThreadGroupSizeX = 8;
const int32 ThreadGroupSizeY = 8;
const int32 ThreadGroupSizeZ = 1;
const int32 GroupCountX = FMath::DivideAndRoundUp(Params.UpdateRegion.Width(), ThreadGroupSizeX);
const int32 GroupCountY = FMath::DivideAndRoundUp(Params.UpdateRegion.Height(), ThreadGroupSizeY);
const int32 GroupCountZ = 1;
// 分派Compute Shader
TShaderMapRef<FDeformationCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
// 设置参数
FParameters ShaderParams;
ShaderParams.ImpactPoint = FVector3f(Params.ImpactPoint);
ShaderParams.ImpactNormal = FVector3f(Params.ImpactNormal);
ShaderParams.ImpactForce = Params.ImpactForce;
ShaderParams.DeformationRadius = Params.DeformationRadius;
ShaderParams.Plasticity = Params.Plasticity;
ShaderParams.InputTexture = Params.InputTexture;
FRHIResourceCreateInfo CreateInfo(TEXT("DeformationCS_UAV"));
ShaderParams.OutputTexture = RHICmdList.CreateUnorderedAccessView(Params.OutputTexture,0);
ShaderParams.TextureSize = Params.TextureSize;
ShaderParams.UpdateRegionMin = FIntVector(Params.UpdateRegion.Min.X, Params.UpdateRegion.Min.Y, 0);
ShaderParams.UpdateRegionSize = FIntVector(Params.UpdateRegion.Width(), Params.UpdateRegion.Height(), 1);
// 设置计算Shader
FComputeShaderUtils::Dispatch(
RHICmdList,
ComputeShader,
ShaderParams,
FIntVector(
FMath::DivideAndRoundUp(Params.UpdateRegion.Width(), 8),
FMath::DivideAndRoundUp(Params.UpdateRegion.Height(), 8),
1
)
);
SetComputePipelineState(RHICmdList, ComputeShader.GetComputeShader());
SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetComputeShader(), Parameters);
RHICmdList.DispatchComputeShader(GroupCountX, GroupCountY, GroupCountZ);
}
// 渲染线程入口点
void DispatchDeformationComputeShaders(FRHICommandListImmediate& RHICmdList)
// 线程安全参数管理
void FThreadSafeDeformationParams::AddParams(const FDeformationCSDispatchParams& NewParams)
{
FDeformationCSDispatchParams Params;
while(GDeformationParams.ConsumeParams(Params))
FScopeLock Lock(&ParamsCriticalSection);
PendingParams.Add(NewParams);
}
bool FThreadSafeDeformationParams::ConsumeParams(FDeformationCSDispatchParams& OutParams)
{
FScopeLock Lock(&ParamsCriticalSection);
if (PendingParams.Num() > 0)
{
FDeformationCS::Dispatch(RHICmdList, Params);
// 复制结果回源纹理
if(Params.InputTexture && Params.OutputTexture)
{
FRHICopyTextureInfo CopyInfo;
CopyInfo.SourcePosition = FIntVector(Params.UpdateRegion.Min.X, Params.UpdateRegion.Min.Y, 0);
CopyInfo.DestPosition = CopyInfo.SourcePosition;
CopyInfo.Size = FIntVector(Params.UpdateRegion.Width(), Params.UpdateRegion.Height(), 1);
RHICmdList.CopyTexture(
Params.OutputTexture,
Params.InputTexture,
CopyInfo
);
}
OutParams = PendingParams[0];
PendingParams.RemoveAt(0);
return true;
}
}
// 注册到渲染线程
void SetupDeformationShutdown();
FAutoConsoleCommand RegisterDeformationCmd(
TEXT("r.Deformation.Compute"),
TEXT(""),
FConsoleCommandDelegate::CreateStatic(SetupDeformationShutdown)
);
void SetupDeformationShutdown()
{
// 每帧结束时调用
ENQUEUE_RENDER_COMMAND(DeformationShutdown)(
[](FRHICommandListImmediate& RHICmdList) {
DispatchDeformationComputeShaders(RHICmdList);
});
return false;
}
+3 -18
View File
@@ -21,7 +21,7 @@ struct FDeformationCSDispatchParams
// 纹理资源
FTextureRHIRef InputTexture;
FTextureRHIRef OutputTexture;
FUnorderedAccessViewRHIRef OutputTexture;
// 更新区域 (优化部分更新)
FIntRect UpdateRegion;
@@ -44,23 +44,8 @@ struct FThreadSafeDeformationParams
FCriticalSection ParamsCriticalSection;
TArray<FDeformationCSDispatchParams> PendingParams;
void AddParams(const FDeformationCSDispatchParams& NewParams)
{
FScopeLock Lock(&ParamsCriticalSection);
PendingParams.Add(NewParams);
}
bool ConsumeParams(FDeformationCSDispatchParams& OutParams)
{
FScopeLock Lock(&ParamsCriticalSection);
if(PendingParams.Num() > 0)
{
OutParams = PendingParams[0];
PendingParams.RemoveAt(0);
return true;
}
return false;
}
void AddParams(const FDeformationCSDispatchParams& NewParams);
bool ConsumeParams(FDeformationCSDispatchParams& OutParams);
};
// 全局参数存储
extern FThreadSafeDeformationParams GDeformationParams;
+270 -60
View File
@@ -27,7 +27,7 @@ AIronBlock::AIronBlock(): StaticMeshComp(nullptr), PositionTexture0(nullptr), Po
void AIronBlock::BeginPlay()
{
Super::BeginPlay();
CalculateLocalBounds();
//CalculateLocalBounds();
InitializePositionTexture();
}
@@ -41,35 +41,55 @@ UTexture2D* AIronBlock::CreatePositionTexture(const FString& TexName, int32 Size
);
// 设置基本属性
NewTexture->Filter = TF_Nearest;
//NewTexture->Filter = TF_Nearest;
NewTexture->SRGB = false;
NewTexture->CompressionSettings = TC_HDR;
NewTexture->MipGenSettings = TMGS_NoMipmaps;
NewTexture->NeverStream = true;
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_A32B32G32R32F;
NewTexture->GetPlatformData()->PixelFormat = PF_R32_FLOAT;
// 添加初始Mip
FTexture2DMipMap* Mip = new FTexture2DMipMap();
NewTexture->GetPlatformData()->Mips.Add(Mip);
//NewTexture->GetPlatformData()->Mips.Reset();
Mip->SizeX = Size;
Mip->SizeY = Size;
// 如果有初始数据,填充纹理
if (InitialData.Num() > 0)
{
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();
}
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;
}
@@ -77,13 +97,17 @@ void AIronBlock::OnEndFrameInitializeTextures()
{
// 确保纹理资源已创建
if (PositionTexture0 && PositionTexture0->GetResource() &&
PositionTexture1 && PositionTexture1->GetResource() &&
PositionRenderTarget && PositionRenderTarget->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();
@@ -115,6 +139,56 @@ void AIronBlock::EndPlay(const EEndPlayReason::Type EndPlayReason)
Super::EndPlay(EndPlayReason);
}
// void CreateTexture()
// {
// 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;
@@ -123,15 +197,42 @@ void AIronBlock::InitializeTexturePair(int32 Index)
if (!Texture || !Texture->GetResource()) return;
// 获取纹理引用
TexturePairs[Index].RHITexture = Texture->GetResource()->TextureRHI;
FTextureRHIRef RHITexture = Texture->GetResource()->GetTexture2DRHI();
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);
@@ -166,38 +267,106 @@ void AIronBlock::GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions)
void AIronBlock::InitializePositionTexture()
{
// 获取顶点数据
// 创建静态网格组件
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;
const int32 TexSize = FMath::RoundUpToPowerOfTwo(FMath::Sqrt((float)VertexPositions.Num()));
//int32 TexSize = 512;
InitialData.SetNumZeroed(TexSize * TexSize);
for (int32 i = 0; i < VertexPositions.Num() && i < InitialData.Num(); i++)
InitialData.SetNum(TextureSize * TextureSize);
// 初始化纹理数据
for (int32 Y = 0; Y < TextureSize; ++Y)
{
InitialData[i] = FLinearColor(VertexPositions[i]);
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("PosTex0", TexSize, InitialData);
PositionTexture1 = CreatePositionTexture("PosTex1", TexSize, InitialData);
// 初始化纹理对
TexturePairs[0].RHITexture = PositionTexture0->GetResource()->TextureRHI;
TexturePairs[1].RHITexture = PositionTexture1->GetResource()->TextureRHI;
// 创建纹理对
PositionTexture0 = CreatePositionTexture(TEXT("PositionTexture0"), TextureSize, InitialData);
PositionTexture1 = CreatePositionTexture(TEXT("PositionTexture1"), TextureSize, InitialData);
// 创建渲染目标
PositionRenderTarget = NewObject<UTextureRenderTarget2D>(this);
PositionRenderTarget->RenderTargetFormat = RTF_RGBA32f;
PositionRenderTarget->bCanCreateUAV = true;
PositionRenderTarget->InitAutoFormat(TexSize, TexSize);
PositionRenderTarget->SizeX = TextureSize;
PositionRenderTarget->SizeY = TextureSize;
PositionRenderTarget->RenderTargetFormat = RTF_RGBA16f;
PositionRenderTarget->bAutoGenerateMips = false;
PositionRenderTarget->UpdateResource();
// 注册纹理初始化委托
TextureInitHandle = FCoreDelegates::OnEndFrame.AddUObject(this, &AIronBlock::OnEndFrameInitializeTextures);
// 设置材质实例
// 设置变形材质
SetupDeformationMaterial();
// 初始化纹理对
InitializeTexturePair(0);
InitializeTexturePair(1);
// 延迟初始化纹理资源
TextureInitHandle = FDelegateHandle();
GetWorld()->GetTimerManager().SetTimerForNextTick([this]()
{
OnEndFrameInitializeTextures();
});
}
// 创建UAV的安全方法
FUnorderedAccessViewRHIRef AIronBlock::CreateSafeUAV(UTextureRenderTarget2D* RenderTarget)
{
if (!RenderTarget || !RenderTarget->GetResource())
return nullptr;
FTextureRHIRef TextureRHI = RenderTarget->GetResource()->GetTexture2DRHI();
if (!TextureRHI.IsValid())
return nullptr;
// 创建UAV描述
FUnorderedAccessViewRHIRef UAV;
ENQUEUE_RENDER_COMMAND(CreateUAVCommand)(
[TextureRHI, &UAV](FRHICommandListImmediate& RHICmdList)
{
FRHIViewDesc::FTextureUAV::FInitializer ViewDesc = FRHIViewDesc::CreateTextureUAV();
ViewDesc.SetMipLevel(0);
ViewDesc.SetPlane(ERHITexturePlane::Primary);
ViewDesc.SetFormat(PF_A32B32G32R32F);
UAV = RHICmdList.CreateUnorderedAccessView(TextureRHI, ViewDesc);
}
);
// 等待渲染命令完成
FlushRenderingCommands();
return UAV;
}
void AIronBlock::CalculateLocalBounds()
@@ -230,12 +399,30 @@ void AIronBlock::CalculateLocalBounds()
void AIronBlock::SetupDeformationMaterial()
{
DynMaterial = UMaterialInstanceDynamic::Create(StaticMeshComp->GetMaterial(0), this);
StaticMeshComp->SetMaterial(0, DynMaterial);
DynMaterial->SetTextureParameterValue("PositionTexture", PositionTexture0);
DynMaterial->SetScalarParameterValue("EnableDeformation", 1.0f);
// 创建动态材质实例
if (StaticMeshComp)
{
// 加载基础材质
UMaterial* BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
if (BaseMaterial)
{
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
StaticMeshComp->SetMaterial(0, DynMaterial);
// 设置初始参数
if (DynMaterial)
{
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), PositionTexture0);
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
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)
@@ -307,10 +494,12 @@ void AIronBlock::ExecuteDeformationCS()
UE_LOG(LogTemp, Error, TEXT("Position textures not initialized!"));
return;
}
// 获取当前纹理资源
UTexture2D* CurrentTex = (CurrentTextureIndex == 0) ? PositionTexture0 : PositionTexture1;
UTexture2D* PrevTex = (CurrentTextureIndex == 0) ? PositionTexture1 : PositionTexture0;
// 获取纹理RHI资源 - 使用GetResource()方法
// 获取纹理RHI资源
FTextureRHIRef InputRHI = GetTextureRHI(PrevTex);
FTextureRHIRef OutputRHI = GetRenderTargetRHI(PositionRenderTarget);
@@ -319,6 +508,7 @@ void AIronBlock::ExecuteDeformationCS()
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!"));
return;
}
// 计算纹理UV坐标
const int32 TexSize = PositionRenderTarget->SizeX;
FVector2D ImpactUV(
@@ -342,20 +532,40 @@ void AIronBlock::ExecuteDeformationCS()
Params.DeformationRadius = CurrentDeformationRadius;
Params.Plasticity = CurrentPlasticity;
Params.InputTexture = InputRHI;
Params.OutputTexture = OutputRHI;
Params.UpdateRegion = UpdateRegion;
Params.TextureSize = FIntVector(TexSize, TexSize, 0);
// 提交到渲染线程
GDeformationParams.AddParams(Params);
// 创建UAV用于输出
FUnorderedAccessViewRHIRef OutputUAV;
ENQUEUE_RENDER_COMMAND(CreateOutputUAV)(
[OutputRHI, &OutputUAV](FRHICommandListImmediate& RHICmdList)
{
FRHIViewDesc::FTextureUAV::FInitializer ViewDesc = FRHIViewDesc::CreateTextureUAV();
ViewDesc.SetMipLevel(0);
ViewDesc.SetPlane(ERHITexturePlane::Primary);
ViewDesc.SetFormat(PF_A32B32G32R32F);
OutputUAV = RHICmdList.CreateUnorderedAccessView(OutputRHI, ViewDesc);
}
);
FlushRenderingCommands();
Params.OutputTexture = OutputUAV;
Params.UpdateRegion = UpdateRegion;
Params.TextureSize = FIntVector(TexSize, TexSize, 1);
// 在渲染线程中执行Compute Shader
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS)(
[Params](FRHICommandListImmediate& RHICmdList)
{
FDeformationCS::Dispatch(RHICmdList, Params);
});
// 更新材质参数
DynMaterial->SetTextureParameterValue("PositionTexture", CurrentTex);
// 触发碰撞体更新 (异步)
GetWorld()->GetTimerManager().SetTimerForNextTick([this, UpdateRegion](){
UpdateCollisionAsync(UpdateRegion);
});
if (DynMaterial)
{
DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), CurrentTex);
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
}
}
// 异步更新物理碰撞体
void AIronBlock::UpdateCollisionAsync(const FIntRect& UpdateRegion)
+6 -3
View File
@@ -29,6 +29,9 @@ public:
// Sets default values for this actor's properties
AIronBlock();
UFUNCTION(BlueprintCallable)
void OnHammerHit(const FHitResult& HitResult);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
@@ -37,10 +40,9 @@ protected:
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
UTexture2D* CreatePositionTexture(const FString& TexName, int32 Size, const TArray<FLinearColor>& InitialData);
void InitializePositionTexture();
FUnorderedAccessViewRHIRef CreateSafeUAV(UTextureRenderTarget2D* RenderTarget);
void OnEndFrameInitializeTextures();
void SetupDeformationMaterial();
UFUNCTION(BlueprintCallable)
void OnHammerHit(const FHitResult& HitResult);
FTextureRHIRef GetTextureRHI(UTexture2D* Texture);
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
private:
@@ -57,11 +59,12 @@ private:
// UAV 资源引用
FUnorderedAccessViewRHIRef UAV;
//FRDGTextureUAVRef UAV;
// 安全释放资源
void ReleaseRHI()
{
UAV.SafeRelease();
//UAV->GetRHI()->Release();
RHITexture.SafeRelease();
}
};