UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
PBDStiffness.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Core.h"
9#include "ChaosStats.h"
10
12
13namespace Chaos::Softs
14{
15
20class FPBDStiffness final : public FPBDWeightMap
21{
22public:
23 static constexpr FSolverReal ParameterFrequency = (FSolverReal)120.; // 60Hz @ 2 iterations as a root for all stiffness values TODO: Make this a global solver parameter
26 static constexpr int32 DefaultTableSize = 16;
27
31 inline FPBDStiffness(
34 int32 ParticleCount = 0, // A value of 0 also disables the map
35 int32 TableSize = DefaultTableSize, // Size of the lookup table, can't be more than 256 values, the larger the table the longer it takes to apply changes to the stiffness values
36 FSolverReal InParameterFitBase = DefaultParameterFitBase, // Logarithm base to use in the PBD stiffness parameter fit function
38
42 template<int32 Valence UE_REQUIRES(Valence >= 2 && Valence <= 4)>
43 inline FPBDStiffness(
47 int32 ParticleOffset = INDEX_NONE, // Constraints have usually a particle offset added to them compared to the weight maps that always starts at index 0
48 int32 ParticleCount = 0, // A value of 0 also disables the map
49 int32 TableSize = DefaultTableSize, // Size of the lookup table, can't be more than 256 values, the larger the table the longer it takes to apply changes to the stiffness values
50 FSolverReal InParameterFitBase = DefaultParameterFitBase, // Logarithm base to use in the PBD stiffness parameter fit function
51 FSolverReal MaxStiffness = DefaultPBDMaxStiffness);
52
53 virtual ~FPBDStiffness() override = default;
54
55 FPBDStiffness(const FPBDStiffness&) = default;
59
69
71 inline void ApplyPBDValues(const FSolverReal Dt, const int32 NumIterations);
72
74 inline void ApplyXPBDValues(const FSolverReal MaxStiffnesss);
75
76private:
77 FSolverReal ParameterFitBase;
78 FSolverReal ParameterFitLogBase;
79 FSolverReal PrevDtOrMaxStiffness = (FSolverReal)0.;
80 int32 PrevNumIterations = 0;
82};
83
87 int32 ParticleCount,
88 int32 TableSize,
90 FSolverReal MaxStiffness)
91 : FPBDWeightMap(FSolverVec2::ZeroVector, Multipliers, ParticleCount, TableSize)
92 , ParameterFitBase(InParameterFitBase)
93 , ParameterFitLogBase(FMath::Loge(InParameterFitBase))
94{
95 SetWeightedValue(InWeightedValue, MaxStiffness);
96}
97
98template<int32 Valence UE_REQUIRES_DEFINITION(Valence >= 2 && Valence <= 4)>
103 int32 ParticleOffset,
104 int32 ParticleCount,
105 int32 TableSize,
107 FSolverReal MaxStiffness)
108 : FPBDWeightMap(FSolverVec2::ZeroVector, Multipliers, Constraints, ParticleOffset, ParticleCount, TableSize)
109 , ParameterFitBase(InParameterFitBase)
110 , ParameterFitLogBase(FMath::Loge(InParameterFitBase))
111{
112 SetWeightedValue(InWeightedValue, MaxStiffness);
113}
114
115static inline FSolverReal CalcExponentialParameterFit(const FSolverReal ParameterFitBase, const FSolverReal ParameterFitLogBase, const FSolverReal InValue)
116{
117 // Get a very steep exponential curve between the [0, 1] range to make easier to set the parameter
118 // The base has been chosen empirically.
119 // ParameterFit = (pow(ParameterFitBase , InValue) - 1) / (ParameterFitBase - 1)
120 // Note that ParameterFit = 0 when InValue = 0, and 1 when InValue = 1.
121 return (FMath::Exp(ParameterFitLogBase * InValue) - (FSolverReal)1.) / (ParameterFitBase - (FSolverReal)1.);
122}
123
124void FPBDStiffness::ApplyPBDValues(const FSolverReal Dt, const int32 NumIterations)
125{
127
128 // Calculate the simulation exponent
129 const FSolverReal Exponent = Dt * ParameterFrequency / (FSolverReal)NumIterations;
130
131 // Define the stiffness mapping function
132 auto SimulationValue = [this, Exponent](const FSolverReal InValue)->FSolverReal
133 {
134 // If InValue is 1 then LogValue = -inf and the output becomes -inf as well,
135 // in order for this function to be continuous, we want the output to be 1 when InValue = 1
136 // and need the stiffness to be exactly 0 when the input is 0
138 {
139 return (FSolverReal)0.;
140 }
142 {
143 return (FSolverReal)1.;
144 }
145 const FSolverReal ParameterFit = CalcExponentialParameterFit(ParameterFitBase, ParameterFitLogBase, InValue);
146
147 // Use simulation dependent stiffness exponent to alleviate the variations in effect when Dt and NumIterations change
148 // This is based on the Position-Based Simulation Methods paper (page 8),
149 // but uses the delta time in addition of the number of iterations in the calculation of the error term.
150 const FSolverReal LogValue = FMath::Loge((FSolverReal)1. - ParameterFit);
151 return (FSolverReal)1. - FMath::Exp(LogValue * Exponent);
152 };
153
154 if (Dt != PrevDtOrMaxStiffness || NumIterations != PrevNumIterations)
155 {
156 PrevDtOrMaxStiffness = Dt;
157 PrevNumIterations = NumIterations;
158 bIsDirty = true;
159 }
160
161 FPBDWeightMap::ApplyValues(SimulationValue); // Note, this still needs to be called even when not dirty for dealing with any change in weights
162}
163
165{
167
168 auto SimulationValue = [this, MaxStiffness](const FSolverReal InValue)->FSolverReal
169 {
170 // Do not apply exponential to XPBDStiffnesses. They are authored in terms of true stiffness values (e.g., kg/s^2), not exponential compliance
171 return FMath::Clamp(InValue, (FSolverReal)0., MaxStiffness);
172 };
173
174 if (MaxStiffness != PrevDtOrMaxStiffness)
175 {
176 PrevDtOrMaxStiffness = MaxStiffness;
177 bIsDirty = true;
178 }
179
180 FPBDWeightMap::ApplyValues(SimulationValue); // Note, this still needs to be called even when not dirty for dealing with any change in weights
181}
182
183} // End namespace Chaos::Softs
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define DECLARE_CYCLE_STAT(CounterName, StatId, GroupId)
Definition Stats.h:669
#define SCOPE_CYCLE_COUNTER(Stat)
Definition Stats.h:650
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_DOUBLE_SMALL_NUMBER
Definition UnrealMathUtility.h:139
Definition PBDStiffness.h:21
void SetWeightedValue(const FSolverVec2 &InWeightedValue, FSolverReal MaxStiffness=DefaultPBDMaxStiffness)
Definition PBDStiffness.h:65
virtual ~FPBDStiffness() override=default
FPBDStiffness(const FPBDStiffness &)=default
static constexpr FSolverReal DefaultPBDMaxStiffness
Definition PBDStiffness.h:24
FPBDStiffness & operator=(const FPBDStiffness &)=default
FPBDStiffness(FPBDStiffness &&)=default
void ApplyPBDValues(const FSolverReal Dt, const int32 NumIterations)
Definition PBDStiffness.h:124
FPBDStiffness & operator=(FPBDStiffness &&)=default
static constexpr int32 DefaultTableSize
Definition PBDStiffness.h:26
static constexpr FSolverReal ParameterFrequency
Definition PBDStiffness.h:23
FPBDStiffness(const FSolverVec2 &InWeightedValue, const TConstArrayView< FRealSingle > &Multipliers=TConstArrayView< FRealSingle >(), int32 ParticleCount=0, int32 TableSize=DefaultTableSize, FSolverReal InParameterFitBase=DefaultParameterFitBase, FSolverReal InMaxStiffness=DefaultPBDMaxStiffness)
Definition PBDStiffness.h:84
void ApplyXPBDValues(const FSolverReal MaxStiffnesss)
Definition PBDStiffness.h:164
static constexpr FSolverReal DefaultParameterFitBase
Definition PBDStiffness.h:25
Definition PBDWeightMap.h:19
void ApplyValues(bool *bOutUpdated=nullptr)
Definition PBDWeightMap.h:71
void SetWeightedValue(const FSolverVec2 &InWeightedValue)
Definition PBDWeightMap.h:62
bool bIsDirty
Definition PBDWeightMap.h:113
Definition Constraints.Build.cs:6
Definition CollectionEmbeddedSpringConstraintFacade.cpp:6
FRealSingle FSolverReal
Definition PBDSoftsEvolutionFwd.h:31
Definition UnrealMathUtility.h:270
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592