ScaleHelpers.h 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Physics/PhysicsSettings.h>
  6. JPH_NAMESPACE_BEGIN
  7. /// Helper functions to get properties of a scaling vector
  8. namespace ScaleHelpers
  9. {
  10. /// The tolerance used to check if components of the scale vector are the same
  11. static constexpr float cScaleToleranceSq = 1.0e-8f;
  12. /// Test if a scale is identity
  13. inline bool IsNotScaled(Vec3Arg inScale) { return inScale.IsClose(Vec3::sReplicate(1.0f), cScaleToleranceSq); }
  14. /// Test if a scale is uniform
  15. inline bool IsUniformScale(Vec3Arg inScale) { return inScale.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>().IsClose(inScale, cScaleToleranceSq); }
  16. /// Scale the convex radius of an object
  17. inline float ScaleConvexRadius(float inConvexRadius, Vec3Arg inScale) { return min(inConvexRadius * inScale.Abs().ReduceMin(), cDefaultConvexRadius); }
  18. /// Test if a scale flips an object inside out (which requires flipping all normals and polygon windings)
  19. inline bool IsInsideOut(Vec3Arg inScale) { return (CountBits(Vec3::sLess(inScale, Vec3::sZero()).GetTrues() & 0x7) & 1) != 0; }
  20. /// Get the average scale if inScale, used to make the scale uniform when a shape doesn't support non-uniform scale
  21. inline Vec3 MakeUniformScale(Vec3Arg inScale) { return Vec3::sReplicate((inScale.GetX() + inScale.GetY() + inScale.GetZ()) / 3.0f); }
  22. /// Checks in scale can be rotated to child shape
  23. /// @param inRotation Rotation of child shape
  24. /// @param inScale Scale in local space of parent shape
  25. /// @return True if the scale is valid (no shearing introduced)
  26. inline bool CanScaleBeRotated(QuatArg inRotation, Vec3Arg inScale)
  27. {
  28. // inScale is a scale in local space of the shape, so the transform for the shape (ignoring translation) is: T = Mat44::sScale(inScale) * mRotation.
  29. // when we pass the scale to the child it needs to be local to the child, so we want T = mRotation * Mat44::sScale(ChildScale).
  30. // Solving for ChildScale: ChildScale = mRotation^-1 * Mat44::sScale(inScale) * mRotation = mRotation^T * Mat44::sScale(inScale) * mRotation
  31. // If any of the off diagonal elements are non-zero, it means the scale / rotation is not compatible.
  32. Mat44 r = Mat44::sRotation(inRotation);
  33. Mat44 child_scale = r.Multiply3x3LeftTransposed(r.PostScaled(inScale));
  34. // Get the columns, but zero the diagonal
  35. Vec4 zero = Vec4::sZero();
  36. Vec4 c0 = Vec4::sSelect(child_scale.GetColumn4(0), zero, UVec4(0xffffffff, 0, 0, 0)).Abs();
  37. Vec4 c1 = Vec4::sSelect(child_scale.GetColumn4(1), zero, UVec4(0, 0xffffffff, 0, 0)).Abs();
  38. Vec4 c2 = Vec4::sSelect(child_scale.GetColumn4(2), zero, UVec4(0, 0, 0xffffffff, 0)).Abs();
  39. // Check if all elements are less than epsilon
  40. Vec4 epsilon = Vec4::sReplicate(1.0e-6f);
  41. return UVec4::sAnd(UVec4::sAnd(Vec4::sLess(c0, epsilon), Vec4::sLess(c1, epsilon)), Vec4::sLess(c2, epsilon)).TestAllTrue();
  42. }
  43. /// Adjust scale for rotated child shape
  44. /// @param inRotation Rotation of child shape
  45. /// @param inScale Scale in local space of parent shape
  46. /// @return Rotated scale
  47. inline Vec3 RotateScale(QuatArg inRotation, Vec3Arg inScale)
  48. {
  49. // Get the diagonal of mRotation^T * Mat44::sScale(inScale) * mRotation (see comment at CanScaleBeRotated)
  50. Mat44 r = Mat44::sRotation(inRotation);
  51. return r.Multiply3x3LeftTransposed(r.PostScaled(inScale)).GetDiagonal3();
  52. }
  53. }
  54. JPH_NAMESPACE_END