使用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",
"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",
+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">
<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>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"FileVersion": 3,
"EngineAssociation": "5.5",
"EngineAssociation": "{DE41D031-4C3F-817F-365A-5AAD9A1CE2AD}",
"Category": "",
"Description": "",
"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;
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();
}
};