Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
HairSettings.h
Go to the documentation of this file.
1// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2// SPDX-FileCopyrightText: 2026 Jorrit Rouwe
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
14
16
17class StreamOut;
18class StreamIn;
19
21class JPH_EXPORT HairSettings : public RefTarget<HairSettings>
22{
24
25public:
27 struct JPH_EXPORT SkinWeight : public JPH_HairSkinWeight
28 {
30 };
31
33 struct JPH_EXPORT SkinPoint : public JPH_HairSkinPoint
34 {
36 };
37
38 static constexpr uint32 cNoInfluence = ~uint32(0);
39
41 struct JPH_EXPORT SVertexInfluence : public JPH_HairSVertexInfluence
42 {
44
45 inline SVertexInfluence() { mVertexIndex = cNoInfluence; mRelativePosition = JPH_float3(0, 0, 0); mWeight = 0.0f; }
46 };
47
50 {
52
53 Float3 mPosition { 0, 0, 0 };
54 SVertexInfluence mInfluences[cHairNumSVertexInfluences];
55 };
56
59 {
61
62
63 SVertex() = default;
64 explicit SVertex(const Float3 &inPosition, float inInvMass = 1.0f) : mPosition(inPosition), mInvMass(inInvMass) { }
65
66 Float3 mPosition { 0, 0, 0 };
67 float mInvMass = 1.0f;
68 float mLength = 0.0f;
69 float mStrandFraction = 0.0f;
70 Float4 mBishop { 0, 0, 0, 1.0f };
71 Float4 mOmega0 { 0, 0, 0, 1.0f };
72 };
73
76 {
78
79
80 RStrand() = default;
81 RStrand(uint32 inStartVtx, uint32 inEndVtx) : mStartVtx(inStartVtx), mEndVtx(inEndVtx) { }
82
83 uint32 VertexCount() const { return mEndVtx - mStartVtx; }
84
85 float MeasureLength(const Array<SVertex> &inVertices) const
86 {
87 float length = 0.0f;
88 for (uint32 v = mStartVtx; v < mEndVtx - 1; ++v)
89 length += (Vec3(inVertices[v + 1].mPosition) - Vec3(inVertices[v].mPosition)).Length();
90 return length;
91 }
92
95 };
96
98 struct JPH_EXPORT SStrand : public RStrand
99 {
101
102 SStrand() = default;
103 SStrand(uint32 inStartVtx, uint32 inEndVtx, uint32 inMaterialIndex) : RStrand(inStartVtx, inEndVtx), mMaterialIndex(inMaterialIndex) { }
104
105 uint32 mMaterialIndex = 0;
106 };
107
110 {
112
113 public:
114 Gradient() = default;
115 Gradient(float inMin, float inMax, float inMinFraction = 0.0f, float inMaxFraction = 1.0f) : mMin(inMin), mMax(inMax), mMinFraction(inMinFraction), mMaxFraction(inMaxFraction) { }
116
128 Gradient MakeStepDependent(float inTimeRatio) const
129 {
130 auto make_dependent = [inTimeRatio](float inValue) {
131 return 1.0f - std::pow(1.0f - inValue, inTimeRatio);
132 };
133
134 return Gradient(make_dependent(mMin), make_dependent(mMax), mMinFraction, mMaxFraction);
135 }
136
138 void SaveBinaryState(StreamOut &inStream) const;
139
141 void RestoreBinaryState(StreamIn &inStream);
142
143 float mMin = 0.0f;
144 float mMax = 1.0f;
145 float mMinFraction = 0.0f;
146 float mMaxFraction = 1.0f;
147 };
148
150 {
151 public:
152 GradientSampler() = default;
153
154 explicit GradientSampler(const Gradient &inGradient) :
155 mMultiplier((inGradient.mMax - inGradient.mMin) / (inGradient.mMaxFraction - inGradient.mMinFraction)),
156 mOffset(inGradient.mMin - inGradient.mMinFraction * mMultiplier),
157 mMin(min(inGradient.mMin, inGradient.mMax)),
158 mMax(max(inGradient.mMin, inGradient.mMax))
159 {
160 }
161
163 inline float Sample(float inFraction) const
164 {
165 return min(mMax, max(mMin, mOffset + inFraction * mMultiplier));
166 }
167
168 inline float Sample(const SStrand &inStrand, uint32 inVertex) const
169 {
170 return Sample(float(inVertex - inStrand.mStartVtx) / float(inStrand.VertexCount() - 1));
171 }
172
174 inline Float4 ToFloat4() const
175 {
176 return Float4(mMultiplier, mOffset, mMin, mMax);
177 }
178
179 private:
180 float mMultiplier;
181 float mOffset;
182 float mMin;
183 float mMax;
184 };
185
188 {
190
191
192 bool NeedsGrid() const { return mGridVelocityFactor.mMin != 0.0f || mGridVelocityFactor.mMax != 0.0f || mGridDensityForceFactor != 0.0f; }
193
195 bool GlobalPoseOnly() const { return !mEnableCollision && mGlobalPose.mMin == 1.0f && mGlobalPose.mMax == 1.0f; }
196
198 float GetBendCompliance(float inStrandFraction) const
199 {
200 float fraction = inStrandFraction * 3.0f;
201 uint idx = min(uint(fraction), 2u);
202 fraction = fraction - float(idx);
203 JPH_ASSERT(fraction >= 0.0f && fraction <= 1.0f);
204 float multiplier = mBendComplianceMultiplier[idx] * (1.0f - fraction) + mBendComplianceMultiplier[idx + 1] * fraction;
205 return multiplier * mBendCompliance;
206 }
207
208 bool mEnableCollision = true;
209 bool mEnableLRA = true;
210 float mLinearDamping = 2.0f;
211 float mAngularDamping = 2.0f;
212 float mMaxLinearVelocity = 10.0f;
213 float mMaxAngularVelocity = 50.0f;
214 Gradient mGravityFactor { 0.1f, 1.0f, 0.2f, 0.8f };
215 float mFriction = 0.2f;
216 float mBendCompliance = 1.0e-7f;
217 Float4 mBendComplianceMultiplier = { 1.0f, 100.0f, 100.0f, 1.0f };
218 float mStretchCompliance = 1.0e-8f;
219 float mInertiaMultiplier = 10.0f;
220 Gradient mHairRadius = { 0.001f, 0.001f };
221 Gradient mWorldTransformInfluence { 0.0f, 1.0f };
222 Gradient mGridVelocityFactor { 0.05f, 0.01f };
223 float mGridDensityForceFactor = 0.0f;
224 Gradient mGlobalPose { 0.01f, 0, 0.0f, 0.3f };
225 Gradient mSkinGlobalPose { 1.0f, 0.0f, 0.0f, 0.1f };
226 float mSimulationStrandsFraction = 0.1f;
227 float mGravityPreloadFactor = 0.0f;
228 };
229
234 void InitRenderAndSimulationStrands(const Array<SVertex> &inVertices, const Array<SStrand> &inStrands);
235
237 static void sResample(Array<SVertex> &ioVertices, Array<SStrand> &ioStrands, uint32 inNumVerticesPerStrand);
238
241 void Init(float &outMaxDistSqHairToScalp);
242
244 void InitCompute(ComputeSystem *inComputeSystem);
245
247 float GetNeutralDensity(uint32 inX, uint32 inY, uint32 inZ) const
248 {
249 JPH_ASSERT(inX < mGridSize.GetX() && inY < mGridSize.GetY() && inZ < mGridSize.GetZ());
250 return mNeutralDensity[inX + inY * mGridSize.GetX() + inZ * mGridSize.GetX() * mGridSize.GetY()];
251 }
252
255 {
256 return uint32(mSimStrands.size()) * mMaxVerticesPerStrand;
257 }
258
263 void PrepareForScalpSkinning(Mat44Arg inJointToHair, const Mat44 *inJointMatrices, Mat44 *outJointMatrices) const;
264
269 void SkinScalpVertices(Mat44Arg inJointToHair, const Mat44 *inJointMatrices, Array<Vec3> &outVertices) const;
270
272 void SaveBinaryState(StreamOut &inStream) const;
273
275 void RestoreBinaryState(StreamIn &inStream);
276
278 {
279 public:
280 inline explicit GridSampler(const HairSettings *inSettings) :
281 mGridSizeMin2(inSettings->mGridSize - UVec4::sReplicate(2)),
282 mGridSizeMin1((inSettings->mGridSize - UVec4::sReplicate(1)).ToFloat()),
283 mGridStride(1, inSettings->mGridSize.GetX(), inSettings->mGridSize.GetX() * inSettings->mGridSize.GetY(), 0),
284 mOffset(inSettings->mSimulationBounds.mMin),
285 mScale(Vec3(inSettings->mGridSize.ToFloat()) / inSettings->mSimulationBounds.GetSize())
286 {
287 }
288
290 inline void PositionToIndexAndFraction(Vec3Arg inPosition, UVec4 &outIndex, Vec3 &outFraction) const
291 {
292 // Get position in grid space
293 Vec3 grid_pos = Vec3::sMin(Vec3::sMax(inPosition - mOffset, Vec3::sZero()) * mScale, mGridSizeMin1);
294 outIndex = UVec4::sMin(Vec4(grid_pos).ToInt(), mGridSizeMin2);
295 outFraction = grid_pos - Vec3(outIndex.ToFloat());
296 }
297
298 template <typename F>
299 inline void Sample(UVec4Arg inIndex, Vec3Arg inFraction, const F &inFunc) const
300 {
301 Vec3 fraction[] = { Vec3::sReplicate(1.0f) - inFraction, inFraction };
302
303 // Sample the grid
304 for (uint32 z = 0; z < 2; ++z)
305 for (uint32 y = 0; y < 2; ++y)
306 for (uint32 x = 0; x < 2; ++x)
307 {
308 uint32 index = mGridStride.Dot(inIndex + UVec4(x, y, z, 0));
309 float combined_fraction = fraction[x].GetX() * fraction[y].GetY() * fraction[z].GetZ();
310 inFunc(index, combined_fraction);
311 }
312 }
313
314 template <typename F>
315 inline void Sample(Vec3Arg inPosition, const F &inFunc) const
316 {
317 UVec4 index;
318 Vec3 fraction;
319 PositionToIndexAndFraction(inPosition, index, fraction);
320 Sample(index, fraction, inFunc);
321 }
322
328 };
329
330 static constexpr uint32 cDefaultIterationsPerSecond = 360;
331
334
337
342 uint mScalpNumSkinWeightsPerVertex = 0;
343
344 uint32 mNumIterationsPerSecond = cDefaultIterationsPerSecond;
345 float mMaxDeltaTime = 1.0f / 30.0f;
346 UVec4 mGridSize { 32, 32, 32, 0 };
347 Vec3 mSimulationBoundsPadding = Vec3::sReplicate(0.1f);
348 Vec3 mInitialGravity { 0, -9.81f, 0 };
350
351 // Values computed by Init
353 AABox mSimulationBounds { Vec3::sZero(), 1.0f };
355 float mDensityScale = 0.0f;
356 uint32 mMaxVerticesPerStrand = 0;
357
358 // Compute data
373};
374
#define JPH_EXPORT
Definition Core.h:275
unsigned int uint
Definition Core.h:500
#define JPH_NAMESPACE_END
Definition Core.h:425
std::uint32_t uint32
Definition Core.h:503
#define JPH_NAMESPACE_BEGIN
Definition Core.h:419
#define JPH_ASSERT(...)
Definition IssueReporting.h:33
#define JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(linkage, class_name)
Definition SerializableObject.h:80
float3 JPH_float3
Definition ShaderCore.h:42
Axis aligned box.
Definition AABox.h:16
Definition Array.h:36
Interface to run a workload on the GPU.
Definition ComputeSystem.h:15
Class that holds 3 floats. Used as a storage class. Convert to Vec3 for calculations.
Definition Float3.h:13
Class that holds 4 float values. Convert to Vec4 to perform calculations.
Definition Float4.h:11
Gradient along a hair strand of a value, e.g. compliance, friction, etc.
Definition HairSettings.h:110
Gradient MakeStepDependent(float inTimeRatio) const
Definition HairSettings.h:128
Gradient(float inMin, float inMax, float inMinFraction=0.0f, float inMaxFraction=1.0f)
Definition HairSettings.h:115
Definition HairSettings.h:150
float Sample(const SStrand &inStrand, uint32 inVertex) const
Definition HairSettings.h:168
GradientSampler(const Gradient &inGradient)
Definition HairSettings.h:154
Float4 ToFloat4() const
Convert to Float4 to pass to shader.
Definition HairSettings.h:174
float Sample(float inFraction) const
Sample the value along the strand.
Definition HairSettings.h:163
Definition HairSettings.h:278
Vec3 mGridSizeMin1
Definition HairSettings.h:324
UVec4 mGridSizeMin2
Definition HairSettings.h:323
void Sample(UVec4Arg inIndex, Vec3Arg inFraction, const F &inFunc) const
Definition HairSettings.h:299
GridSampler(const HairSettings *inSettings)
Definition HairSettings.h:280
Vec3 mScale
Definition HairSettings.h:327
void PositionToIndexAndFraction(Vec3Arg inPosition, UVec4 &outIndex, Vec3 &outFraction) const
Convert a position in hair space to a grid index and fraction.
Definition HairSettings.h:290
UVec4 mGridStride
Definition HairSettings.h:325
void Sample(Vec3Arg inPosition, const F &inFunc) const
Definition HairSettings.h:315
Vec3 mOffset
Definition HairSettings.h:326
This class defines the setup of a hair groom, it can be shared between multiple hair instances.
Definition HairSettings.h:22
Array< SVertex > mSimVertices
Simulated vertices. Used by mSimStrands.
Definition HairSettings.h:332
Array< SStrand > mSimStrands
Defines the start and end of each simulated strand.
Definition HairSettings.h:333
Array< SkinWeight > mScalpSkinWeights
Skin weights of the scalp mesh, for each vertex we have mScalpNumSkinWeightsPerVertex entries.
Definition HairSettings.h:341
Ref< ComputeBuffer > mVerticesBishopCB
Definition HairSettings.h:365
Array< SkinPoint > mSkinPoints
For each simulated vertex, where it is attached to the scalp mesh.
Definition HairSettings.h:352
Ref< ComputeBuffer > mScalpSkinWeightsCB
Definition HairSettings.h:361
Ref< ComputeBuffer > mVerticesLengthCB
Definition HairSettings.h:367
Ref< ComputeBuffer > mVerticesOmega0CB
Definition HairSettings.h:366
Ref< ComputeBuffer > mScalpVerticesCB
Definition HairSettings.h:359
Ref< ComputeBuffer > mVerticesStrandFractionCB
Definition HairSettings.h:368
Array< float > mNeutralDensity
Neutral density grid used to apply forces to keep the hair in place.
Definition HairSettings.h:354
Array< Mat44 > mScalpInverseBindPose
Inverse bind pose of the scalp mesh, joints are in model space.
Definition HairSettings.h:340
float GetNeutralDensity(uint32 inX, uint32 inY, uint32 inZ) const
Sample the neutral density at a grid position.
Definition HairSettings.h:247
Ref< ComputeBuffer > mScalpTrianglesCB
Definition HairSettings.h:360
Array< RStrand > mRenderStrands
Defines the start and end of each rendered strand.
Definition HairSettings.h:336
Array< Material > mMaterials
Materials used by the hair strands.
Definition HairSettings.h:349
Ref< ComputeBuffer > mSkinPointsCB
Definition HairSettings.h:362
Ref< ComputeBuffer > mStrandVertexCountsCB
Definition HairSettings.h:369
Ref< ComputeBuffer > mVerticesPositionCB
Definition HairSettings.h:364
Array< RVertex > mRenderVertices
Rendered vertices. Used by mRenderStrands.
Definition HairSettings.h:335
Ref< ComputeBuffer > mVerticesFixedCB
Definition HairSettings.h:363
Ref< ComputeBuffer > mSVertexInfluencesCB
Definition HairSettings.h:372
Ref< ComputeBuffer > mStrandMaterialIndexCB
Definition HairSettings.h:370
Array< Float3 > mScalpVertices
Vertices of the scalp mesh, used to attach hairs. Note that the hair vertices mSimVertices must be in...
Definition HairSettings.h:338
Array< IndexedTriangleNoMaterial > mScalpTriangles
Triangles of the scalp mesh.
Definition HairSettings.h:339
Ref< ComputeBuffer > mNeutralDensityCB
Definition HairSettings.h:371
uint32 GetNumVerticesPadded() const
Get the number of vertices in the vertex buffers padded to a multiple of mMaxVerticesPerStrand.
Definition HairSettings.h:254
Holds a 4x4 matrix of floats, but supports also operations on the 3x3 upper left part of the matrix.
Definition Mat44.h:13
Definition Reference.h:107
Definition Reference.h:35
Simple binary input stream.
Definition StreamIn.h:13
Simple binary output stream.
Definition StreamOut.h:13
Definition UVec4.h:12
static JPH_INLINE UVec4 sMin(UVec4Arg inV1, UVec4Arg inV2)
Return the minimum value of each of the components.
Definition UVec4.inl:115
JPH_INLINE Vec4 ToFloat() const
Convert each component from an int to a float.
Definition UVec4.inl:356
Definition Vec3.h:17
static JPH_INLINE Vec3 sMax(Vec3Arg inV1, Vec3Arg inV2)
Return the maximum of each of the components.
Definition Vec3.inl:160
static JPH_INLINE Vec3 sMin(Vec3Arg inV1, Vec3Arg inV2)
Return the minimum value of each of the components.
Definition Vec3.inl:147
JPH_INLINE float GetX() const
Get individual components.
Definition Vec3.h:127
JPH_INLINE float GetY() const
Definition Vec3.h:128
static JPH_INLINE Vec3 sZero()
Vector with all zeros.
Definition Vec3.inl:103
static JPH_INLINE Vec3 sReplicate(float inV)
Replicate inV across all components.
Definition Vec3.inl:114
JPH_INLINE float GetZ() const
Definition Vec3.h:129
Definition Vec4.h:14
The material determines the simulation parameters for a hair strand.
Definition HairSettings.h:188
bool GlobalPoseOnly() const
If this material only needs running the global pose logic.
Definition HairSettings.h:195
float GetBendCompliance(float inStrandFraction) const
Calculate the bend compliance at a fraction along the strand.
Definition HairSettings.h:198
A hair render strand.
Definition HairSettings.h:76
float MeasureLength(const Array< SVertex > &inVertices) const
Definition HairSettings.h:85
uint32 mStartVtx
Definition HairSettings.h:93
uint32 mEndVtx
Definition HairSettings.h:94
uint32 VertexCount() const
Definition HairSettings.h:83
A render vertex.
Definition HairSettings.h:50
A hair simulation strand.
Definition HairSettings.h:99
A simulated vertex in a hair strand.
Definition HairSettings.h:59
Describes how a render vertex is influenced by a simulated vertex.
Definition HairSettings.h:42
Information about where a hair strand is attached to the scalp mesh.
Definition HairSettings.h:34
How much a vertex is influenced by a joint.
Definition HairSettings.h:28