UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MuscleActivationConstraints.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Curve.h"
8
10
11namespace Chaos::Softs
12{
13 using Chaos::TVec3;
16 template <typename T, typename ParticleType>
18 {
19 public:
20 //Handles muscle activation data
22
24
25 void AddMuscles(const ParticleType& RestParticles, const Facade& FMuscleActivation, int32 VertexOffset = 0, int32 ElementOffset = 0)
26 {
27 for (int MuscleIdx = 0; MuscleIdx < FMuscleActivation.NumMuscles(); MuscleIdx++)
28 {
29 Data MuscleActivationData = FMuscleActivation.GetMuscleActivationData(MuscleIdx);
30 if (FMuscleActivation.IsValidGeometryIndex(MuscleActivationData.GeometryGroupIndex))
31 {
32 if (ensureMsgf(MuscleActivationData.MuscleLengthRatioThresholdForMaxActivation > 0 &&
33 MuscleActivationData.MuscleLengthRatioThresholdForMaxActivation < 1,
34 TEXT("MuscleLengthRatioThresholdForMaxActivation %f of muscle indexed %d is out of range (0,1), please check your setup."), MuscleActivationData.MuscleLengthRatioThresholdForMaxActivation, MuscleIdx)
35 &&
36 ensureMsgf(MuscleActivationData.MuscleActivationElement.Num() == MuscleActivationData.FiberDirectionMatrix.Num(),
37 TEXT("MuscleActivationElement size %d is not equal to FiberDirectionMatrix size %d for muscle indexed %d"), MuscleActivationData.MuscleActivationElement.Num(), MuscleActivationData.FiberDirectionMatrix.Num(), MuscleIdx)
38 &&
39 ensureMsgf(MuscleActivationData.FiberLengthRatioAtMaxActivation > 0 &&
40 MuscleActivationData.FiberLengthRatioAtMaxActivation < 1,
41 TEXT("FiberLengthRatioAtMaxActivation %f of muscle indexed %d is out of range (0,1), please check your setup."), MuscleActivationData.FiberLengthRatioAtMaxActivation, MuscleIdx)
42 &&
43 ensureMsgf(MuscleActivationData.InflationVolumeScale > 0,
44 TEXT("FiberLengthRatioAtMaxActivation %f of muscle indexed %d is <= 0, please check your setup."), MuscleActivationData.InflationVolumeScale, MuscleIdx))
45 {
47 MuscleActivationData.OriginInsertionPair[1] += VertexOffset;
48 if (!RestParticles.XArray().IsValidIndex(MuscleActivationData.OriginInsertionPair[0]) ||
49 !RestParticles.XArray().IsValidIndex(MuscleActivationData.OriginInsertionPair[1]))
50 {
51 UE_LOG(LogMuscleActivationConstraint, Error, TEXT("Muscle Idx[%d] has invalid origin[%d] or insertion[%d]."),
52 MuscleIdx, MuscleActivationData.OriginInsertionPair[0], MuscleActivationData.OriginInsertionPair[1]);
53 continue;
54 }
55 const int32 OldSize = MuscleActivationElement.AddDefaulted(1);
56 FiberDirectionMatrix.AddDefaulted(1);
57 ContractionVolumeScale.AddDefaulted(1);
58 for (int32 i = 0; i < MuscleActivationData.MuscleActivationElement.Num(); i++)
59 {
60 if (FMuscleActivation.IsValidElementIndex(MuscleActivationData.MuscleActivationElement[i]))
61 {
62 MuscleActivationElement[OldSize].Add(MuscleActivationData.MuscleActivationElement[i] + ElementOffset);
63 FiberDirectionMatrix[OldSize].Add(MuscleActivationData.FiberDirectionMatrix[i]);
64 ContractionVolumeScale[OldSize].Add(MuscleActivationData.ContractionVolumeScale[i]);
65 }
66 }
67 FiberLengthRatioAtMaxActivation.Add(MuscleActivationData.FiberLengthRatioAtMaxActivation);
68 MuscleLengthRatioThresholdForMaxActivation.Add(MuscleActivationData.MuscleLengthRatioThresholdForMaxActivation);
69 InflationVolumeScale.Add(MuscleActivationData.InflationVolumeScale);
70 OriginInsertionPair.Add(MuscleActivationData.OriginInsertionPair);
71 MuscleRestLength.Add((RestParticles.GetX(MuscleActivationData.OriginInsertionPair[0]) - RestParticles.GetX(MuscleActivationData.OriginInsertionPair[1])).Size());
72 MuscleActivation.Add(0.f);
73 MuscleVertexOffset.Add(FMuscleActivation.MuscleVertexOffset(MuscleIdx));
74 MuscleVertexCount.Add(FMuscleActivation.NumMuscleVertices(MuscleIdx));
75 LengthActivationCurves.Add(FMuscleActivation.GetLengthActivationCurve(MuscleIdx));
76 }
77 }
78 else
79 {
80 UE_LOG(LogMuscleActivationConstraint, Error, TEXT("Muscle Idx[%d] has invalid geometry index[%d]."),
81 MuscleIdx, MuscleActivationData.GeometryGroupIndex);
82 }
83 }
84 }
85
87 {
88 for (int32 MuscleIdx = 0; MuscleIdx < MuscleActivationElement.Num(); MuscleIdx++)
89 {
90 if (ensureMsgf(MuscleLengthRatioThresholdForMaxActivation[MuscleIdx] > 0 &&
91 MuscleLengthRatioThresholdForMaxActivation[MuscleIdx] < 1,
92 TEXT("MuscleLengthRatioThresholdForMaxActivation %f of muscle indexed %d is out of range (0,1), please check your setup."), MuscleLengthRatioThresholdForMaxActivation[MuscleIdx], MuscleIdx))
93 {
94 // calculate origin/insertion length
95 const float MuscleLengthRatio = (InParticles.P(OriginInsertionPair[MuscleIdx][0]) - InParticles.P(OriginInsertionPair[MuscleIdx][1])).Size() / MuscleRestLength[MuscleIdx];
96 if (MuscleLengthRatio >= 1.f)
97 {
98 // not active
99 MuscleActivation[MuscleIdx] = 0.f;
100 }
101 else
102 {
103 float NormalizedMuscleLengthLevel = FMath::Clamp((1.f - MuscleLengthRatio) / (1 - MuscleLengthRatioThresholdForMaxActivation[MuscleIdx]), 0.f, 1.f);
104 if (LengthActivationCurves[MuscleIdx].GetNumKeys())
105 {
106 MuscleActivation[MuscleIdx] = LengthActivationCurves[MuscleIdx].Eval(NormalizedMuscleLengthLevel);
107 }
108 else
109 {
110 // no keys, default to linear muscle activation model: muscle reaches max activation 1 at threshold length
111 MuscleActivation[MuscleIdx] = NormalizedMuscleLengthLevel;
112 }
113 }
114 }
115 }
116 }
117
119 {
120 for (int32 MuscleIdx = 0; MuscleIdx < MuscleActivationElement.Num(); MuscleIdx++)
121 {
122 if (ensureMsgf(MuscleActivationElement[MuscleIdx].Num() == FiberDirectionMatrix[MuscleIdx].Num(),
123 TEXT("MuscleActivationElement[%d].Num() = %d, not equal to FiberDirectionMatrix[%d].Num() = %d"), MuscleIdx, MuscleActivationElement[MuscleIdx].Num(), MuscleIdx, FiberDirectionMatrix[MuscleIdx].Num())
124 && ensureMsgf(FiberLengthRatioAtMaxActivation[MuscleIdx] > 0 &&
125 FiberLengthRatioAtMaxActivation[MuscleIdx] < 1,
126 TEXT("FiberLengthRatioAtMaxActivation %f of muscle indexed %d is out of range (0,1), please check your setup."), FiberLengthRatioAtMaxActivation[MuscleIdx], MuscleIdx))
127 {
128 const float FiberLengthRatio = 1.f - MuscleActivation[MuscleIdx] * (1.f - FiberLengthRatioAtMaxActivation[MuscleIdx]);
129 for (int32 ElemIdx = 0; ElemIdx < MuscleActivationElement[MuscleIdx].Num(); ElemIdx++)
130 {
131 Constraints.ModifyDmInverseFromMuscleLength(MuscleActivationElement[MuscleIdx][ElemIdx], FiberLengthRatio, FiberDirectionMatrix[MuscleIdx][ElemIdx], ContractionVolumeScale[MuscleIdx][ElemIdx]);
132 }
133 }
134 }
135 }
136
138 {
139 for (int32 MuscleIdx = 0; MuscleIdx < MuscleActivationElement.Num(); MuscleIdx++)
140 {
141 if (ensureMsgf(MuscleActivationElement[MuscleIdx].Num() == FiberDirectionMatrix[MuscleIdx].Num(),
142 TEXT("MuscleActivationElement[%d].Num() = %d, not equal to FiberDirectionMatrix[%d].Num() = %d"), MuscleIdx, MuscleActivationElement[MuscleIdx].Num(), MuscleIdx, FiberDirectionMatrix[MuscleIdx].Num())
143 && ensureMsgf(InflationVolumeScale[MuscleIdx] > 0,
144 TEXT("InflationVolumeScale %f of muscle indexed %d is <= 0, please check your setup."), InflationVolumeScale[MuscleIdx], MuscleIdx))
145 {
146 for (int32 ElemIdx = 0; ElemIdx < MuscleActivationElement[MuscleIdx].Num(); ElemIdx++)
147 {
148 Constraints.ModifyDmInverseSaveFromInflationVolumeScale(MuscleActivationElement[MuscleIdx][ElemIdx], InflationVolumeScale[MuscleIdx], FiberDirectionMatrix[MuscleIdx][ElemIdx]);
149 }
150 }
151 }
152 }
153
154 int32 NumMuscles() { return MuscleActivationElement.Num(); };
155 int32 GetMuscleVertexOffset(int32 MuscleIndex) { return MuscleVertexOffset[MuscleIndex]; };
156 int32 GetMuscleVertexCount(int32 MuscleIndex) { return MuscleVertexCount[MuscleIndex]; };
157
158 /* returns muscle activation of the specified muscle */
160 if (MuscleActivation.IsValidIndex(MuscleIndex))
161 {
162 return MuscleActivation[MuscleIndex];
163 }
164 return 0.f;
165 };
166
167 /* Sets muscle activation of the specified muscle and returns bool for success*/
169 {
170 if (MuscleActivation.IsValidIndex(MuscleIndex))
171 {
172 MuscleActivation[MuscleIndex] = FMath::Clamp(InMuscleActivation, 0.f, 1.f);
173 return true;
174 }
175 return false;
176 };
177
178 private:
179 TArray<TArray<int32>> MuscleActivationElement;
180 TArray<FIntVector2> OriginInsertionPair;
181 TArray<float> MuscleRestLength;
182 TArray<float> MuscleActivation;
183 TArray<TArray<Chaos::PMatrix33d>> FiberDirectionMatrix;
184 TArray<TArray<float>> ContractionVolumeScale;
185 TArray<float> FiberLengthRatioAtMaxActivation;
186 TArray<float> MuscleLengthRatioThresholdForMaxActivation;
187 TArray<float> InflationVolumeScale;
188 TArray<Chaos::FLinearCurve> LengthActivationCurves;
189 TArray<int32> MuscleVertexOffset;
190 TArray<int32> MuscleVertexCount;
191 };
192
193
194}// End namespace Chaos::Softs
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define DEFINE_LOG_CATEGORY_STATIC(CategoryName, DefaultVerbosity, CompileTimeVerbosity)
Definition LogMacros.h:380
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
@ Num
Definition MetalRHIPrivate.h:234
uint32 Size
Definition VulkanMemory.cpp:4034
Definition MuscleActivationConstraints.h:18
void AddMuscles(const ParticleType &RestParticles, const Facade &FMuscleActivation, int32 VertexOffset=0, int32 ElementOffset=0)
Definition MuscleActivationConstraints.h:25
int32 GetMuscleVertexCount(int32 MuscleIndex)
Definition MuscleActivationConstraints.h:156
int32 NumMuscles()
Definition MuscleActivationConstraints.h:154
float GetMuscleActivation(int32 MuscleIndex) const
Definition MuscleActivationConstraints.h:159
void UpdateLengthBasedMuscleActivation(const ParticleType &InParticles)
Definition MuscleActivationConstraints.h:86
void ApplyMuscleActivation(FXPBDCorotatedConstraints< T, ParticleType > &Constraints) const
Definition MuscleActivationConstraints.h:118
void ApplyInflationVolumeScale(FXPBDCorotatedConstraints< T, ParticleType > &Constraints) const
Definition MuscleActivationConstraints.h:137
int32 GetMuscleVertexOffset(int32 MuscleIndex)
Definition MuscleActivationConstraints.h:155
bool SetMuscleActivation(int32 MuscleIndex, float InMuscleActivation)
Definition MuscleActivationConstraints.h:168
virtual ~FMuscleActivationConstraints()
Definition MuscleActivationConstraints.h:23
FMuscleActivationConstraints()
Definition MuscleActivationConstraints.h:21
Definition XPBDCorotatedConstraints.h:20
Definition Vector.h:1000
Definition Constraints.Build.cs:6
Definition CollectionMuscleActivationFacade.h:35
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
SizeType AddDefaulted()
Definition Array.h:2795
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
Definition CollectionEmbeddedSpringConstraintFacade.cpp:6
GeometryCollection::Facades::FMuscleActivationFacade Facade
Definition MuscleActivationConstraints.h:14
GeometryCollection::Facades::FMuscleActivationData Data
Definition MuscleActivationConstraints.h:15
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
Definition CollectionMuscleActivationFacade.h:20
FIntVector2 OriginInsertionPair
Definition CollectionMuscleActivationFacade.h:23