gs.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package physics implements a basic physics engine.
  5. package solver
  6. import (
  7. "time"
  8. "github.com/g3n/engine/math32"
  9. )
  10. // GaussSeidel equation solver.
  11. // See https://en.wikipedia.org/wiki/Gauss-Seidel_method.
  12. // The number of solver iterations determines the quality of the solution.
  13. // More iterations yield a better solution but require more computation.
  14. type GaussSeidel struct {
  15. Solver
  16. Solution
  17. maxIter int // Number of solver iterations.
  18. tolerance float32 // When the error is less than the tolerance, the system is assumed to be converged.
  19. solveInvCs []float32
  20. solveBs []float32
  21. solveLambda []float32
  22. }
  23. // NewGaussSeidel creates and returns a pointer to a new GaussSeidel constraint equation solver.
  24. func NewGaussSeidel() *GaussSeidel {
  25. gs := new(GaussSeidel)
  26. gs.maxIter = 10
  27. gs.tolerance = 1e-7
  28. gs.VelocityDeltas = make([]math32.Vector3, 0)
  29. gs.AngularVelocityDeltas = make([]math32.Vector3, 0)
  30. gs.solveInvCs = make([]float32, 0)
  31. gs.solveBs = make([]float32, 0)
  32. gs.solveLambda = make([]float32, 0)
  33. return gs
  34. }
  35. func (gs *GaussSeidel) Reset() {
  36. gs.VelocityDeltas = gs.VelocityDeltas[0:0]
  37. gs.AngularVelocityDeltas = gs.AngularVelocityDeltas[0:0]
  38. gs.solveInvCs = gs.solveInvCs[0:0]
  39. gs.solveBs = gs.solveBs[0:0]
  40. gs.solveLambda = gs.solveLambda[0:0]
  41. }
  42. // Solve
  43. func (gs *GaussSeidel) Solve(frameDelta time.Duration, nBodies int) int {
  44. gs.Reset()
  45. iter := 0
  46. nEquations := len(gs.equations)
  47. h := float32(frameDelta.Seconds())
  48. // Reset deltas
  49. for i := 0; i < nBodies; i++ {
  50. gs.VelocityDeltas = append(gs.VelocityDeltas, math32.Vector3{0,0,0})
  51. gs.AngularVelocityDeltas = append(gs.AngularVelocityDeltas, math32.Vector3{0,0,0})
  52. }
  53. // Things that do not change during iteration can be computed once
  54. for i := 0; i < nEquations; i++ {
  55. eq := gs.equations[i]
  56. gs.solveInvCs = append(gs.solveInvCs, 1.0 / eq.ComputeC())
  57. gs.solveBs = append(gs.solveBs, eq.ComputeB(h))
  58. gs.solveLambda = append(gs.solveLambda, 0.0)
  59. }
  60. if nEquations > 0 {
  61. tolSquared := gs.tolerance*gs.tolerance
  62. // Iterate over equations
  63. for iter = 0; iter < gs.maxIter; iter++ {
  64. // Accumulate the total error for each iteration.
  65. deltaLambdaTot := float32(0)
  66. for j := 0; j < nEquations; j++ {
  67. eq := gs.equations[j]
  68. // Compute iteration
  69. lambdaJ := gs.solveLambda[j]
  70. idxBodyA := eq.BodyA().Index()
  71. idxBodyB := eq.BodyB().Index()
  72. vA := gs.VelocityDeltas[idxBodyA]
  73. vB := gs.VelocityDeltas[idxBodyB]
  74. wA := gs.AngularVelocityDeltas[idxBodyA]
  75. wB := gs.AngularVelocityDeltas[idxBodyB]
  76. jeA := eq.JeA()
  77. jeB := eq.JeB()
  78. spatA := jeA.Spatial()
  79. spatB := jeB.Spatial()
  80. rotA := jeA.Rotational()
  81. rotB := jeB.Rotational()
  82. GWlambda := jeA.MultiplyVectors(&vA, &wA) + jeB.MultiplyVectors(&vB, &wB)
  83. deltaLambda := gs.solveInvCs[j] * ( gs.solveBs[j] - GWlambda - eq.Eps() *lambdaJ)
  84. // Clamp if we are outside the min/max interval
  85. if lambdaJ+deltaLambda < eq.MinForce() {
  86. deltaLambda = eq.MinForce() - lambdaJ
  87. } else if lambdaJ+deltaLambda > eq.MaxForce() {
  88. deltaLambda = eq.MaxForce() - lambdaJ
  89. }
  90. gs.solveLambda[j] += deltaLambda
  91. deltaLambdaTot += math32.Abs(deltaLambda)
  92. // Add to velocity deltas
  93. gs.VelocityDeltas[idxBodyA].Add(spatA.MultiplyScalar(eq.BodyA().InvMassSolve() * deltaLambda))
  94. gs.VelocityDeltas[idxBodyB].Add(spatB.MultiplyScalar(eq.BodyB().InvMassSolve() * deltaLambda))
  95. // Add to angular velocity deltas
  96. gs.AngularVelocityDeltas[idxBodyA].Add(rotA.ApplyMatrix3(eq.BodyA().InvInertiaWorldSolve()).MultiplyScalar(deltaLambda))
  97. gs.AngularVelocityDeltas[idxBodyB].Add(rotB.ApplyMatrix3(eq.BodyB().InvInertiaWorldSolve()).MultiplyScalar(deltaLambda))
  98. }
  99. // If the total error is small enough - stop iterating
  100. if deltaLambdaTot*deltaLambdaTot < tolSquared {
  101. break
  102. }
  103. }
  104. // Set the .multiplier property of each equation
  105. for i := range gs.equations {
  106. gs.equations[i].SetMultiplier(gs.solveLambda[i] / h)
  107. }
  108. iter += 1
  109. }
  110. return iter
  111. }