Hair.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2026 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Physics/Hair/HairSettings.h>
  6. #include <Jolt/Physics/Collision/ObjectLayer.h>
  7. #include <Jolt/Physics/Collision/Shape/Shape.h>
  8. #include <Jolt/Core/StridedPtr.h>
  9. #include <Jolt/Core/NonCopyable.h>
  10. JPH_NAMESPACE_BEGIN
  11. class PhysicsSystem;
  12. #ifdef JPH_DEBUG_RENDERER
  13. class DebugRenderer;
  14. #endif
  15. class HairShaders;
  16. /// Hair simulation instance
  17. ///
  18. /// Note that this system is currently still in development, it is missing important features like:
  19. ///
  20. /// - Level of detail
  21. /// - Wind forces
  22. /// - Advection step for the grid velocity field
  23. /// - Support for collision detection against shapes other than ConvexHullShape
  24. /// - The Gradient class is very limited and will be replaced by a texture lookup
  25. /// - Gravity preload factor is not fully functioning yet
  26. /// - It is wasteful of memory (e.g. stores everything both on CPU and GPU)
  27. /// - Only supports a single neutral pose to drive towards
  28. /// - It could use further optimizations
  29. class JPH_EXPORT Hair : public NonCopyable
  30. {
  31. public:
  32. /// Constructor / destructor
  33. Hair(const HairSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, ObjectLayer inLayer);
  34. ~Hair();
  35. /// Initialize
  36. void Init(ComputeSystem *inComputeSystem);
  37. /// Position and rotation of the hair in world space
  38. void SetPosition(RVec3Arg inPosition) { mPosition = inPosition; }
  39. void SetRotation(QuatArg inRotation) { mRotation = inRotation; }
  40. RMat44 GetWorldTransform() const { return RMat44::sRotationTranslation(mRotation, mPosition); }
  41. /// Access to the hair settings object which contains the configuration of the hair
  42. const HairSettings * GetHairSettings() const { return mSettings; }
  43. /// The hair will be initialized in its default pose with zero velocity at the new position and rotation during the next update
  44. void OnTeleported() { mTeleported = true; }
  45. /// Ability to externally provide the scalp vertices buffer. This allows skipping skinning the scalp during the simulation update. You may need to override JPH_SHADER_BIND_SCALP_VERTICES in HairSkinRootsBindings.h to match the format of the provided buffer.
  46. void SetScalpVerticesCB(ComputeBuffer *inBuffer) { mScalpVerticesCB = inBuffer; }
  47. /// Ability to externally provide the scalp triangle indices buffer. This allows skipping skinning the scalp in during the simulation update. You may need to override JPH_SHADER_BIND_SCALP_TRIANGLES in HairSkinRootsBindings.h to match the format of the provided buffer.
  48. void SetScalpTrianglesCB(ComputeBuffer *inBuffer) { mScalpTrianglesCB = inBuffer; }
  49. /// When skipping skinning, this allow specifying a transform that transforms the scalp mesh into head space.
  50. void SetScalpToHead(Mat44Arg inMat) { mScalpToHead = inMat; }
  51. /// Function that converts the render positions buffer to Float3 vertices for debugging purposes. It maps an application defined format to Float3. Third parameter is the number of vertices.
  52. using RenderPositionsToFloat3 = std::function<void(ComputeBuffer *, Float3 *, uint)>;
  53. /// Enable externally set render vertices buffer (with potentially different vertex layout). Note that this also requires replacing the HairCalculateRenderPositions shader.
  54. void OverrideRenderPositionsCB(const RenderPositionsToFloat3 &inRenderPositionsToFloat3) { JPH_ASSERT(mRenderPositionsCB == nullptr, "Must be called before Init"); mRenderPositionsOverridden = true; mRenderPositionsToFloat3 = inRenderPositionsToFloat3; }
  55. /// Allow setting the render vertices buffer externally in case it has special requirements for the calling application. You may need to override JPH_SHADER_BIND_RENDER_POSITIONS in HairCalculateRenderPositionsBindings.h to match the format of the provided buffer.
  56. void SetRenderPositionsCB(ComputeBuffer *inBuffer) { JPH_ASSERT(mRenderPositionsOverridden, "Must call OverrideRenderPositionsCB first"); mRenderPositionsCB = inBuffer; }
  57. /// Step the hair simulation forward in time
  58. /// @param inDeltaTime Time step
  59. /// @param inJointToHair Transform that transforms from joint space to hair local space (as defined by GetWorldTransform)
  60. /// @param inJointMatrices Array of joint matrices in world space, length needs to match HairSettings::mScalpInverseBindPose.size()
  61. /// @param inSystem Physics system used for collision detection
  62. /// @param inShaders Preloaded hair compute shaders
  63. /// @param inComputeSystem Compute system to use
  64. /// @param inComputeQueue Compute queue to use
  65. void Update(float inDeltaTime, Mat44Arg inJointToHair, const Mat44 *inJointMatrices, const PhysicsSystem &inSystem, const HairShaders &inShaders, ComputeSystem *inComputeSystem, ComputeQueue *inComputeQueue);
  66. /// Access to the resulting simulation data
  67. ComputeBuffer * GetScalpVerticesCB() const { return mScalpVerticesCB; } ///< Skinned scalp vertices
  68. ComputeBuffer * GetScalpTrianglesCB() const { return mScalpTrianglesCB; } ///< Skinned scalp triangle indices
  69. ComputeBuffer * GetPositionsCB() const { return mPositionsCB; } ///< Note transposed for better memory access
  70. ComputeBuffer * GetVelocitiesCB() const { return mVelocitiesCB; } ///< Note transposed for better memory access
  71. ComputeBuffer * GetVelocityAndDensityCB() const { return mVelocityAndDensityCB; } ///< Velocity grid
  72. ComputeBuffer * GetRenderPositionsCB() const { return mRenderPositionsCB; } ///< Render positions of the hair strands (see HairSettings::mRenderStrands to see where each strand starts and ends)
  73. /// Read back the GPU state so that the functions below can be used. For debugging purposes only, this is slow!
  74. void ReadBackGPUState(ComputeQueue *inComputeQueue);
  75. /// Lock/unlock the data buffers so that the functions below return valid values.
  76. void LockReadBackBuffers();
  77. void UnlockReadBackBuffers();
  78. /// Access to the resulting simulation data (only valid when ReadBackGPUState has been called and the buffers have been locked)
  79. const Float3 * GetScalpVertices() const { return mScalpVertices; }
  80. const Float3 * GetPositions() const { return mPositions; }
  81. const Quat * GetRotations() const { return mRotations; }
  82. StridedPtr<const Float3> GetVelocities() const { return { (const Float3 *)&mVelocities->mVelocity, sizeof(JPH_HairVelocity) }; }
  83. StridedPtr<const Float3> GetAngularVelocities() const { return { (const Float3 *)&mVelocities->mAngularVelocity, sizeof(JPH_HairVelocity) }; }
  84. const Float4 * GetGridVelocityAndDensity() const { return mVelocityAndDensity; }
  85. const Float3 * GetRenderPositions() const { return mRenderPositions; }
  86. #ifdef JPH_DEBUG_RENDERER
  87. enum class ERenderStrandColor
  88. {
  89. PerRenderStrand,
  90. PerSimulatedStrand,
  91. GravityFactor,
  92. WorldTransformInfluence,
  93. GridVelocityFactor,
  94. GlobalPose,
  95. SkinGlobalPose,
  96. };
  97. struct DrawSettings
  98. {
  99. /// This specifies the range of simulation strands to draw, when drawing render strands we only draw the strands that belong to these simulation strands.
  100. uint mSimulationStrandBegin = 0;
  101. uint mSimulationStrandEnd = UINT_MAX;
  102. bool mDrawRods = true; ///< Draws the simulated rods
  103. bool mDrawUnloadedRods = false; ///< Draw rods in their unloaded pose. This pose is obtained by removing gravity influence from the modeled pose.
  104. bool mDrawVertexVelocity = false; ///< Draws the velocity at each simulated vertex as an arrow
  105. bool mDrawAngularVelocity = false; ///< Draws the angular velocity at each simulated vertex as an arrow
  106. bool mDrawOrientations = false; ///< Draws a coordinate space for each simulated vertex
  107. bool mDrawNeutralDensity = false; ///< Draws grid density of the hair in its neutral pose
  108. bool mDrawGridDensity = false; ///< Draws the current grid density of the hair
  109. bool mDrawGridVelocity = false; ///< Draws the velocity of each grid cell as an arrow
  110. bool mDrawSkinPoints = false; ///< Draws the skinning points on the scalp
  111. bool mDrawRenderStrands = false; ///< Draws the render strands (slow, for debugging purposes!)
  112. bool mDrawInitialGravity = true; ///< Draws the configured initial gravity vector used to calculate the unloaded vertex positions
  113. ERenderStrandColor mRenderStrandColor = ERenderStrandColor::PerSimulatedStrand; ///< Color for each strand
  114. };
  115. /// Debug functionality to draw the hair and its simulation properties
  116. void Draw(const DrawSettings &inSettings, DebugRenderer *inRenderer);
  117. #endif // JPH_DEBUG_RENDERER
  118. protected:
  119. using Gradient = HairSettings::Gradient;
  120. using GradientSampler = HairSettings::GradientSampler;
  121. // Information about a colliding shape. Is always a leaf shape, compound shapes are expanded.
  122. struct LeafShape
  123. {
  124. LeafShape() = default;
  125. LeafShape(Mat44Arg inTransform, Vec3Arg inScale, Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, const Shape *inShape) : mTransform(inTransform), mScale(inScale), mLinearVelocity(inLinearVelocity), mAngularVelocity(inAngularVelocity), mShape(inShape) { }
  126. Mat44 mTransform;
  127. Vec3 mScale;
  128. Vec3 mLinearVelocity;
  129. Vec3 mAngularVelocity;
  130. RefConst<Shape> mShape;
  131. };
  132. // Internal context used during a simulation step
  133. struct UpdateContext
  134. {
  135. Mat44 mDeltaTransform; // Transforms positions from the old hair transform to the new
  136. Quat mDeltaTransformQuat; // Rotation part of mDeltaTransform
  137. uint mNumIterations; // Number of iterations to run the solver for
  138. bool mNeedsCollision; // If collision detection should be performed
  139. bool mNeedsGrid; // If the grid should be calculated
  140. bool mGlobalPoseOnly; // If no simulation is needed and only the global pose needs to be applied
  141. bool mHasTransformChanged; // If the world transform has changed
  142. float mDeltaTime; // Delta time for a sub step
  143. float mHalfDeltaTime; // 0.5 * mDeltaTime
  144. float mInvDeltaTimeSq; // 1 / mDeltaTime^2
  145. float mTwoDivDeltaTime; // 2 / mDeltaTime
  146. float mTimeRatio; // Ratio between sub step delta time and default sub step delta time
  147. Vec3 mSubStepGravity; // Gravity to apply in a sub step
  148. Array<LeafShape> mShapes; // List of colliding shapes
  149. };
  150. // Calculate the UpdateContext parameters
  151. void InitializeContext(UpdateContext &outCtx, float inDeltaTime, const PhysicsSystem &inSystem);
  152. RefConst<HairSettings> mSettings; // Shared hair settings, must be kept alive during the lifetime of this hair instance
  153. RVec3 mPrevPosition; // Position at the start of the last time step
  154. RVec3 mPosition; // Current position in world space
  155. Quat mPrevRotation; // Rotation at the start of the last time step
  156. Quat mRotation; // Current rotation in world space
  157. bool mTeleported = true; // If the hair got teleported and should be set to the default pose
  158. ObjectLayer mLayer; // Layer for the hair to collide with
  159. Mat44 mScalpToHead = Mat44::sIdentity(); // When skipping skinning, this allow specifying a transform that transforms the scalp mesh into head space
  160. bool mRenderPositionsOverridden = false; // Indicates that the render positions buffer is provided externally
  161. RenderPositionsToFloat3 mRenderPositionsToFloat3; // Function that transforms the render positions buffer to Float3 vertices for debugging purposes
  162. Ref<ComputeBuffer> mScalpJointMatricesCB;
  163. Ref<ComputeBuffer> mScalpVerticesCB;
  164. Ref<ComputeBuffer> mScalpTrianglesCB;
  165. Ref<ComputeBuffer> mTargetPositionsCB; // Target root positions determined by skinning (where we're interpolating to, eventually written to mPositionsCB)
  166. Ref<ComputeBuffer> mTargetGlobalPoseTransformsCB; // Target global pose transforms determined by skinning (where we're interpolating to, eventually written to mGlobalPoseTransformsCB)
  167. Ref<ComputeBuffer> mGlobalPoseTransformsCB; // Current global pose transforms used for skinning the hairs
  168. Ref<ComputeBuffer> mShapePlanesCB;
  169. Ref<ComputeBuffer> mShapeVerticesCB;
  170. Ref<ComputeBuffer> mShapeIndicesCB;
  171. Ref<ComputeBuffer> mCollisionPlanesCB;
  172. Ref<ComputeBuffer> mCollisionShapesCB;
  173. Ref<ComputeBuffer> mMaterialsCB;
  174. Ref<ComputeBuffer> mPreviousPositionsCB;
  175. Ref<ComputeBuffer> mPositionsCB;
  176. Ref<ComputeBuffer> mVelocitiesCB;
  177. Ref<ComputeBuffer> mVelocityAndDensityCB;
  178. Ref<ComputeBuffer> mConstantsCB;
  179. Array<Ref<ComputeBuffer>> mIterationConstantsCB;
  180. Ref<ComputeBuffer> mRenderPositionsCB;
  181. // Only valid after ReadBackGPUState has been called
  182. Ref<ComputeBuffer> mScalpVerticesReadBackCB;
  183. Ref<ComputeBuffer> mPositionsReadBackCB;
  184. Ref<ComputeBuffer> mVelocitiesReadBackCB;
  185. Ref<ComputeBuffer> mVelocityAndDensityReadBackCB;
  186. Ref<ComputeBuffer> mRenderPositionsReadBackCB;
  187. const Float3 * mScalpVertices = nullptr;
  188. Float3 * mPositions = nullptr;
  189. Quat * mRotations = nullptr;
  190. JPH_HairVelocity * mVelocities = nullptr;
  191. const Float4 * mVelocityAndDensity = nullptr;
  192. const Float3 * mRenderPositions = nullptr;
  193. };
  194. JPH_NAMESPACE_END