HairIntegrate.h 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2026 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. float DeltaDensity(uint inIndex)
  5. {
  6. return gVelocityAndDensity[inIndex].w - gNeutralDensity[inIndex];
  7. }
  8. void ApplyGrid(JPH_IN(JPH_HairPosition) inPos, JPH_IN_OUT(JPH_HairVelocity) ioVel, JPH_IN(JPH_HairMaterial) inMaterial, float inStrandFraction)
  9. {
  10. if (!inMaterial.mEnableGrid)
  11. return;
  12. // Convert position to grid index and fraction
  13. uint3 index;
  14. float3 ma;
  15. GridPositionToIndexAndFraction(inPos.mPosition, index, ma);
  16. float3 a = float3(1, 1, 1) - ma;
  17. // Get average velocity at the vertex position (trilinear sample)
  18. float3 velocity;
  19. uint3 stride = cGridStride;
  20. uint adr_000 = GridIndexToBufferIndex(index);
  21. uint adr_100 = adr_000 + 1;
  22. uint adr_010 = adr_000 + stride.y;
  23. uint adr_110 = adr_010 + 1;
  24. velocity = gVelocityAndDensity[adr_000].xyz * ( a.x * a.y * a.z);
  25. velocity += gVelocityAndDensity[adr_100].xyz * (ma.x * a.y * a.z);
  26. velocity += gVelocityAndDensity[adr_010].xyz * ( a.x * ma.y * a.z);
  27. velocity += gVelocityAndDensity[adr_110].xyz * (ma.x * ma.y * a.z);
  28. velocity += gVelocityAndDensity[adr_000 + stride.z].xyz * ( a.x * a.y * ma.z);
  29. velocity += gVelocityAndDensity[adr_100 + stride.z].xyz * (ma.x * a.y * ma.z);
  30. velocity += gVelocityAndDensity[adr_010 + stride.z].xyz * ( a.x * ma.y * ma.z);
  31. velocity += gVelocityAndDensity[adr_110 + stride.z].xyz * (ma.x * ma.y * ma.z);
  32. // Drive towards the average velocity of the cell
  33. ioVel.mVelocity += GradientSamplerSample(inMaterial.mGridVelocityFactor, inStrandFraction) * (velocity - ioVel.mVelocity);
  34. // Calculate force to go towards neutral density
  35. // Based on eq 3 of Volumetric Methods for Simulation and Rendering of Hair - Lena Petrovic, Mark Henne and John Anderson
  36. float dd000 = DeltaDensity(adr_000);
  37. float dd100 = DeltaDensity(adr_100);
  38. float dd010 = DeltaDensity(adr_010);
  39. float dd110 = DeltaDensity(adr_110);
  40. float dd001 = DeltaDensity(adr_000 + stride.z);
  41. float dd101 = DeltaDensity(adr_100 + stride.z);
  42. float dd011 = DeltaDensity(adr_010 + stride.z);
  43. float dd111 = DeltaDensity(adr_110 + stride.z);
  44. float3 force = float3(
  45. a.y * a.z * (dd000 - dd100)
  46. + ma.y * a.z * (dd010 - dd110)
  47. + a.y * ma.z * (dd001 - dd101)
  48. + ma.y * ma.z * (dd011 - dd111),
  49. a.x * a.z * (dd000 - dd010)
  50. + ma.x * a.z * (dd100 - dd110)
  51. + a.x * ma.z * (dd001 - dd011)
  52. + ma.x * ma.z * (dd101 - dd111),
  53. a.x * a.y * (dd000 - dd001)
  54. + ma.x * a.y * (dd100 - dd101)
  55. + a.x * ma.y * (dd010 - dd011)
  56. + ma.x * ma.y * (dd110 - dd111));
  57. ioVel.mVelocity += inMaterial.mGridDensityForceFactor * force * cDeltaTime; // / mass, but mass is 1
  58. }
  59. void Integrate(JPH_IN_OUT(JPH_HairPosition) ioPos, JPH_IN(JPH_HairVelocity) inVel, JPH_IN(JPH_HairMaterial) inMaterial, float inStrandFraction)
  60. {
  61. JPH_HairVelocity vel = inVel;
  62. // Gravity
  63. vel.mVelocity += cSubStepGravity * GradientSamplerSample(inMaterial.mGravityFactor, inStrandFraction);
  64. // Damping
  65. vel.mVelocity *= inMaterial.mExpLinearDampingDeltaTime;
  66. vel.mAngularVelocity *= inMaterial.mExpAngularDampingDeltaTime;
  67. // Integrate position
  68. ioPos.mPosition += vel.mVelocity * cDeltaTime;
  69. // Integrate rotation
  70. JPH_Quat rotation = ioPos.mRotation;
  71. JPH_Quat delta_rotation = cHalfDeltaTime * JPH_QuatImaginaryMulQuat(vel.mAngularVelocity, rotation);
  72. ioPos.mRotation = normalize(rotation + delta_rotation);
  73. }