HairUpdateVelocity.h 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2026 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "HairApplyGlobalPose.h"
  5. void ApplyCollisionAndUpdateVelocity(uint inVtx, JPH_IN_OUT(JPH_HairPosition) ioPos, JPH_IN(JPH_HairPosition) inPreviousPos, JPH_IN(JPH_HairMaterial) inMaterial, float inStrandFraction, JPH_OUT(JPH_HairVelocity) outVel)
  6. {
  7. // Update velocities
  8. outVel.mVelocity = (ioPos.mPosition - inPreviousPos.mPosition) / cDeltaTime;
  9. outVel.mAngularVelocity = cTwoDivDeltaTime * JPH_QuatMulQuat(ioPos.mRotation, JPH_QuatConjugate(inPreviousPos.mRotation)).xyz;
  10. if (inMaterial.mEnableCollision)
  11. {
  12. // Calculate closest point on the collision plane
  13. JPH_HairCollisionPlane plane = gCollisionPlanes[inVtx];
  14. float distance_to_plane = JPH_PlaneSignedDistance(plane.mPlane, ioPos.mPosition);
  15. float3 contact_normal = JPH_PlaneGetNormal(plane.mPlane);
  16. float3 point_on_plane = ioPos.mPosition - distance_to_plane * contact_normal;
  17. // Calculate how much the plane moved in this time step
  18. JPH_HairCollisionShape shape = gCollisionShapes[plane.mShapeIndex];
  19. float3 plane_velocity = shape.mLinearVelocity + cross(shape.mAngularVelocity, point_on_plane - shape.mCenterOfMass);
  20. float plane_movement = dot(plane_velocity, contact_normal) * cAccumulatedDeltaTime;
  21. float projected_distance = -distance_to_plane + plane_movement + GradientSamplerSample(inMaterial.mHairRadius, inStrandFraction);
  22. if (projected_distance > 0.0f)
  23. {
  24. // Resolve penetration
  25. ioPos.mPosition += contact_normal * projected_distance;
  26. // Only update velocity when moving towards each other
  27. float3 v_relative = outVel.mVelocity - plane_velocity;
  28. float v_relative_dot_normal = dot(contact_normal, v_relative);
  29. if (v_relative_dot_normal < 0.0f)
  30. {
  31. // Calculate normal and tangential velocity (equation 30)
  32. float3 v_normal = contact_normal * v_relative_dot_normal;
  33. float3 v_tangential = v_relative - v_normal;
  34. float v_tangential_length = length(v_tangential);
  35. // Apply friction as described in Detailed Rigid Body Simulation with Extended Position Based Dynamics - Matthias Muller et al. (modified equation 31)
  36. if (v_tangential_length > 0.0f)
  37. outVel.mVelocity -= v_tangential * min(inMaterial.mFriction * projected_distance / (v_tangential_length * cDeltaTime), 1.0f);
  38. // Apply restitution of zero (equation 35)
  39. outVel.mVelocity -= v_normal;
  40. }
  41. }
  42. }
  43. }
  44. void LimitVelocity(JPH_IN_OUT(JPH_HairVelocity) ioVel, JPH_IN(JPH_HairMaterial) inMaterial)
  45. {
  46. // Limit linear velocity
  47. float linear_velocity_sq = dot(ioVel.mVelocity, ioVel.mVelocity);
  48. if (linear_velocity_sq > inMaterial.mMaxLinearVelocitySq)
  49. ioVel.mVelocity *= sqrt(inMaterial.mMaxLinearVelocitySq / linear_velocity_sq);
  50. // Limit angular velocity
  51. float angular_velocity_sq = dot(ioVel.mAngularVelocity, ioVel.mAngularVelocity);
  52. if (angular_velocity_sq > inMaterial.mMaxAngularVelocitySq)
  53. ioVel.mAngularVelocity *= sqrt(inMaterial.mMaxAngularVelocitySq / angular_velocity_sq);
  54. }