Files
BladeSmith/docs/plans/plastic-deformation-voxel-system-plan.md
T
zhangqing 61016f9c2a 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>
2026-01-20 19:29:49 +08:00

22 KiB
Raw Blame History

BladeSmith塑性变形体素系统 - 实现计划

概述

基于现有温度系统架构,构建一个完整的塑性变形体素系统。系统采用两步法:

  1. 应力传播阶段:锤击施加应力,通过GPU迭代计算应力在体素间扩散
  2. 位移计算阶段:从应力分布计算位移场,应用到网格顶点

核心设计决策

  • 物理模型:简化模型(塑性流动 + 应变软化 + 体积守恒)
  • 体素数据:存储应力、应变、位移(混合方式)
  • GPU架构:应力Ping-Pong双缓冲 + 独立位移/应变缓冲
  • 锤击响应:两步法(应力注入 → GPU计算 → 顶点更新)
  • 内存占用:36字节/体素(20³网格 = 281KB,100³网格 = 34.4MB)

一、数据结构设计

1.1 变形体素结构(添加到DynamicIronBlock.h)

/**
 * 变形体素结构 - 存储单个体素的力学状态
 * 大小: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)

// ========== 变形系统数据 ==========

// 变形体素网格(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 (新建)

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 (新建)

[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 (新建)

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 (新建)

[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)

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 应力注入函数

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 从体素位移场采样到顶点

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 三线性插值采样位移

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数据流

  1. 创建GPU缓冲区

    • CreateDeformationGPUBuffers(): 创建所有RHI缓冲区
    • ReleaseDeformationGPUBuffers(): 清理资源
  2. 数据传输

    • UploadDeformationStressToGPU(): 应力数据 CPU→GPU
    • DownloadDeformationDataAndApplyToMesh(): 位移数据 GPU→CPU
    • 测试:上传后立即下载,验证数据完整性

阶段3:GPU计算着色器(3-4天)

目标:实现两阶段GPU计算

  1. 应力传播Shader

    • 新建 FStressPropagationShader.h/cpp (参考FTemperatureComputeShader)
    • 新建 StressPropagationCS.usf
    • 实现6邻域扩散 + 应力松弛
    • 测试:单点应力观察传播
  2. 位移计算Shader

    • 新建 FDisplacementFromStressShader.h/cpp
    • 新建 DisplacementFromStressCS.usf
    • 实现应力→位移 + 体积守恒
    • 测试:固定应力验证位移
  3. 调度逻辑

    • DispatchStressPropagationCompute(): RDG调度应力传播
    • DispatchDisplacementCompute(): RDG调度位移计算
    • 测试:完整流程(应力→传播→位移→网格)

阶段4:集成和优化(2-3天)

目标:完整集成,调优参数

  1. 修改锤击逻辑

    • 更新 OnHammerImpact() 使用新系统
    • 保留旧逻辑作为fallback (OnHammerImpact_Legacy())
  2. 参数调优

    • 调整物理参数观察效果
    • 确保变形符合物理直觉
  3. 性能优化

    • 添加性能日志
    • 优化迭代次数
    • 考虑局部更新
  4. 调试工具

    • 可视化应力分布(顶点颜色)
    • 可视化位移场(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()

需要新建的文件

  1. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Public\FStressPropagationShader.h

    • 应力传播着色器类声明
  2. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Private\FStressPropagationShader.cpp

    • Shader实现(IMPLEMENT_GLOBAL_SHADER)
  3. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Public\FDisplacementFromStressShader.h

    • 位移计算着色器类声明
  4. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Source\MiceShaders\Private\FDisplacementFromStressShader.cpp

    • Shader实现
  5. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Shaders\Private\StressPropagationCS.usf

    • 应力传播HLSL代码
  6. C:\MiceCola\Indi\BladeSmith\Plugins\MiceShaders\Shaders\Private\DisplacementFromStressCS.usf

    • 位移计算HLSL代码

七、验证和测试

单元测试

  1. 体素索引测试

    • 验证 GetTemperatureIndex() 3D→1D转换正确性
    • 测试边界情况
  2. 插值测试

    • 设置8个体素位移为已知值
    • 验证中心点插值结果精度
  3. 应力衰减测试

    • 注入单点应力
    • 验证距离衰减符合高斯曲线

集成测试

  1. 锤击响应测试

    • 冷态测试(塑性=0):锤击应无明显变形
    • 热态测试(塑性=1):锤击应有深度变形
    • 体积守恒验证:压缩区深度 ≈ 凸起区体积
  2. 性能测试

    • 测量每次锤击耗时(目标 <7ms)
    • 验证60fps稳定性
    • GPU占用率监控

物理验证

  1. 应力传播验证

    • 单点冲击应力向周围扩散
    • 表面体素应力快速释放
  2. 温度-塑性耦合验证

    • 高温区域深度变形
    • 低温区域轻微变形

端到端测试

  1. 完整流程测试
    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()
  • 确保碰撞检测使用最新几何

与顶点颜色系统协作

  • 可选:混合显示温度(红色)+ 应力(蓝色)
  • 或独立显示:切换模式(温度模式 / 应力模式)

计划完成。建议按照实现步骤逐步推进,每个阶段充分测试后再进入下一阶段。