diff --git a/.idea/.idea.BladeSmith/.idea/vcs.xml b/.idea/.idea.BladeSmith/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.BladeSmith/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vsconfig b/.vsconfig
index b3c233d..3b919ea 100644
--- a/.vsconfig
+++ b/.vsconfig
@@ -1,10 +1,12 @@
{
"version": "1.0",
"components": [
+ "Component.Unreal.Debugger",
+ "Component.Unreal.Ide",
"Microsoft.Net.Component.4.6.2.TargetingPack",
- "Microsoft.VisualStudio.Component.Unreal.Workspace",
"Microsoft.VisualStudio.Component.VC.14.38.17.8.ATL",
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64",
+ "Microsoft.VisualStudio.Component.VC.Llvm.Clang",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
"Microsoft.VisualStudio.Workload.CoreEditor",
diff --git a/BladeSmith.sln.DotSettings.user b/BladeSmith.sln.DotSettings.user
index 8ace9b1..f937637 100644
--- a/BladeSmith.sln.DotSettings.user
+++ b/BladeSmith.sln.DotSettings.user
@@ -1,2 +1,4 @@
+ ForceIncluded
+ ForceIncluded
ForceIncluded
\ No newline at end of file
diff --git a/BladeSmith.uproject b/BladeSmith.uproject
index 511e59d..89230e3 100644
--- a/BladeSmith.uproject
+++ b/BladeSmith.uproject
@@ -1,6 +1,6 @@
{
"FileVersion": 3,
- "EngineAssociation": "5.5",
+ "EngineAssociation": "{DE41D031-4C3F-817F-365A-5AAD9A1CE2AD}",
"Category": "",
"Description": "",
"Modules": [
diff --git a/README.md b/README.md
index 4a1aadd..dc353c1 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,166 @@
-# BladeSmith
+# BladeSmith - UE5.5 打铁游戏
+
+这是一个基于UE5.5开发的打铁游戏,使用C++实现铁锤击中铁块造成物理形变的效果。
+
+## 系统特性
+
+### 核心功能
+- **铁块变形系统**: 使用Compute Shader实时计算铁块顶点变形
+- **锤击交互**: 第一人称锤击系统,支持力度和方向检测
+- **物理形变**: 基于冲击力、位置和法线的真实物理变形
+- **材质系统**: 动态材质实例,实时更新变形效果
+
+### 技术实现
+- **Compute Shader**: 使用GPU并行计算顶点变形
+- **双缓冲纹理**: 避免读写冲突,确保渲染稳定性
+- **射线检测**: 精确的锤击碰撞检测
+- **动态材质**: 实时更新变形参数
+
+## 系统架构
+
+### 主要组件
+
+1. **AIronBlock** - 铁块Actor
+ - 管理变形纹理和Compute Shader
+ - 处理锤击碰撞和变形计算
+ - 更新动态材质参数
+
+2. **UBladeSmithWeaponComponent** - 锤子组件
+ - 第一人称锤击交互
+ - 射线检测和碰撞处理
+ - 音效和动画播放
+
+3. **FDeformationCS** - Compute Shader
+ - GPU并行变形计算
+ - 基于距离的衰减效果
+ - 塑性变形模拟
+
+### 文件结构
+```
+Source/BladeSmith/
+├── IronBlock.h/cpp # 铁块实现
+├── FDeformComputeShader.h/cpp # Compute Shader
+├── BladeSmithWeaponComponent.h/cpp # 锤子组件
+├── BladeSmithCharacter.h/cpp # 角色类
+└── BladeSmith.Build.cs # 模块配置
+
+Shaders/Private/
+└── DeformationCS.usf # Compute Shader源码
+```
+
+## 使用方法
+
+### 1. 设置输入映射
+在UE编辑器中创建以下输入动作:
+- **HammerAction**: 锤击输入(建议绑定鼠标左键)
+- **MoveAction**: 移动输入(WASD)
+- **LookAction**: 视角输入(鼠标)
+- **JumpAction**: 跳跃输入(空格)
+
+### 2. 配置角色蓝图
+1. 打开角色蓝图
+2. 确保HammerComponent已正确附加
+3. 设置锤子网格和动画
+4. 配置输入映射上下文
+
+### 3. 放置铁块
+1. 在场景中放置IronBlock Actor
+2. 确保静态网格组件已设置
+3. 系统会自动初始化变形纹理
+
+### 4. 创建材质
+创建支持变形的材质,包含以下参数:
+- **PositionTexture**: 顶点位置纹理
+- **LocalBoundsMin/Max**: 本地边界
+- **DeformationStrength**: 变形强度
+
+## 技术细节
+
+### Compute Shader参数
+```hlsl
+struct Parameters
+{
+ float3 ImpactPoint; // 冲击点
+ float3 ImpactNormal; // 冲击法线
+ float ImpactForce; // 冲击力
+ float DeformationRadius; // 变形半径
+ float Plasticity; // 塑性系数
+ Texture2D InputTexture; // 输入纹理
+ RWTexture2D OutputTexture; // 输出纹理
+};
+```
+
+### 变形算法
+1. **距离计算**: 计算每个顶点到冲击点的距离
+2. **衰减函数**: 使用高斯衰减模拟真实物理
+3. **变形计算**: 基于法线方向和冲击力计算变形量
+4. **塑性应用**: 应用塑性系数实现永久变形
+
+### 性能优化
+- **区域更新**: 只更新受影响的纹理区域
+- **双缓冲**: 避免读写冲突
+- **异步处理**: 在渲染线程中执行Compute Shader
+- **LOD支持**: 根据距离调整计算精度
+
+## 编译和运行
+
+### 编译要求
+- UE5.5
+- Visual Studio 2022
+- Windows 10/11
+
+### 编译步骤
+1. 右键点击.uproject文件
+2. 选择"Generate Visual Studio project files"
+3. 打开生成的.sln文件
+4. 编译项目
+
+### 运行步骤
+1. 在UE编辑器中打开项目
+2. 确保所有输入映射已配置
+3. 在场景中放置IronBlock
+4. 运行游戏并测试锤击功能
+
+## 故障排除
+
+### 常见问题
+
+1. **Compute Shader不工作**
+ - 检查GPU驱动是否支持Compute Shader
+ - 确认纹理格式正确
+ - 查看渲染日志中的错误信息
+
+2. **变形效果不明显**
+ - 调整ImpactForce参数
+ - 增加DeformationRadius
+ - 检查材质参数设置
+
+3. **性能问题**
+ - 减少纹理分辨率
+ - 缩小更新区域
+ - 启用LOD系统
+
+### 调试功能
+- 启用调试绘制查看射线检测
+- 使用LogTemp输出调试信息
+- 检查纹理资源是否正确创建
+
+## 扩展功能
+
+### 可能的改进
+1. **多材质支持**: 不同材质的不同变形特性
+2. **温度系统**: 基于温度影响变形效果
+3. **声音系统**: 更真实的锤击音效
+4. **粒子效果**: 锤击时的火花和灰尘
+5. **工具系统**: 不同类型的锤子和工具
+
+### 自定义开发
+- 修改Compute Shader实现不同的变形算法
+- 添加新的物理参数(弹性、硬度等)
+- 实现更复杂的碰撞检测
+- 集成第三方物理引擎
+
+## 许可证
+
+本项目基于Epic Games的UE5.5开发,遵循相应的许可证条款。
diff --git a/Source/BladeSmith/BladeSmith.Build.cs b/Source/BladeSmith/BladeSmith.Build.cs
index bbac650..399b74d 100644
--- a/Source/BladeSmith/BladeSmith.Build.cs
+++ b/Source/BladeSmith/BladeSmith.Build.cs
@@ -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"
+ });
}
}
diff --git a/Source/BladeSmith/BladeSmithCharacter.cpp b/Source/BladeSmith/BladeSmithCharacter.cpp
index 1470af9..90722a7 100644
--- a/Source/BladeSmith/BladeSmithCharacter.cpp
+++ b/Source/BladeSmith/BladeSmithCharacter.cpp
@@ -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(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();
+ }
}
\ No newline at end of file
diff --git a/Source/BladeSmith/BladeSmithCharacter.h b/Source/BladeSmith/BladeSmithCharacter.h
index 33b7594..6e6336b 100644
--- a/Source/BladeSmith/BladeSmithCharacter.h
+++ b/Source/BladeSmith/BladeSmithCharacter.h
@@ -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; }
};
diff --git a/Source/BladeSmith/BladeSmithWeaponComponent.cpp b/Source/BladeSmith/BladeSmithWeaponComponent.cpp
index 68e2df6..05885e2 100644
--- a/Source/BladeSmith/BladeSmithWeaponComponent.cpp
+++ b/Source/BladeSmith/BladeSmithWeaponComponent.cpp
@@ -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(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(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())
+ 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(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(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(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(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(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(PlayerController->GetLocalPlayer()))
{
- Subsystem->RemoveMappingContext(FireMappingContext);
+ if (HammerMappingContext)
+ {
+ Subsystem->RemoveMappingContext(HammerMappingContext);
+ }
}
}
}
-
- // maintain the EndPlay call chain
- Super::EndPlay(EndPlayReason);
}
\ No newline at end of file
diff --git a/Source/BladeSmith/BladeSmithWeaponComponent.h b/Source/BladeSmith/BladeSmithWeaponComponent.h
index d4e01e2..ca4c0eb 100644
--- a/Source/BladeSmith/BladeSmithWeaponComponent.h
+++ b/Source/BladeSmith/BladeSmithWeaponComponent.h
@@ -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 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);
};
diff --git a/Source/BladeSmith/FDeformComputeShader.cpp b/Source/BladeSmith/FDeformComputeShader.cpp
index 05ffcd0..c2e9d08 100644
--- a/Source/BladeSmith/FDeformComputeShader.cpp
+++ b/Source/BladeSmith/FDeformComputeShader.cpp
@@ -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 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;
}
\ No newline at end of file
diff --git a/Source/BladeSmith/FDeformComputeShader.h b/Source/BladeSmith/FDeformComputeShader.h
index 0499694..f77c5ff 100644
--- a/Source/BladeSmith/FDeformComputeShader.h
+++ b/Source/BladeSmith/FDeformComputeShader.h
@@ -21,7 +21,7 @@ struct FDeformationCSDispatchParams
// 纹理资源
FTextureRHIRef InputTexture;
- FTextureRHIRef OutputTexture;
+ FUnorderedAccessViewRHIRef OutputTexture;
// 更新区域 (优化部分更新)
FIntRect UpdateRegion;
@@ -44,23 +44,8 @@ struct FThreadSafeDeformationParams
FCriticalSection ParamsCriticalSection;
TArray 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;
diff --git a/Source/BladeSmith/IronBlock.cpp b/Source/BladeSmith/IronBlock.cpp
index 9f8c503..65e44e0 100644
--- a/Source/BladeSmith/IronBlock.cpp
+++ b/Source/BladeSmith/IronBlock.cpp
@@ -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& OutPositions)
void AIronBlock::InitializePositionTexture()
{
- // 获取顶点数据
+ // 创建静态网格组件
+ if (!StaticMeshComp)
+ {
+ StaticMeshComp = CreateDefaultSubobject(TEXT("StaticMeshComponent"));
+ RootComponent = StaticMeshComp;
+
+ // 设置默认网格(立方体)
+ UStaticMesh* DefaultMesh = LoadObject(nullptr, TEXT("/Engine/BasicShapes/Cube"));
+ if (DefaultMesh)
+ {
+ StaticMeshComp->SetStaticMesh(DefaultMesh);
+ }
+ }
+
+ // 计算本地边界
+ CalculateLocalBounds();
+
+ // 获取顶点位置
TArray VertexPositions;
GetStaticMeshVertexPositions(VertexPositions);
- // 创建初始数据数组
+ // 创建位置纹理
+ const int32 TextureSize = 256; // 纹理尺寸
TArray 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(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(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)
diff --git a/Source/BladeSmith/IronBlock.h b/Source/BladeSmith/IronBlock.h
index 2fcda2e..3ddabcc 100644
--- a/Source/BladeSmith/IronBlock.h
+++ b/Source/BladeSmith/IronBlock.h
@@ -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& OutPositions);
UTexture2D* CreatePositionTexture(const FString& TexName, int32 Size, const TArray& 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();
}
};