使用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
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+3 -1
View File
@@ -1,10 +1,12 @@
{ {
"version": "1.0", "version": "1.0",
"components": [ "components": [
"Component.Unreal.Debugger",
"Component.Unreal.Ide",
"Microsoft.Net.Component.4.6.2.TargetingPack", "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.ATL",
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64", "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.VC.Tools.x86.x64",
"Microsoft.VisualStudio.Component.Windows11SDK.22621", "Microsoft.VisualStudio.Component.Windows11SDK.22621",
"Microsoft.VisualStudio.Workload.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor",
+2
View File
@@ -1,2 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAdpcmAudioDecoder_002EBuild_002Ecs_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E5_003FEngine_003FSource_003FRuntime_003FAdpcmAudioDecoder_003FModule_003FAdpcmAudioDecoder_002EBuild_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGajuzad_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FXexaveh_003FGajuzad_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AZilegoz_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FZucifip_003FZilegoz_002Easm/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AZilegoz_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FZucifip_003FZilegoz_002Easm/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"FileVersion": 3, "FileVersion": 3,
"EngineAssociation": "5.5", "EngineAssociation": "{DE41D031-4C3F-817F-365A-5AAD9A1CE2AD}",
"Category": "", "Category": "",
"Description": "", "Description": "",
"Modules": [ "Modules": [
+165 -1
View File
@@ -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开发,遵循相应的许可证条款。
+14 -1
View File
@@ -8,6 +8,19 @@ public class BladeSmith : ModuleRules
{ {
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 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 "BladeSmithCharacter.h"
#include "BladeSmithProjectile.h" #include "BladeSmithProjectile.h"
#include "BladeSmithWeaponComponent.h"
#include "Animation/AnimInstance.h" #include "Animation/AnimInstance.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h" #include "Components/CapsuleComponent.h"
@@ -35,6 +36,9 @@ ABladeSmithCharacter::ABladeSmithCharacter()
Mesh1P->CastShadow = false; Mesh1P->CastShadow = false;
Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f)); Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f));
// Create hammer component
HammerComponent = CreateDefaultSubobject<UBladeSmithWeaponComponent>(TEXT("HammerComponent"));
HammerComponent->SetupAttachment(Mesh1P);
} }
//////////////////////////////////////////////////////////////////////////// Input //////////////////////////////////////////////////////////////////////////// Input
@@ -67,6 +71,9 @@ void ABladeSmithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInpu
// Looking // Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ABladeSmithCharacter::Look); EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ABladeSmithCharacter::Look);
// Hammer
EnhancedInputComponent->BindAction(HammerAction, ETriggerEvent::Started, this, &ABladeSmithCharacter::Hammer);
} }
else else
{ {
@@ -74,7 +81,6 @@ void ABladeSmithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInpu
} }
} }
void ABladeSmithCharacter::Move(const FInputActionValue& Value) void ABladeSmithCharacter::Move(const FInputActionValue& Value)
{ {
// input is a Vector2D // input is a Vector2D
@@ -100,3 +106,12 @@ void ABladeSmithCharacter::Look(const FInputActionValue& Value)
AddControllerPitchInput(LookAxisVector.Y); 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 UCameraComponent;
class UInputAction; class UInputAction;
class UInputMappingContext; class UInputMappingContext;
class UBladeSmithWeaponComponent;
struct FInputActionValue; struct FInputActionValue;
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
@@ -29,6 +30,10 @@ class ABladeSmithCharacter : public ACharacter
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
UCameraComponent* FirstPersonCameraComponent; UCameraComponent* FirstPersonCameraComponent;
/** 锤子组件 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Weapon, meta = (AllowPrivateAccess = "true"))
UBladeSmithWeaponComponent* HammerComponent;
/** MappingContext */ /** MappingContext */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputMappingContext* DefaultMappingContext; UInputMappingContext* DefaultMappingContext;
@@ -45,6 +50,10 @@ class ABladeSmithCharacter : public ACharacter
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* LookAction; class UInputAction* LookAction;
/** Hammer Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* HammerAction;
public: public:
ABladeSmithCharacter(); ABladeSmithCharacter();
@@ -55,6 +64,9 @@ protected:
/** Called for looking input */ /** Called for looking input */
void Look(const FInputActionValue& Value); void Look(const FInputActionValue& Value);
/** Called for hammer input */
void Hammer(const FInputActionValue& Value);
protected: protected:
// APawn interface // APawn interface
virtual void NotifyControllerChanged() override; virtual void NotifyControllerChanged() override;
@@ -66,6 +78,8 @@ public:
USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; } USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
/** Returns FirstPersonCameraComponent subobject **/ /** Returns FirstPersonCameraComponent subobject **/
UCameraComponent* GetFirstPersonCameraComponent() const { return FirstPersonCameraComponent; } 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 "BladeSmithWeaponComponent.h"
#include "BladeSmithCharacter.h" #include "BladeSmithCharacter.h"
#include "BladeSmithProjectile.h" #include "IronBlock.h"
#include "GameFramework/PlayerController.h" #include "Animation/AnimInstance.h"
#include "Camera/PlayerCameraManager.h" #include "Components/SkeletalMeshComponent.h"
#include "Kismet/GameplayStatics.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "Animation/AnimInstance.h" #include "InputActionValue.h"
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/World.h" #include "Engine/World.h"
#include "DrawDebugHelpers.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "Camera/CameraComponent.h"
// Sets default values for this component's properties // Sets default values for this component's properties
UBladeSmithWeaponComponent::UBladeSmithWeaponComponent() 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;
} }
bool UBladeSmithWeaponComponent::AttachHammer(ABladeSmithCharacter* TargetCharacter)
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)
{ {
Character = TargetCharacter; Character = TargetCharacter;
if (Character == nullptr)
// Check that the character is valid, and has no weapon component yet
if (Character == nullptr || Character->GetInstanceComponents().FindItemByClass<UBladeSmithWeaponComponent>())
{ {
return false; return false;
} }
// Attach the weapon to the First Person Character // 附加到角色的第一人称网格
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true); USkeletalMeshComponent* CharacterMesh = Character->GetMesh1P();
AttachToComponent(Character->GetMesh1P(), AttachmentRules, FName(TEXT("GripPoint"))); if (CharacterMesh)
{
AttachToComponent(CharacterMesh, FAttachmentTransformRules::KeepRelativeTransform);
SetOnlyOwnerSee(true);
SetOwnerNoSee(false);
CastShadow = false;
}
// Set up action bindings // 设置输入映射
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController())) if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{ {
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) 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 if (HammerMappingContext)
Subsystem->AddMappingContext(FireMappingContext, 1); {
} Subsystem->AddMappingContext(HammerMappingContext, 1);
}
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent))
{
// Fire
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Triggered, this, &UBladeSmithWeaponComponent::Fire);
} }
} }
return true; 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) void UBladeSmithWeaponComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{ {
// ensure we have a character owner Super::EndPlay(EndPlayReason);
if (Character != nullptr)
// 清理输入映射
if (Character)
{ {
// remove the input mapping context from the Player Controller
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController())) if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{ {
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) 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" #include "BladeSmithWeaponComponent.generated.h"
class ABladeSmithCharacter; class ABladeSmithCharacter;
class AIronBlock;
UCLASS(Blueprintable, BlueprintType, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) UCLASS(Blueprintable, BlueprintType, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BLADESMITH_API UBladeSmithWeaponComponent : public USkeletalMeshComponent class BLADESMITH_API UBladeSmithWeaponComponent : public USkeletalMeshComponent
@@ -14,47 +15,61 @@ class BLADESMITH_API UBladeSmithWeaponComponent : public USkeletalMeshComponent
GENERATED_BODY() GENERATED_BODY()
public: 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) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
USoundBase* FireSound; USoundBase* HammerHitSound;
/** AnimMontage to play each time we fire */ /** 锤击动画 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
UAnimMontage* FireAnimation; UAnimMontage* HammerSwingAnimation;
/** Gun muzzle's offset from the characters location */ /** 锤子头部偏移 */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay) 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")) 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")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* FireAction; class UInputAction* HammerAction;
/** Sets default values for this component's properties */ /** 设置默认值 */
UBladeSmithWeaponComponent(); UBladeSmithWeaponComponent();
/** Attaches the actor to a FirstPersonCharacter */ /** 将锤子附加到角色 */
UFUNCTION(BlueprintCallable, Category="Weapon") UFUNCTION(BlueprintCallable, Category="Hammer")
bool AttachWeapon(ABladeSmithCharacter* TargetCharacter); bool AttachHammer(ABladeSmithCharacter* TargetCharacter);
/** Make the weapon Fire a Projectile */ /** 执行锤击 */
UFUNCTION(BlueprintCallable, Category="Weapon") UFUNCTION(BlueprintCallable, Category="Hammer")
void Fire(); void SwingHammer();
/** 获取锤子头部位置 */
UFUNCTION(BlueprintCallable, Category="Hammer")
FVector GetHammerHeadLocation() const;
protected: protected:
/** Ends gameplay for this component. */ /** 组件结束游戏时的处理 */
UFUNCTION() UFUNCTION()
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private: private:
/** The Character holding this weapon*/ /** 持有此锤子的角色 */
ABladeSmithCharacter* Character; ABladeSmithCharacter* Character;
/** 执行锤击检测 */
void PerformHammerHit();
/** 处理与铁块的碰撞 */
void HandleIronBlockHit(AIronBlock* IronBlock, const FHitResult& HitResult);
}; };
+55 -66
View File
@@ -1,79 +1,68 @@
#include "FDeformComputeShader.h" #include "FDeformComputeShader.h"
// DeformationCS.cpp #include "GlobalShader.h"
#include "RenderGraphUtils.h" #include "ShaderParameterStruct.h"
#include "ShaderParameterUtils.h" #include "RHIStaticStates.h"
#include "Shader.h"
#include "GlobalShader.h"
#include "RHICommandList.h" #include "RHICommandList.h"
IMPLEMENT_GLOBAL_SHADER(FDeformationCS, "/CustomShaders/DeformationCS.usf", "MainCS", SF_Compute); #include "RHIResources.h"
#include "ShaderParameterUtils.h"
// 全局参数存储
FThreadSafeDeformationParams GDeformationParams; FThreadSafeDeformationParams GDeformationParams;
// 实现Compute Shader
IMPLEMENT_GLOBAL_SHADER(FDeformationCS, "/Shaders/Private/DeformationCS.usf", "MainCS", SF_Compute);
// 分派函数实现
void FDeformationCS::Dispatch( void FDeformationCS::Dispatch(
FRHICommandListImmediate& RHICmdList, FRHICommandListImmediate& RHICmdList,
const FDeformationCSDispatchParams& Params) 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)); TShaderMapRef<FDeformationCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
SetComputePipelineState(RHICmdList, ComputeShader.GetComputeShader());
// 设置参数 SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetComputeShader(), Parameters);
FParameters ShaderParams; RHICmdList.DispatchComputeShader(GroupCountX, GroupCountY, GroupCountZ);
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
)
);
} }
// 渲染线程入口点
void DispatchDeformationComputeShaders(FRHICommandListImmediate& RHICmdList) // 线程安全参数管理
void FThreadSafeDeformationParams::AddParams(const FDeformationCSDispatchParams& NewParams)
{ {
FDeformationCSDispatchParams Params; FScopeLock Lock(&ParamsCriticalSection);
while(GDeformationParams.ConsumeParams(Params)) PendingParams.Add(NewParams);
}
bool FThreadSafeDeformationParams::ConsumeParams(FDeformationCSDispatchParams& OutParams)
{
FScopeLock Lock(&ParamsCriticalSection);
if (PendingParams.Num() > 0)
{ {
FDeformationCS::Dispatch(RHICmdList, Params); OutParams = PendingParams[0];
PendingParams.RemoveAt(0);
// 复制结果回源纹理 return true;
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
);
}
} }
} return false;
// 注册到渲染线程
void SetupDeformationShutdown();
FAutoConsoleCommand RegisterDeformationCmd(
TEXT("r.Deformation.Compute"),
TEXT(""),
FConsoleCommandDelegate::CreateStatic(SetupDeformationShutdown)
);
void SetupDeformationShutdown()
{
// 每帧结束时调用
ENQUEUE_RENDER_COMMAND(DeformationShutdown)(
[](FRHICommandListImmediate& RHICmdList) {
DispatchDeformationComputeShaders(RHICmdList);
});
} }
+3 -18
View File
@@ -21,7 +21,7 @@ struct FDeformationCSDispatchParams
// 纹理资源 // 纹理资源
FTextureRHIRef InputTexture; FTextureRHIRef InputTexture;
FTextureRHIRef OutputTexture; FUnorderedAccessViewRHIRef OutputTexture;
// 更新区域 (优化部分更新) // 更新区域 (优化部分更新)
FIntRect UpdateRegion; FIntRect UpdateRegion;
@@ -44,23 +44,8 @@ struct FThreadSafeDeformationParams
FCriticalSection ParamsCriticalSection; FCriticalSection ParamsCriticalSection;
TArray<FDeformationCSDispatchParams> PendingParams; TArray<FDeformationCSDispatchParams> PendingParams;
void AddParams(const FDeformationCSDispatchParams& NewParams) void AddParams(const FDeformationCSDispatchParams& NewParams);
{ bool ConsumeParams(FDeformationCSDispatchParams& OutParams);
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;
}
}; };
// 全局参数存储 // 全局参数存储
extern FThreadSafeDeformationParams GDeformationParams; extern FThreadSafeDeformationParams GDeformationParams;
+269 -59
View File
@@ -27,7 +27,7 @@ AIronBlock::AIronBlock(): StaticMeshComp(nullptr), PositionTexture0(nullptr), Po
void AIronBlock::BeginPlay() void AIronBlock::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
CalculateLocalBounds(); //CalculateLocalBounds();
InitializePositionTexture(); 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->SRGB = false;
NewTexture->CompressionSettings = TC_HDR; NewTexture->bNoTiling = true;
NewTexture->MipGenSettings = TMGS_NoMipmaps; NewTexture->AddressX = TA_Clamp;
NewTexture->NeverStream = true; 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->SetPlatformData(new FTexturePlatformData());
NewTexture->GetPlatformData()->SizeX = Size; NewTexture->GetPlatformData()->SizeX = Size;
NewTexture->GetPlatformData()->SizeY = Size; NewTexture->GetPlatformData()->SizeY = Size;
NewTexture->GetPlatformData()->PixelFormat = PF_A32B32G32R32F; NewTexture->GetPlatformData()->PixelFormat = PF_R32_FLOAT;
// 添加初始Mip // 添加初始Mip
FTexture2DMipMap* Mip = new FTexture2DMipMap(); FTexture2DMipMap* Mip = new FTexture2DMipMap();
NewTexture->GetPlatformData()->Mips.Add(Mip); //NewTexture->GetPlatformData()->Mips.Reset();
Mip->SizeX = Size; Mip->SizeX = Size;
Mip->SizeY = Size; Mip->SizeY = Size;
const int32 DataSize = Size * Size * sizeof(FLinearColor);
// 如果有初始数据,填充纹理 Mip->BulkData.Lock(LOCK_READ_WRITE);
if (InitialData.Num() > 0) Mip->BulkData.Realloc(DataSize);
{ Mip->BulkData.Unlock();
const int32 DataSize = Size * Size * sizeof(FLinearColor); NewTexture->GetPlatformData()->Mips.Add(Mip);
Mip->BulkData.Lock(LOCK_READ_WRITE); // // 如果有初始数据,填充纹理
FMemory::Memcpy(Mip->BulkData.Realloc(DataSize), InitialData.GetData(), DataSize); // if (InitialData.Num() >= Size * Size)
Mip->BulkData.Unlock(); // {
} // 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(); NewTexture->UpdateResource();
//ETextureDimension Dimension = NewTexture->GetResource()->GetTextureRHI()->GetDesc().Dimension;
return NewTexture; return NewTexture;
} }
@@ -77,13 +97,17 @@ void AIronBlock::OnEndFrameInitializeTextures()
{ {
// 确保纹理资源已创建 // 确保纹理资源已创建
if (PositionTexture0 && PositionTexture0->GetResource() && if (PositionTexture0 && PositionTexture0->GetResource() &&
PositionTexture1 && PositionTexture1->GetResource() && PositionTexture1 && PositionTexture1->GetResource()
PositionRenderTarget && PositionRenderTarget->GetResource()) /*&& PositionRenderTarget && PositionRenderTarget->GetResource()*/)
{ {
// 等待资源提交完成
FRenderCommandFence Fence;
Fence.BeginFence();
Fence.Wait();
// 初始化纹理对 // 初始化纹理对
InitializeTexturePair(0); InitializeTexturePair(0);
InitializeTexturePair(1); InitializeTexturePair(1);
//CreateSafeUAV(PositionRenderTarget);
// 移除委托 // 移除委托
FCoreDelegates::OnEndFrame.Remove(TextureInitHandle); FCoreDelegates::OnEndFrame.Remove(TextureInitHandle);
TextureInitHandle.Reset(); TextureInitHandle.Reset();
@@ -115,6 +139,56 @@ void AIronBlock::EndPlay(const EEndPlayReason::Type EndPlayReason)
Super::EndPlay(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) void AIronBlock::InitializeTexturePair(int32 Index)
{ {
if (Index < 0 || Index > 1) return; if (Index < 0 || Index > 1) return;
@@ -123,15 +197,42 @@ void AIronBlock::InitializeTexturePair(int32 Index)
if (!Texture || !Texture->GetResource()) return; if (!Texture || !Texture->GetResource()) return;
// 获取纹理引用 // 获取纹理引用
TexturePairs[Index].RHITexture = Texture->GetResource()->TextureRHI; FTextureRHIRef RHITexture = Texture->GetResource()->TextureRHI;
FTextureRHIRef RHITexture = Texture->GetResource()->GetTexture2DRHI();
if (!RHITexture.IsValid()) return; if (!RHITexture.IsValid()) return;
TexturePairs[Index].RHITexture = RHITexture;
// 在渲染线程创建 UAV // 在渲染线程创建 UAV
ENQUEUE_RENDER_COMMAND(CreateTextureUAV)( ENQUEUE_RENDER_COMMAND(CreateTextureUAV)(
[this, Index](FRHICommandListImmediate& RHICmdList) [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(); 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); TexturePairs[Index].UAV = RHICmdList.CreateUnorderedAccessView(TexturePairs[Index].RHITexture,ViewDesc);
UE_LOG(LogTemp, Log, TEXT("Created UAV for texture %d"), Index); UE_LOG(LogTemp, Log, TEXT("Created UAV for texture %d"), Index);
@@ -166,38 +267,106 @@ void AIronBlock::GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions)
void AIronBlock::InitializePositionTexture() 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; TArray<FVector3f> VertexPositions;
GetStaticMeshVertexPositions(VertexPositions); GetStaticMeshVertexPositions(VertexPositions);
// 创建初始数据数组 // 创建位置纹理
const int32 TextureSize = 256; // 纹理尺寸
TArray<FLinearColor> InitialData; TArray<FLinearColor> InitialData;
const int32 TexSize = FMath::RoundUpToPowerOfTwo(FMath::Sqrt((float)VertexPositions.Num())); InitialData.SetNum(TextureSize * TextureSize);
//int32 TexSize = 512;
InitialData.SetNumZeroed(TexSize * TexSize); // 初始化纹理数据
for (int32 i = 0; i < VertexPositions.Num() && i < InitialData.Num(); i++) 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); PositionTexture0 = CreatePositionTexture(TEXT("PositionTexture0"), TextureSize, InitialData);
PositionTexture1 = CreatePositionTexture("PosTex1", TexSize, InitialData); PositionTexture1 = CreatePositionTexture(TEXT("PositionTexture1"), TextureSize, InitialData);
// 初始化纹理对
TexturePairs[0].RHITexture = PositionTexture0->GetResource()->TextureRHI;
TexturePairs[1].RHITexture = PositionTexture1->GetResource()->TextureRHI;
// 创建渲染目标 // 创建渲染目标
PositionRenderTarget = NewObject<UTextureRenderTarget2D>(this); PositionRenderTarget = NewObject<UTextureRenderTarget2D>(this);
PositionRenderTarget->RenderTargetFormat = RTF_RGBA32f; PositionRenderTarget->SizeX = TextureSize;
PositionRenderTarget->bCanCreateUAV = true; PositionRenderTarget->SizeY = TextureSize;
PositionRenderTarget->InitAutoFormat(TexSize, TexSize); PositionRenderTarget->RenderTargetFormat = RTF_RGBA16f;
PositionRenderTarget->bAutoGenerateMips = false;
PositionRenderTarget->UpdateResource(); PositionRenderTarget->UpdateResource();
// 注册纹理初始化委托 // 设置变形材质
TextureInitHandle = FCoreDelegates::OnEndFrame.AddUObject(this, &AIronBlock::OnEndFrameInitializeTextures);
// 设置材质实例
SetupDeformationMaterial(); 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() void AIronBlock::CalculateLocalBounds()
@@ -230,12 +399,30 @@ void AIronBlock::CalculateLocalBounds()
void AIronBlock::SetupDeformationMaterial() void AIronBlock::SetupDeformationMaterial()
{ {
DynMaterial = UMaterialInstanceDynamic::Create(StaticMeshComp->GetMaterial(0), this); // 创建动态材质实例
StaticMeshComp->SetMaterial(0, DynMaterial); if (StaticMeshComp)
{
// 加载基础材质
UMaterial* BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial"));
if (BaseMaterial)
{
DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
StaticMeshComp->SetMaterial(0, DynMaterial);
DynMaterial->SetTextureParameterValue("PositionTexture", PositionTexture0); // 设置初始参数
if (DynMaterial)
DynMaterial->SetScalarParameterValue("EnableDeformation", 1.0f); {
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) void AIronBlock::OnHammerHit(const FHitResult& HitResult)
@@ -307,10 +494,12 @@ void AIronBlock::ExecuteDeformationCS()
UE_LOG(LogTemp, Error, TEXT("Position textures not initialized!")); UE_LOG(LogTemp, Error, TEXT("Position textures not initialized!"));
return; return;
} }
// 获取当前纹理资源 // 获取当前纹理资源
UTexture2D* CurrentTex = (CurrentTextureIndex == 0) ? PositionTexture0 : PositionTexture1; UTexture2D* CurrentTex = (CurrentTextureIndex == 0) ? PositionTexture0 : PositionTexture1;
UTexture2D* PrevTex = (CurrentTextureIndex == 0) ? PositionTexture1 : PositionTexture0; UTexture2D* PrevTex = (CurrentTextureIndex == 0) ? PositionTexture1 : PositionTexture0;
// 获取纹理RHI资源 - 使用GetResource()方法
// 获取纹理RHI资源
FTextureRHIRef InputRHI = GetTextureRHI(PrevTex); FTextureRHIRef InputRHI = GetTextureRHI(PrevTex);
FTextureRHIRef OutputRHI = GetRenderTargetRHI(PositionRenderTarget); FTextureRHIRef OutputRHI = GetRenderTargetRHI(PositionRenderTarget);
@@ -319,6 +508,7 @@ void AIronBlock::ExecuteDeformationCS()
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!")); UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!"));
return; return;
} }
// 计算纹理UV坐标 // 计算纹理UV坐标
const int32 TexSize = PositionRenderTarget->SizeX; const int32 TexSize = PositionRenderTarget->SizeX;
FVector2D ImpactUV( FVector2D ImpactUV(
@@ -342,20 +532,40 @@ void AIronBlock::ExecuteDeformationCS()
Params.DeformationRadius = CurrentDeformationRadius; Params.DeformationRadius = CurrentDeformationRadius;
Params.Plasticity = CurrentPlasticity; Params.Plasticity = CurrentPlasticity;
Params.InputTexture = InputRHI; Params.InputTexture = InputRHI;
Params.OutputTexture = OutputRHI;
Params.UpdateRegion = UpdateRegion;
Params.TextureSize = FIntVector(TexSize, TexSize, 0);
// 提交到渲染线程 // 创建UAV用于输出
GDeformationParams.AddParams(Params); 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); if (DynMaterial)
{
// 触发碰撞体更新 (异步) DynMaterial->SetTextureParameterValue(TEXT("PositionTexture"), CurrentTex);
GetWorld()->GetTimerManager().SetTimerForNextTick([this, UpdateRegion](){ DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMin"), FLinearColor(LocalBounds.Min));
UpdateCollisionAsync(UpdateRegion); DynMaterial->SetVectorParameterValue(TEXT("LocalBoundsMax"), FLinearColor(LocalBounds.Max));
}); }
} }
// 异步更新物理碰撞体 // 异步更新物理碰撞体
void AIronBlock::UpdateCollisionAsync(const FIntRect& UpdateRegion) void AIronBlock::UpdateCollisionAsync(const FIntRect& UpdateRegion)
+6 -3
View File
@@ -29,6 +29,9 @@ public:
// Sets default values for this actor's properties // Sets default values for this actor's properties
AIronBlock(); AIronBlock();
UFUNCTION(BlueprintCallable)
void OnHammerHit(const FHitResult& HitResult);
protected: protected:
// Called when the game starts or when spawned // Called when the game starts or when spawned
virtual void BeginPlay() override; virtual void BeginPlay() override;
@@ -37,10 +40,9 @@ protected:
void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions); void GetStaticMeshVertexPositions(TArray<FVector3f>& OutPositions);
UTexture2D* CreatePositionTexture(const FString& TexName, int32 Size, const TArray<FLinearColor>& InitialData); UTexture2D* CreatePositionTexture(const FString& TexName, int32 Size, const TArray<FLinearColor>& InitialData);
void InitializePositionTexture(); void InitializePositionTexture();
FUnorderedAccessViewRHIRef CreateSafeUAV(UTextureRenderTarget2D* RenderTarget);
void OnEndFrameInitializeTextures(); void OnEndFrameInitializeTextures();
void SetupDeformationMaterial(); void SetupDeformationMaterial();
UFUNCTION(BlueprintCallable)
void OnHammerHit(const FHitResult& HitResult);
FTextureRHIRef GetTextureRHI(UTexture2D* Texture); FTextureRHIRef GetTextureRHI(UTexture2D* Texture);
FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT); FTextureRHIRef GetRenderTargetRHI(UTextureRenderTarget2D* RT);
private: private:
@@ -57,11 +59,12 @@ private:
// UAV 资源引用 // UAV 资源引用
FUnorderedAccessViewRHIRef UAV; FUnorderedAccessViewRHIRef UAV;
//FRDGTextureUAVRef UAV;
// 安全释放资源 // 安全释放资源
void ReleaseRHI() void ReleaseRHI()
{ {
UAV.SafeRelease(); UAV.SafeRelease();
//UAV->GetRHI()->Release();
RHITexture.SafeRelease(); RHITexture.SafeRelease();
} }
}; };