Add plastic deformation voxel system implementation plan to project
Move plan from user directory to project docs for cross-machine sync. This plan describes the two-phase GPU-based deformation system: stress propagation and displacement calculation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,723 @@
|
||||
# BladeSmith塑性变形体素系统 - 实现计划
|
||||
|
||||
## 概述
|
||||
|
||||
基于现有温度系统架构,构建一个完整的塑性变形体素系统。系统采用**两步法**:
|
||||
1. **应力传播阶段**:锤击施加应力,通过GPU迭代计算应力在体素间扩散
|
||||
2. **位移计算阶段**:从应力分布计算位移场,应用到网格顶点
|
||||
|
||||
## 核心设计决策
|
||||
|
||||
- **物理模型**:简化模型(塑性流动 + 应变软化 + 体积守恒)
|
||||
- **体素数据**:存储应力、应变、位移(混合方式)
|
||||
- **GPU架构**:应力Ping-Pong双缓冲 + 独立位移/应变缓冲
|
||||
- **锤击响应**:两步法(应力注入 → GPU计算 → 顶点更新)
|
||||
- **内存占用**:36字节/体素(20³网格 = 281KB,100³网格 = 34.4MB)
|
||||
|
||||
---
|
||||
|
||||
## 一、数据结构设计
|
||||
|
||||
### 1.1 变形体素结构(添加到DynamicIronBlock.h)
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* 变形体素结构 - 存储单个体素的力学状态
|
||||
* 大小:36字节(紧凑型设计)
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FDeformationVoxel
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// 应力张量(简化为主应力,6字节)
|
||||
FFloat16 StressPrincipal; // 主应力(沿锤击方向) - 2字节
|
||||
FFloat16 StressShear; // 剪应力(切向) - 2字节
|
||||
uint16 StressFlags; // 应力状态标志 - 2字节
|
||||
|
||||
// 累积应变(12字节)
|
||||
FVector3f Strain; // 累积应变向量 (εx, εy, εz)
|
||||
|
||||
// 位移场(当前帧变形,12字节)
|
||||
FVector3f Displacement; // 位移向量 (Δx, Δy, Δz)
|
||||
|
||||
// 物理属性(4字节)
|
||||
float PlasticFlow; // 塑性流动系数 [0,1],由温度决定
|
||||
|
||||
// 辅助数据(6字节)
|
||||
uint16 MaterialID; // 材料ID
|
||||
uint32 AuxFlags; // 辅助标志位
|
||||
|
||||
FDeformationVoxel()
|
||||
: StressPrincipal(0.0f), StressShear(0.0f), StressFlags(0)
|
||||
, Strain(FVector3f::ZeroVector), Displacement(FVector3f::ZeroVector)
|
||||
, PlasticFlow(0.0f), MaterialID(0), AuxFlags(0)
|
||||
{}
|
||||
};
|
||||
```
|
||||
|
||||
### 1.2 类成员变量(添加到DynamicIronBlock.h)
|
||||
|
||||
```cpp
|
||||
// ========== 变形系统数据 ==========
|
||||
|
||||
// 变形体素网格(CPU侧)
|
||||
TArray<FDeformationVoxel> DeformationGrid;
|
||||
|
||||
// 原始网格顶点位置(未变形状态)
|
||||
TArray<FVector3f> OriginalVertexPositions;
|
||||
|
||||
// 是否启用变形系统
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deformation System")
|
||||
bool bEnableDeformationSystem = true;
|
||||
|
||||
// 变形系统参数
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deformation System")
|
||||
float YieldStress = 50.0f; // 屈服应力阈值
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deformation System")
|
||||
float StressDiffusionRate = 0.3f; // 应力扩散速率
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deformation System")
|
||||
float VolumeConservationStrength = 0.8f; // 体积守恒强度
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deformation System")
|
||||
float ComplianceFactor = 0.01f; // 柔度(应力→位移转换系数)
|
||||
|
||||
// ========== GPU缓冲区 ==========
|
||||
|
||||
// 应力缓冲区(Ping-Pong)
|
||||
FBufferRHIRef StressBufferA;
|
||||
FBufferRHIRef StressBufferB;
|
||||
|
||||
// 位移和应变缓冲区
|
||||
FBufferRHIRef DisplacementBuffer; // PF_R32G32B32_FLOAT(3D向量)
|
||||
FBufferRHIRef StrainBuffer; // PF_R32G32B32_FLOAT
|
||||
|
||||
// UAV/SRV视图
|
||||
FUnorderedAccessViewRHIRef StressUAV_A;
|
||||
FUnorderedAccessViewRHIRef StressUAV_B;
|
||||
FUnorderedAccessViewRHIRef DisplacementUAV;
|
||||
FUnorderedAccessViewRHIRef StrainUAV;
|
||||
|
||||
FShaderResourceViewRHIRef StressSRV_A;
|
||||
FShaderResourceViewRHIRef StressSRV_B;
|
||||
FShaderResourceViewRHIRef DisplacementSRV;
|
||||
FShaderResourceViewRHIRef StrainSRV;
|
||||
|
||||
bool bUseStressBufferA = true; // Ping-Pong标志
|
||||
|
||||
// GPU缓冲区是否准备好
|
||||
std::atomic<bool> bDeformationGPUBuffersReady{false};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、GPU计算着色器
|
||||
|
||||
### 2.1 应力传播着色器(阶段1)
|
||||
|
||||
**文件**: `FStressPropagationShader.h` (新建)
|
||||
|
||||
```cpp
|
||||
class MICESHADERS_API FStressPropagationShader : public FGlobalShader
|
||||
{
|
||||
DECLARE_GLOBAL_SHADER(FStressPropagationShader);
|
||||
SHADER_USE_PARAMETER_STRUCT(FStressPropagationShader, FGlobalShader);
|
||||
|
||||
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
||||
SHADER_PARAMETER(FIntVector, VoxelResolution)
|
||||
SHADER_PARAMETER(float, DeltaTime)
|
||||
SHADER_PARAMETER(float, StressDiffusionRate)
|
||||
SHADER_PARAMETER(float, YieldStress)
|
||||
SHADER_PARAMETER(float, StrainSofteningFactor)
|
||||
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float>, InputStressBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float>, PlasticityBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, SurfaceVoxelFlagsBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<float>, OutputStressBuffer)
|
||||
END_SHADER_PARAMETER_STRUCT()
|
||||
|
||||
static FIntVector GetGroupSize() { return FIntVector(8, 8, 8); }
|
||||
};
|
||||
```
|
||||
|
||||
**HLSL**: `StressPropagationCS.usf` (新建)
|
||||
|
||||
```hlsl
|
||||
[numthreads(8, 8, 8)]
|
||||
void MainCompute(uint3 DispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
int3 voxelCoord = int3(DispatchThreadID);
|
||||
if (!IsValidCoord(voxelCoord)) return;
|
||||
|
||||
int index = GetVoxelIndex(voxelCoord);
|
||||
float currentStress = InputStressBuffer[index];
|
||||
float plasticity = PlasticityBuffer[index];
|
||||
|
||||
// === 6邻域应力扩散 ===
|
||||
float neighborStressSum = 0.0;
|
||||
int neighborCount = 0;
|
||||
const int3 neighbors[6] = {
|
||||
int3(-1,0,0), int3(1,0,0),
|
||||
int3(0,-1,0), int3(0,1,0),
|
||||
int3(0,0,-1), int3(0,0,1)
|
||||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int3 neighborCoord = voxelCoord + neighbors[i];
|
||||
if (IsValidCoord(neighborCoord)) {
|
||||
neighborStressSum += InputStressBuffer[GetVoxelIndex(neighborCoord)];
|
||||
neighborCount++;
|
||||
}
|
||||
}
|
||||
|
||||
float avgNeighborStress = neighborStressSum / max(neighborCount, 1);
|
||||
|
||||
// === 应力传播(塑性越高,传播越快) ===
|
||||
float diffusionRate = StressDiffusionRate * (1.0 + plasticity * 2.0);
|
||||
float stressDiffusion = diffusionRate * (avgNeighborStress - currentStress) * DeltaTime;
|
||||
|
||||
// === 应力松弛(超过屈服点的应力衰减) ===
|
||||
float stressRelaxation = 0.0;
|
||||
if (currentStress > YieldStress && plasticity > 0.1) {
|
||||
float excessStress = currentStress - YieldStress;
|
||||
stressRelaxation = -excessStress * plasticity * StrainSofteningFactor * DeltaTime;
|
||||
}
|
||||
|
||||
// === 表面应力自由释放 ===
|
||||
bool isSurface = (SurfaceVoxelFlagsBuffer[index] & 1) != 0;
|
||||
if (isSurface) {
|
||||
stressRelaxation += -currentStress * 0.1 * DeltaTime;
|
||||
}
|
||||
|
||||
// === 更新应力 ===
|
||||
float newStress = max(0.0, currentStress + stressDiffusion + stressRelaxation);
|
||||
OutputStressBuffer[index] = newStress;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 位移计算着色器(阶段2)
|
||||
|
||||
**文件**: `FDisplacementFromStressShader.h` (新建)
|
||||
|
||||
```cpp
|
||||
class MICESHADERS_API FDisplacementFromStressShader : public FGlobalShader
|
||||
{
|
||||
DECLARE_GLOBAL_SHADER(FDisplacementFromStressShader);
|
||||
SHADER_USE_PARAMETER_STRUCT(FDisplacementFromStressShader, FGlobalShader);
|
||||
|
||||
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
||||
SHADER_PARAMETER(FIntVector, VoxelResolution)
|
||||
SHADER_PARAMETER(float, DeltaTime)
|
||||
SHADER_PARAMETER(float, VolumeConservationStrength)
|
||||
SHADER_PARAMETER(float, ComplianceFactor)
|
||||
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float>, StressBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float>, PlasticityBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float3>, PreviousStrainBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<float3>, OutputDisplacementBuffer)
|
||||
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<float3>, OutputStrainBuffer)
|
||||
END_SHADER_PARAMETER_STRUCT()
|
||||
|
||||
static FIntVector GetGroupSize() { return FIntVector(8, 8, 8); }
|
||||
};
|
||||
```
|
||||
|
||||
**HLSL**: `DisplacementFromStressCS.usf` (新建)
|
||||
|
||||
```hlsl
|
||||
[numthreads(8, 8, 8)]
|
||||
void MainCompute(uint3 DispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
int3 voxelCoord = int3(DispatchThreadID);
|
||||
if (!IsValidCoord(voxelCoord)) return;
|
||||
|
||||
int index = GetVoxelIndex(voxelCoord);
|
||||
float stress = StressBuffer[index];
|
||||
float plasticity = PlasticityBuffer[index];
|
||||
float3 previousStrain = PreviousStrainBuffer[index];
|
||||
|
||||
// === 计算应力梯度(主变形方向) ===
|
||||
float3 stressGradient = ComputeStressGradient(voxelCoord);
|
||||
float3 deformationDirection = length(stressGradient) > 0.001 ?
|
||||
normalize(stressGradient) :
|
||||
float3(0, 0, -1);
|
||||
|
||||
// === 计算塑性位移 ===
|
||||
float displacementMagnitude = stress * ComplianceFactor * plasticity;
|
||||
float3 plasticDisplacement = deformationDirection * displacementMagnitude;
|
||||
|
||||
// === 体积守恒修正 ===
|
||||
float compressionAmount = dot(plasticDisplacement, deformationDirection);
|
||||
float lateralExpansion = -compressionAmount * VolumeConservationStrength * 0.5;
|
||||
|
||||
float3 lateral1 = normalize(cross(deformationDirection, float3(0, 0, 1)));
|
||||
float3 lateral2 = normalize(cross(deformationDirection, lateral1));
|
||||
float3 volumeCompensation = (lateral1 + lateral2) * lateralExpansion;
|
||||
|
||||
// === 最终位移和应变 ===
|
||||
float3 totalDisplacement = plasticDisplacement + volumeCompensation;
|
||||
float3 newStrain = previousStrain + totalDisplacement * DeltaTime;
|
||||
|
||||
OutputDisplacementBuffer[index] = totalDisplacement;
|
||||
OutputStrainBuffer[index] = newStrain;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、锤击响应流程
|
||||
|
||||
### 3.1 修改OnHammerImpact(DynamicIronBlock.cpp)
|
||||
|
||||
```cpp
|
||||
void ADynamicIronBlock::OnHammerImpact(
|
||||
FVector HitLocation, FVector HitNormal,
|
||||
float ImpactRadius, float ImpactDepth, float ImpactForce)
|
||||
{
|
||||
if (!bEnableDeformationSystem || DeformationGrid.Num() == 0)
|
||||
{
|
||||
// 回退到旧逻辑(直接修改顶点)
|
||||
OnHammerImpact_Legacy(HitLocation, HitNormal, ImpactRadius, ImpactDepth, ImpactForce);
|
||||
return;
|
||||
}
|
||||
|
||||
// === 步骤1:应力注入 ===
|
||||
ApplyImpactStressToVoxels(HitLocation, HitNormal, ImpactRadius, ImpactDepth, ImpactForce);
|
||||
|
||||
// === 步骤2:GPU应力传播(迭代3次) ===
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
DispatchStressPropagationCompute(0.016f); // 16ms时间步
|
||||
}
|
||||
|
||||
// === 步骤3:GPU位移计算 ===
|
||||
DispatchDisplacementCompute(0.016f);
|
||||
|
||||
// === 步骤4:下载并应用到网格 ===
|
||||
DownloadDeformationDataAndApplyToMesh();
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 应力注入函数
|
||||
|
||||
```cpp
|
||||
void ADynamicIronBlock::ApplyImpactStressToVoxels(
|
||||
FVector HitLocation, FVector HitNormal,
|
||||
float ImpactRadius, float ImpactDepth, float ImpactForce)
|
||||
{
|
||||
// 转换到局部坐标
|
||||
FTransform ActorTransform = GetActorTransform();
|
||||
FVector LocalHitLocation = ActorTransform.InverseTransformPosition(HitLocation);
|
||||
|
||||
// 计算体素坐标
|
||||
FVector GridOrigin = -BoxSize * 0.5f;
|
||||
FVector VoxelSizeCM = FVector(TemperatureVoxelSize / 10.0f);
|
||||
|
||||
// 遍历影响范围
|
||||
for (int32 Z = 0; Z < TemperatureResolution.Z; ++Z)
|
||||
{
|
||||
for (int32 Y = 0; Y < TemperatureResolution.Y; ++Y)
|
||||
{
|
||||
for (int32 X = 0; X < TemperatureResolution.X; ++X)
|
||||
{
|
||||
FVector VoxelCenter = GridOrigin + FVector(
|
||||
(X + 0.5f) * VoxelSizeCM.X,
|
||||
(Y + 0.5f) * VoxelSizeCM.Y,
|
||||
(Z + 0.5f) * VoxelSizeCM.Z
|
||||
);
|
||||
|
||||
float Distance = FVector::Dist(VoxelCenter, LocalHitLocation);
|
||||
|
||||
if (Distance < ImpactRadius)
|
||||
{
|
||||
int32 Index = GetTemperatureIndex(X, Y, Z);
|
||||
|
||||
// 高斯衰减
|
||||
float Falloff = FMath::Exp(-FMath::Square(Distance / ImpactRadius) * 3.0f);
|
||||
|
||||
// 应力大小
|
||||
float StressMagnitude = ImpactForce * ImpactDepth * Falloff * 100.0f;
|
||||
|
||||
// 注入到体素
|
||||
if (DeformationGrid.IsValidIndex(Index))
|
||||
{
|
||||
DeformationGrid[Index].StressPrincipal = FMath::Min(
|
||||
DeformationGrid[Index].StressPrincipal.GetFloat() + StressMagnitude,
|
||||
1000.0f // 应力上限
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到GPU
|
||||
UploadDeformationStressToGPU();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、顶点更新机制
|
||||
|
||||
### 4.1 从体素位移场采样到顶点
|
||||
|
||||
```cpp
|
||||
void ADynamicIronBlock::UpdateVertexDeformation()
|
||||
{
|
||||
UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent();
|
||||
if (!DynMeshComp) return;
|
||||
|
||||
UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh();
|
||||
if (!DynMesh) return;
|
||||
|
||||
// 修改网格顶点
|
||||
DynMesh->EditMesh([&](FDynamicMesh3& EditMesh)
|
||||
{
|
||||
for (int32 VertexID : EditMesh.VertexIndicesItr())
|
||||
{
|
||||
// 获取原始顶点位置
|
||||
FVector3d OriginalPos = FVector3d(OriginalVertexPositions[VertexID]);
|
||||
|
||||
// 采样体素位移场(三线性插值)
|
||||
FVector Displacement = SampleDisplacementAtPosition(FVector(OriginalPos));
|
||||
|
||||
// 新位置 = 原始位置 + 位移
|
||||
FVector3d NewPosition = OriginalPos + FVector3d(Displacement);
|
||||
|
||||
EditMesh.SetVertex(VertexID, NewPosition);
|
||||
}
|
||||
}, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false);
|
||||
|
||||
// 重新计算法线
|
||||
FGeometryScriptCalculateNormalsOptions NormalOp;
|
||||
UGeometryScriptLibrary_MeshNormalsFunctions::RecomputeNormals(DynMesh, NormalOp);
|
||||
|
||||
DynMeshComp->NotifyMeshUpdated();
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 三线性插值采样位移
|
||||
|
||||
```cpp
|
||||
FVector ADynamicIronBlock::SampleDisplacementAtPosition(const FVector& LocalPosition) const
|
||||
{
|
||||
if (!bEnableDeformationSystem || DeformationGrid.Num() == 0)
|
||||
{
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// 转换到体素坐标系
|
||||
FVector GridOrigin = -BoxSize * 0.5f;
|
||||
FVector VoxelSizeCM = FVector(TemperatureVoxelSize / 10.0f);
|
||||
FVector VoxelCoord = (LocalPosition - GridOrigin) / VoxelSizeCM;
|
||||
|
||||
// 获取相邻8个体素
|
||||
int32 X0 = FMath::FloorToInt(VoxelCoord.X);
|
||||
int32 Y0 = FMath::FloorToInt(VoxelCoord.Y);
|
||||
int32 Z0 = FMath::FloorToInt(VoxelCoord.Z);
|
||||
int32 X1 = X0 + 1, Y1 = Y0 + 1, Z1 = Z0 + 1;
|
||||
|
||||
// 边界检查
|
||||
if (!IsValidTemperatureCoord(X0, Y0, Z0) || !IsValidTemperatureCoord(X1, Y1, Z1))
|
||||
{
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// 插值权重
|
||||
float Fx = VoxelCoord.X - X0;
|
||||
float Fy = VoxelCoord.Y - Y0;
|
||||
float Fz = VoxelCoord.Z - Z0;
|
||||
|
||||
// 获取8个角点的位移
|
||||
auto GetDisp = [&](int X, int Y, int Z) -> FVector
|
||||
{
|
||||
int32 Index = GetTemperatureIndex(X, Y, Z);
|
||||
return FVector(DeformationGrid[Index].Displacement);
|
||||
};
|
||||
|
||||
FVector D000 = GetDisp(X0, Y0, Z0);
|
||||
FVector D100 = GetDisp(X1, Y0, Z0);
|
||||
FVector D010 = GetDisp(X0, Y1, Z0);
|
||||
FVector D110 = GetDisp(X1, Y1, Z0);
|
||||
FVector D001 = GetDisp(X0, Y0, Z1);
|
||||
FVector D101 = GetDisp(X1, Y0, Z1);
|
||||
FVector D011 = GetDisp(X0, Y1, Z1);
|
||||
FVector D111 = GetDisp(X1, Y1, Z1);
|
||||
|
||||
// 三线性插值
|
||||
FVector D00 = FMath::Lerp(D000, D100, Fx);
|
||||
FVector D10 = FMath::Lerp(D010, D110, Fx);
|
||||
FVector D01 = FMath::Lerp(D001, D101, Fx);
|
||||
FVector D11 = FMath::Lerp(D011, D111, Fx);
|
||||
FVector D0 = FMath::Lerp(D00, D10, Fy);
|
||||
FVector D1 = FMath::Lerp(D01, D11, Fy);
|
||||
return FMath::Lerp(D0, D1, Fz);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、实现步骤
|
||||
|
||||
### 阶段1:基础架构(2-3天)
|
||||
|
||||
**目标**:建立数据结构和CPU侧逻辑
|
||||
|
||||
1. **添加数据结构** (DynamicIronBlock.h)
|
||||
- 定义 `FDeformationVoxel` 结构体
|
||||
- 添加 `DeformationGrid`、`OriginalVertexPositions` 成员变量
|
||||
- 添加变形系统参数(YieldStress、StressDiffusionRate等)
|
||||
|
||||
2. **实现初始化** (DynamicIronBlock.cpp)
|
||||
- `InitializeDeformationGrid()`: 分配体素数组
|
||||
- 在 `InitializeBoxMesh()` 中保存原始顶点位置
|
||||
|
||||
3. **实现应力注入**
|
||||
- `ApplyImpactStressToVoxels()`: CPU版本应力注入
|
||||
- 测试:打印应力分布,验证高斯衰减
|
||||
|
||||
4. **实现位移采样**
|
||||
- `SampleDisplacementAtPosition()`: 三线性插值
|
||||
- `UpdateVertexDeformation()`: 应用到网格
|
||||
- 测试:手动设置位移值,观察网格变形
|
||||
|
||||
### 阶段2:GPU缓冲区(1-2天)
|
||||
|
||||
**目标**:建立GPU缓冲区,实现CPU-GPU数据流
|
||||
|
||||
5. **创建GPU缓冲区**
|
||||
- `CreateDeformationGPUBuffers()`: 创建所有RHI缓冲区
|
||||
- `ReleaseDeformationGPUBuffers()`: 清理资源
|
||||
|
||||
6. **数据传输**
|
||||
- `UploadDeformationStressToGPU()`: 应力数据 CPU→GPU
|
||||
- `DownloadDeformationDataAndApplyToMesh()`: 位移数据 GPU→CPU
|
||||
- 测试:上传后立即下载,验证数据完整性
|
||||
|
||||
### 阶段3:GPU计算着色器(3-4天)
|
||||
|
||||
**目标**:实现两阶段GPU计算
|
||||
|
||||
7. **应力传播Shader**
|
||||
- 新建 `FStressPropagationShader.h/cpp` (参考FTemperatureComputeShader)
|
||||
- 新建 `StressPropagationCS.usf`
|
||||
- 实现6邻域扩散 + 应力松弛
|
||||
- 测试:单点应力观察传播
|
||||
|
||||
8. **位移计算Shader**
|
||||
- 新建 `FDisplacementFromStressShader.h/cpp`
|
||||
- 新建 `DisplacementFromStressCS.usf`
|
||||
- 实现应力→位移 + 体积守恒
|
||||
- 测试:固定应力验证位移
|
||||
|
||||
9. **调度逻辑**
|
||||
- `DispatchStressPropagationCompute()`: RDG调度应力传播
|
||||
- `DispatchDisplacementCompute()`: RDG调度位移计算
|
||||
- 测试:完整流程(应力→传播→位移→网格)
|
||||
|
||||
### 阶段4:集成和优化(2-3天)
|
||||
|
||||
**目标**:完整集成,调优参数
|
||||
|
||||
10. **修改锤击逻辑**
|
||||
- 更新 `OnHammerImpact()` 使用新系统
|
||||
- 保留旧逻辑作为fallback (`OnHammerImpact_Legacy()`)
|
||||
|
||||
11. **参数调优**
|
||||
- 调整物理参数观察效果
|
||||
- 确保变形符合物理直觉
|
||||
|
||||
12. **性能优化**
|
||||
- 添加性能日志
|
||||
- 优化迭代次数
|
||||
- 考虑局部更新
|
||||
|
||||
13. **调试工具**
|
||||
- 可视化应力分布(顶点颜色)
|
||||
- 可视化位移场(Debug Gizmo)
|
||||
|
||||
---
|
||||
|
||||
## 六、关键文件清单
|
||||
|
||||
### 需要修改的文件
|
||||
|
||||
1. **C:\MiceCola\Indi\BladeSmith\Source\BladeSmith\DynamicIronBlock.h**
|
||||
- 添加 `FDeformationVoxel` 结构体
|
||||
- 添加变形系统成员变量和参数
|
||||
- 添加新函数声明(约15个函数)
|
||||
|
||||
2. **C:\MiceCola\Indi\BladeSmith\Source\BladeSmith\DynamicIronBlock.cpp**
|
||||
- 实现所有变形系统函数
|
||||
- 修改 `OnHammerImpact()` 为两步法
|
||||
- 修改 `BeginPlay()`、`EndPlay()`、`InitializeBoxMesh()`
|
||||
|
||||
### 需要新建的文件
|
||||
|
||||
3. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Public\FStressPropagationShader.h**
|
||||
- 应力传播着色器类声明
|
||||
|
||||
4. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Private\FStressPropagationShader.cpp**
|
||||
- Shader实现(IMPLEMENT_GLOBAL_SHADER)
|
||||
|
||||
5. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Public\FDisplacementFromStressShader.h**
|
||||
- 位移计算着色器类声明
|
||||
|
||||
6. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Private\FDisplacementFromStressShader.cpp**
|
||||
- Shader实现
|
||||
|
||||
7. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Shaders\Private\StressPropagationCS.usf**
|
||||
- 应力传播HLSL代码
|
||||
|
||||
8. **C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Shaders\Private\DisplacementFromStressCS.usf**
|
||||
- 位移计算HLSL代码
|
||||
|
||||
---
|
||||
|
||||
## 七、验证和测试
|
||||
|
||||
### 单元测试
|
||||
|
||||
1. **体素索引测试**
|
||||
- 验证 `GetTemperatureIndex()` 3D→1D转换正确性
|
||||
- 测试边界情况
|
||||
|
||||
2. **插值测试**
|
||||
- 设置8个体素位移为已知值
|
||||
- 验证中心点插值结果精度
|
||||
|
||||
3. **应力衰减测试**
|
||||
- 注入单点应力
|
||||
- 验证距离衰减符合高斯曲线
|
||||
|
||||
### 集成测试
|
||||
|
||||
4. **锤击响应测试**
|
||||
- **冷态测试**(塑性=0):锤击应无明显变形
|
||||
- **热态测试**(塑性=1):锤击应有深度变形
|
||||
- **体积守恒验证**:压缩区深度 ≈ 凸起区体积
|
||||
|
||||
5. **性能测试**
|
||||
- 测量每次锤击耗时(目标 <7ms)
|
||||
- 验证60fps稳定性
|
||||
- GPU占用率监控
|
||||
|
||||
### 物理验证
|
||||
|
||||
6. **应力传播验证**
|
||||
- 单点冲击应力向周围扩散
|
||||
- 表面体素应力快速释放
|
||||
|
||||
7. **温度-塑性耦合验证**
|
||||
- 高温区域深度变形
|
||||
- 低温区域轻微变形
|
||||
|
||||
### 端到端测试
|
||||
|
||||
8. **完整流程测试**
|
||||
```
|
||||
1. 启动游戏 → 加载DynamicIronBlock
|
||||
2. 开启自动加热 → 观察温度上升
|
||||
3. 等待塑性系数 > 0.5
|
||||
4. 执行锤击 → 观察变形
|
||||
5. 验证:顶点位置改变、法线重新计算、BVH更新
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、性能预期
|
||||
|
||||
### 内存占用
|
||||
|
||||
- **小网格(20×20×20)**:约 0.5 MB
|
||||
- **中网格(50×50×50)**:约 4 MB
|
||||
- **大网格(100×100×100)**:约 67 MB
|
||||
|
||||
### 计算延迟(一次锤击)
|
||||
|
||||
- GPU应力传播:0.1ms × 3迭代 = 0.3ms
|
||||
- GPU位移计算:0.1ms
|
||||
- CPU下载:约 1ms(异步)
|
||||
- 顶点更新:约 5ms(10万顶点)
|
||||
- **总延迟**:约 6-7ms(<16.7ms/60fps)✅
|
||||
|
||||
---
|
||||
|
||||
## 九、物理模型说明
|
||||
|
||||
### 简化的应力-应变关系
|
||||
|
||||
本系统使用简化模型:
|
||||
```
|
||||
位移 = 应力 × 柔度 × 塑性系数
|
||||
Δu = σ × C × P
|
||||
```
|
||||
|
||||
其中:
|
||||
- `σ`:应力(Pa)
|
||||
- `C`:柔度系数 (ComplianceFactor)
|
||||
- `P`:塑性系数(温度决定,0-1)
|
||||
|
||||
### 温度对塑性的影响
|
||||
|
||||
塑性系数从温度系统读取(复用PlasticityBuffer):
|
||||
```
|
||||
P = Smoothstep((T - T_min) / (T_max - T_min))
|
||||
```
|
||||
- 温度越高 → 塑性越强 → 应力更易转换为位移
|
||||
|
||||
### 体积守恒近似
|
||||
|
||||
压缩方向位移后,横向补偿:
|
||||
```
|
||||
压缩量 = |位移 · 方向|
|
||||
横向膨胀 = -压缩量 × 守恒强度 × 0.5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、调试建议
|
||||
|
||||
1. **日志级别**
|
||||
- 使用 `UE_LOG(LogTemp, Warning, ...)` 输出关键数据
|
||||
- 每个阶段添加性能计时
|
||||
|
||||
2. **可视化工具**
|
||||
- 顶点颜色显示应力分布(蓝色=低,红色=高)
|
||||
- Debug Gizmo绘制体素应力箭头
|
||||
|
||||
3. **参数调优UI**
|
||||
- 所有物理参数暴露到Blueprint
|
||||
- 实时调整观察效果
|
||||
|
||||
4. **逐步验证**
|
||||
- 先验证CPU逻辑(阶段1)
|
||||
- 再验证GPU传输(阶段2)
|
||||
- 最后验证GPU计算(阶段3)
|
||||
|
||||
---
|
||||
|
||||
## 十一、与现有系统的集成
|
||||
|
||||
### 与温度系统协作
|
||||
|
||||
- **共享缓冲区**:`PlasticityBuffer`、`SurfaceVoxelFlagsBuffer`
|
||||
- **共享分辨率**:`TemperatureResolution` 用于变形体素网格
|
||||
- **调度顺序**:温度计算(每1秒) → 变形计算(锤击触发)
|
||||
|
||||
### 与BVH系统协作
|
||||
|
||||
- 每次 `UpdateVertexDeformation()` 后调用 `GenerateBVH()`
|
||||
- 确保碰撞检测使用最新几何
|
||||
|
||||
### 与顶点颜色系统协作
|
||||
|
||||
- 可选:混合显示温度(红色)+ 应力(蓝色)
|
||||
- 或独立显示:切换模式(温度模式 / 应力模式)
|
||||
|
||||
---
|
||||
|
||||
**计划完成**。建议按照实现步骤逐步推进,每个阶段充分测试后再进入下一阶段。
|
||||
Reference in New Issue
Block a user