使用cursor修正代码
This commit is contained in:
Generated
+6
@@ -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>
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"FileVersion": 3,
|
"FileVersion": 3,
|
||||||
"EngineAssociation": "5.5",
|
"EngineAssociation": "{DE41D031-4C3F-817F-365A-5AAD9A1CE2AD}",
|
||||||
"Category": "",
|
"Category": "",
|
||||||
"Description": "",
|
"Description": "",
|
||||||
"Modules": [
|
"Modules": [
|
||||||
|
|||||||
@@ -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开发,遵循相应的许可证条款。
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user