diff --git a/docs/plans/plastic-deformation-voxel-system-plan.md b/docs/plans/plastic-deformation-voxel-system-plan.md new file mode 100644 index 0000000..19e3370 --- /dev/null +++ b/docs/plans/plastic-deformation-voxel-system-plan.md @@ -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 DeformationGrid; + +// 原始网格顶点位置(未变形状态) +TArray 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 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, InputStressBuffer) + SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer, PlasticityBuffer) + SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer, SurfaceVoxelFlagsBuffer) + SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, 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, StressBuffer) + SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer, PlasticityBuffer) + SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer, PreviousStrainBuffer) + SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, OutputDisplacementBuffer) + SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, 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()` +- 确保碰撞检测使用最新几何 + +### 与顶点颜色系统协作 + +- 可选:混合显示温度(红色)+ 应力(蓝色) +- 或独立显示:切换模式(温度模式 / 应力模式) + +--- + +**计划完成**。建议按照实现步骤逐步推进,每个阶段充分测试后再进入下一阶段。