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