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 explicit Gradient(float inValue) : mMin(inValue), mMax(inValue) { }
116 Gradient(float inMin, float inMax, float inMinFraction = 0.0f, float inMaxFraction = 1.0f) : mMin(inMin), mMax(inMax), mMinFraction(inMinFraction), mMaxFraction(inMaxFraction) { }
117
129 Gradient MakeStepDependent(float inTimeRatio) const
130 {
131 auto make_dependent = [inTimeRatio](float inValue) {
132 return 1.0f - std::pow(1.0f - inValue, inTimeRatio);
133 };
134
135 return Gradient(make_dependent(mMin), make_dependent(mMax), mMinFraction, mMaxFraction);
136 }
137
139 void SaveBinaryState(StreamOut &inStream) const;
140
142 void RestoreBinaryState(StreamIn &inStream);
143
144 float mMin = 0.0f;
145 float mMax = 1.0f;
146 float mMinFraction = 0.0f;
147 float mMaxFraction = 1.0f;
148 };
149
151 {
152 public:
153 GradientSampler() = default;
154
155 explicit GradientSampler(const Gradient &inGradient) :
156 mMultiplier((inGradient.mMax - inGradient.mMin) / (inGradient.mMaxFraction - inGradient.mMinFraction)),
157 mOffset(inGradient.mMin - inGradient.mMinFraction * mMultiplier),
158 mMin(min(inGradient.mMin, inGradient.mMax)),
159 mMax(max(inGradient.mMin, inGradient.mMax))
160 {
161 }
162
164 inline float Sample(float inFraction) const
165 {
166 return min(mMax, max(mMin, mOffset + inFraction * mMultiplier));
167 }
168
169 inline float Sample(const SStrand &inStrand, uint32 inVertex) const
170 {
171 return Sample(float(inVertex - inStrand.mStartVtx) / float(inStrand.VertexCount() - 1));
172 }
173
175 inline Float4 ToFloat4() const
176 {
177 return Float4(mMultiplier, mOffset, mMin, mMax);
178 }
179
180 private:
181 float mMultiplier;
182 float mOffset;
183 float mMin;
184 float mMax;
185 };
186
189 {
191
192
193 bool NeedsGrid() const { return mGridVelocityFactor.mMin != 0.0f || mGridVelocityFactor.mMax != 0.0f || mGridDensityForceFactor != 0.0f; }
194
196 bool GlobalPoseOnly() const { return !mEnableCollision && mGlobalPose.mMin == 1.0f && mGlobalPose.mMax == 1.0f; }
197
199 float GetBendCompliance(float inStrandFraction) const
200 {
201 float fraction = inStrandFraction * 3.0f;
202 uint idx = min(uint(fraction), 2u);
203 fraction = fraction - float(idx);
204 JPH_ASSERT(fraction >= 0.0f && fraction <= 1.0f);
205 float multiplier = mBendComplianceMultiplier[idx] * (1.0f - fraction) + mBendComplianceMultiplier[idx + 1] * fraction;
206 return multiplier * mBendCompliance;
207 }
208
209 bool mEnableCollision = true;
210 bool mEnableLRA = true;
211 float mLinearDamping = 2.0f;
212 float mAngularDamping = 2.0f;
213 float mMaxLinearVelocity = 10.0f;
214 float mMaxAngularVelocity = 50.0f;
215 Gradient mGravityFactor { 0.1f, 1.0f, 0.2f, 0.8f };
216 float mFriction = 0.2f;
217 float mBendCompliance = 1.0e-7f;
218 Float4 mBendComplianceMultiplier = { 1.0f, 100.0f, 100.0f, 1.0f };
219 float mStretchCompliance = 1.0e-8f;
220 float mInertiaMultiplier = 10.0f;
221 Gradient mHairRadius = { 0.001f, 0.001f };
222 Gradient mWorldTransformInfluence { 0.0f, 1.0f };
223 Gradient mGridVelocityFactor { 0.05f, 0.01f };
224 float mGridDensityForceFactor = 0.0f;
225 Gradient mGlobalPose { 0.01f, 0, 0.0f, 0.3f };
226 Gradient mSkinGlobalPose { 1.0f, 0.0f, 0.0f, 0.1f };
227 float mSimulationStrandsFraction = 0.1f;
228 float mGravityPreloadFactor = 0.0f;
229 };
230
235 void InitRenderAndSimulationStrands(const Array<SVertex> &inVertices, const Array<SStrand> &inStrands);
236
238 static void sResample(Array<SVertex> &ioVertices, Array<SStrand> &ioStrands, uint32 inNumVerticesPerStrand);
239
242 void Init(float &outMaxDistSqHairToScalp);
243
245 void InitCompute(ComputeSystem *inComputeSystem);
246
248 float GetNeutralDensity(uint32 inX, uint32 inY, uint32 inZ) const
249 {
250 JPH_ASSERT(inX < mGridSize.GetX() && inY < mGridSize.GetY() && inZ < mGridSize.GetZ());
251 return mNeutralDensity[inX + inY * mGridSize.GetX() + inZ * mGridSize.GetX() * mGridSize.GetY()];
252 }
253
256 {
257 return uint32(mSimStrands.size()) * mMaxVerticesPerStrand;
258 }
259
264 void PrepareForScalpSkinning(Mat44Arg inJointToHair, const Mat44 *inJointMatrices, Mat44 *outJointMatrices) const;
265
270 void SkinScalpVertices(Mat44Arg inJointToHair, const Mat44 *inJointMatrices, Array<Vec3> &outVertices) const;
271
273 void SaveBinaryState(StreamOut &inStream) const;
274
276 void RestoreBinaryState(StreamIn &inStream);
277
279 {
280 public:
281 inline explicit GridSampler(const HairSettings *inSettings) :
282 mGridSizeMin2(inSettings->mGridSize - UVec4::sReplicate(2)),
283 mGridSizeMin1((inSettings->mGridSize - UVec4::sReplicate(1)).ToFloat()),
284 mGridStride(1, inSettings->mGridSize.GetX(), inSettings->mGridSize.GetX() * inSettings->mGridSize.GetY(), 0),
285 mOffset(inSettings->mSimulationBounds.mMin),
286 mScale(Vec3(inSettings->mGridSize.ToFloat()) / inSettings->mSimulationBounds.GetSize())
287 {
288 }
289
291 inline void PositionToIndexAndFraction(Vec3Arg inPosition, UVec4 &outIndex, Vec3 &outFraction) const
292 {
293 // Get position in grid space
294 Vec3 grid_pos = Vec3::sMin(Vec3::sMax(inPosition - mOffset, Vec3::sZero()) * mScale, mGridSizeMin1);
295 outIndex = UVec4::sMin(Vec4(grid_pos).ToInt(), mGridSizeMin2);
296 outFraction = grid_pos - Vec3(outIndex.ToFloat());
297 }
298
299 template <typename F>
300 inline void Sample(UVec4Arg inIndex, Vec3Arg inFraction, const F &inFunc) const
301 {
302 Vec3 fraction[] = { Vec3::sReplicate(1.0f) - inFraction, inFraction };
303
304 // Sample the grid
305 for (uint32 z = 0; z < 2; ++z)
306 for (uint32 y = 0; y < 2; ++y)
307 for (uint32 x = 0; x < 2; ++x)
308 {
309 uint32 index = mGridStride.Dot(inIndex + UVec4(x, y, z, 0));
310 float combined_fraction = fraction[x].GetX() * fraction[y].GetY() * fraction[z].GetZ();
311 inFunc(index, combined_fraction);
312 }
313 }
314
315 template <typename F>
316 inline void Sample(Vec3Arg inPosition, const F &inFunc) const
317 {
318 UVec4 index;
319 Vec3 fraction;
320 PositionToIndexAndFraction(inPosition, index, fraction);
321 Sample(index, fraction, inFunc);
322 }
323
329 };
330
331 static constexpr uint32 cDefaultIterationsPerSecond = 360;
332
335
338
343 uint mScalpNumSkinWeightsPerVertex = 0;
344
345 uint32 mNumIterationsPerSecond = cDefaultIterationsPerSecond;
346 float mMaxDeltaTime = 1.0f / 30.0f;
347 UVec4 mGridSize { 32, 32, 32, 0 };
348 Vec3 mSimulationBoundsPadding = Vec3::sReplicate(0.1f);
349 Vec3 mInitialGravity { 0, -9.81f, 0 };
351
352 // Values computed by Init
354 AABox mSimulationBounds { Vec3::sZero(), 1.0f };
356 float mDensityScale = 0.0f;
357 uint32 mMaxVerticesPerStrand = 0;
358
359 // Compute data
374};
375
#define JPH_EXPORT
Definition Core.h:303
unsigned int uint
Definition Core.h:564
#define JPH_NAMESPACE_END
Definition Core.h:487
std::uint32_t uint32
Definition Core.h:567
#define JPH_NAMESPACE_BEGIN
Definition Core.h:481
#define JPH_ASSERT(...)
Definition IssueReporting.h:28
#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:22
Interface to run a workload on the GPU.
Definition ComputeSystem.h:16
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:129
Gradient(float inValue)
Definition HairSettings.h:115
Gradient(float inMin, float inMax, float inMinFraction=0.0f, float inMaxFraction=1.0f)
Definition HairSettings.h:116
Definition HairSettings.h:151
float Sample(const SStrand &inStrand, uint32 inVertex) const
Definition HairSettings.h:169
GradientSampler(const Gradient &inGradient)
Definition HairSettings.h:155
Float4 ToFloat4() const
Convert to Float4 to pass to shader.
Definition HairSettings.h:175
float Sample(float inFraction) const
Sample the value along the strand.
Definition HairSettings.h:164
Definition HairSettings.h:279
Vec3 mGridSizeMin1
Definition HairSettings.h:325
UVec4 mGridSizeMin2
Definition HairSettings.h:324
void Sample(UVec4Arg inIndex, Vec3Arg inFraction, const F &inFunc) const
Definition HairSettings.h:300
GridSampler(const HairSettings *inSettings)
Definition HairSettings.h:281
Vec3 mScale
Definition HairSettings.h:328
void PositionToIndexAndFraction(Vec3Arg inPosition, UVec4 &outIndex, Vec3 &outFraction) const
Convert a position in hair space to a grid index and fraction.
Definition HairSettings.h:291
UVec4 mGridStride
Definition HairSettings.h:326
void Sample(Vec3Arg inPosition, const F &inFunc) const
Definition HairSettings.h:316
Vec3 mOffset
Definition HairSettings.h:327
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:333
Array< SStrand > mSimStrands
Defines the start and end of each simulated strand.
Definition HairSettings.h:334
Array< SkinWeight > mScalpSkinWeights
Skin weights of the scalp mesh, for each vertex we have mScalpNumSkinWeightsPerVertex entries.
Definition HairSettings.h:342
Ref< ComputeBuffer > mVerticesBishopCB
Definition HairSettings.h:366
Array< SkinPoint > mSkinPoints
For each simulated vertex, where it is attached to the scalp mesh.
Definition HairSettings.h:353
Ref< ComputeBuffer > mScalpSkinWeightsCB
Definition HairSettings.h:362
Ref< ComputeBuffer > mVerticesLengthCB
Definition HairSettings.h:368
Ref< ComputeBuffer > mVerticesOmega0CB
Definition HairSettings.h:367
Ref< ComputeBuffer > mScalpVerticesCB
Definition HairSettings.h:360
Ref< ComputeBuffer > mVerticesStrandFractionCB
Definition HairSettings.h:369
Array< float > mNeutralDensity
Neutral density grid used to apply forces to keep the hair in place.
Definition HairSettings.h:355
Array< Mat44 > mScalpInverseBindPose
Inverse bind pose of the scalp mesh, joints are in model space.
Definition HairSettings.h:341
float GetNeutralDensity(uint32 inX, uint32 inY, uint32 inZ) const
Sample the neutral density at a grid position.
Definition HairSettings.h:248
Ref< ComputeBuffer > mScalpTrianglesCB
Definition HairSettings.h:361
Array< RStrand > mRenderStrands
Defines the start and end of each rendered strand.
Definition HairSettings.h:337
Array< Material > mMaterials
Materials used by the hair strands.
Definition HairSettings.h:350
Ref< ComputeBuffer > mSkinPointsCB
Definition HairSettings.h:363
Ref< ComputeBuffer > mStrandVertexCountsCB
Definition HairSettings.h:370
Ref< ComputeBuffer > mVerticesPositionCB
Definition HairSettings.h:365
Array< RVertex > mRenderVertices
Rendered vertices. Used by mRenderStrands.
Definition HairSettings.h:336
Ref< ComputeBuffer > mVerticesFixedCB
Definition HairSettings.h:364
Ref< ComputeBuffer > mSVertexInfluencesCB
Definition HairSettings.h:373
Ref< ComputeBuffer > mStrandMaterialIndexCB
Definition HairSettings.h:371
Array< Float3 > mScalpVertices
Vertices of the scalp mesh, used to attach hairs. Note that the hair vertices mSimVertices must be in...
Definition HairSettings.h:339
Array< IndexedTriangleNoMaterial > mScalpTriangles
Triangles of the scalp mesh.
Definition HairSettings.h:340
Ref< ComputeBuffer > mNeutralDensityCB
Definition HairSettings.h:372
uint32 GetNumVerticesPadded() const
Get the number of vertices in the vertex buffers padded to a multiple of mMaxVerticesPerStrand.
Definition HairSettings.h:255
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:110
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:156
JPH_INLINE Vec4 ToFloat() const
Convert each component from an int to a float.
Definition UVec4.inl:510
Definition Vec3.h:17
static JPH_INLINE Vec3 sMax(Vec3Arg inV1, Vec3Arg inV2)
Return the maximum of each of the components.
Definition Vec3.inl:203
static JPH_INLINE Vec3 sMin(Vec3Arg inV1, Vec3Arg inV2)
Return the minimum value of each of the components.
Definition Vec3.inl:183
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:125
static JPH_INLINE Vec3 sReplicate(float inV)
Replicate inV across all components.
Definition Vec3.inl:141
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:189
bool GlobalPoseOnly() const
If this material only needs running the global pose logic.
Definition HairSettings.h:196
float GetBendCompliance(float inStrandFraction) const
Calculate the bend compliance at a fraction along the strand.
Definition HairSettings.h:199
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