simulation.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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
  5. import (
  6. "github.com/g3n/engine/experimental/physics/equation"
  7. "github.com/g3n/engine/experimental/physics/solver"
  8. "github.com/g3n/engine/experimental/physics/constraint"
  9. "github.com/g3n/engine/experimental/collision"
  10. "github.com/g3n/engine/math32"
  11. "github.com/g3n/engine/experimental/physics/object"
  12. "github.com/g3n/engine/core"
  13. "github.com/g3n/engine/experimental/collision/shape"
  14. )
  15. // Simulation represents a physics simulation.
  16. type Simulation struct {
  17. scene *core.Node
  18. forceFields []ForceField
  19. // Bodies under simulation
  20. bodies []*object.Body // Slice of bodies. May contain nil values.
  21. nilBodies []int // Array keeps track of which indices of the 'bodies' array are nil
  22. // Collision tracking
  23. collisionMatrix collision.Matrix // Boolean triangular matrix indicating which pairs of bodies are colliding
  24. prevCollisionMatrix collision.Matrix // CollisionMatrix from the previous step.
  25. allowSleep bool // Makes bodies go to sleep when they've been inactive
  26. paused bool
  27. quatNormalizeSkip int // How often to normalize quaternions. Set to 0 for every step, 1 for every second etc..
  28. // A larger value increases performance.
  29. // If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
  30. quatNormalizeFast bool // Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
  31. time float32 // The wall-clock time since simulation start
  32. stepnumber int // Number of timesteps taken since start
  33. default_dt float32 // Default and last timestep sizes
  34. dt float32 // Currently / last used timestep. Is set to -1 if not available. This value is updated before each internal step, which means that it is "fresh" inside event callbacks.
  35. accumulator float32 // Time accumulator for interpolation. See http://gafferongames.com/game-physics/fix-your-timestep/
  36. broadphase *Broadphase // The broadphase algorithm to use, default is NaiveBroadphase
  37. narrowphase *Narrowphase // The narrowphase algorithm to use
  38. solver solver.ISolver // The solver algorithm to use, default is Gauss-Seidel
  39. constraints []constraint.IConstraint // All constraints
  40. materials []*Material // All added materials
  41. cMaterials []*ContactMaterial
  42. //contactMaterialTable map[intPair]*ContactMaterial // Used to look up a ContactMaterial given two instances of Material.
  43. //defaultMaterial *Material
  44. defaultContactMaterial *ContactMaterial
  45. doProfiling bool
  46. }
  47. // NewSimulation creates and returns a pointer to a new physics simulation.
  48. func NewSimulation(scene *core.Node) *Simulation {
  49. s := new(Simulation)
  50. s.time = 0
  51. s.dt = -1
  52. s.default_dt = 1/60
  53. s.scene = scene
  54. // Set up broadphase, narrowphase, and solver
  55. s.broadphase = NewBroadphase()
  56. s.narrowphase = NewNarrowphase(s)
  57. s.solver = solver.NewGaussSeidel()
  58. s.collisionMatrix = collision.NewMatrix()
  59. s.prevCollisionMatrix = collision.NewMatrix()
  60. //s.contactMaterialTable = make(map[intPair]*ContactMaterial)
  61. //s.defaultMaterial = NewMaterial
  62. s.defaultContactMaterial = NewContactMaterial()
  63. return s
  64. }
  65. func (s *Simulation) Scene() *core.Node {
  66. return s.scene
  67. }
  68. // AddForceField adds a force field to the simulation.
  69. func (s *Simulation) AddForceField(ff ForceField) {
  70. s.forceFields = append(s.forceFields, ff)
  71. }
  72. // RemoveForceField removes the specified force field from the simulation.
  73. // Returns true if found, false otherwise.
  74. func (s *Simulation) RemoveForceField(ff ForceField) bool {
  75. for pos, current := range s.forceFields {
  76. if current == ff {
  77. copy(s.forceFields[pos:], s.forceFields[pos+1:])
  78. s.forceFields[len(s.forceFields)-1] = nil
  79. s.forceFields = s.forceFields[:len(s.forceFields)-1]
  80. return true
  81. }
  82. }
  83. return false
  84. }
  85. // AddBody adds a body to the simulation.
  86. func (s *Simulation) AddBody(body *object.Body, name string) {
  87. // Do nothing if body is already present
  88. for _, existingBody := range s.bodies {
  89. if existingBody == body {
  90. return // Do nothing
  91. }
  92. }
  93. // If there are any open/nil spots in the body slice - add the body to one of them
  94. // Else, just append to the end of the slice. Either way compute the body's index in the slice.
  95. var idx int
  96. nilLen := len(s.nilBodies)
  97. if nilLen > 0 {
  98. idx = s.nilBodies[nilLen]
  99. s.nilBodies = s.nilBodies[0:nilLen-1]
  100. } else {
  101. idx = len(s.bodies)
  102. s.bodies = append(s.bodies, body)
  103. // Initialize collision matrix values up to the current index (and set the colliding flag to false)
  104. s.collisionMatrix.Set(idx, idx, false)
  105. s.prevCollisionMatrix.Set(idx, idx, false)
  106. }
  107. body.SetIndex(idx)
  108. body.SetName(name)
  109. // TODO dispatch add-body event
  110. //s.Dispatch(AddBodyEvent, BodyEvent{body})
  111. }
  112. // RemoveBody removes the specified body from the simulation.
  113. // Returns true if found, false otherwise.
  114. func (s *Simulation) RemoveBody(body *object.Body) bool {
  115. for idx, current := range s.bodies {
  116. if current == body {
  117. s.bodies[idx] = nil
  118. // TODO dispatch remove-body event
  119. //s.Dispatch(AddBodyEvent, BodyEvent{body})
  120. return true
  121. }
  122. }
  123. return false
  124. }
  125. // Clean removes nil bodies from the bodies array, recalculates the body indices and updates the collision matrix.
  126. //func (s *Simulation) Clean() {
  127. //
  128. // // TODO Remove nil bodies from array
  129. // //copy(s.bodies[pos:], s.bodies[pos+1:])
  130. // //s.bodies[len(s.bodies)-1] = nil
  131. // //s.bodies = s.bodies[:len(s.bodies)-1]
  132. //
  133. // // Recompute body indices (each body has a .index int property)
  134. // for i:=0; i<len(s.bodies); i++ {
  135. // s.bodies[i].SetIndex(i)
  136. // }
  137. //
  138. // // TODO Update collision matrix
  139. //
  140. //}
  141. // Bodies returns the slice of bodies under simulation.
  142. // The slice may contain nil values!
  143. func (s *Simulation) Bodies() []*object.Body{
  144. return s.bodies
  145. }
  146. func (s *Simulation) Step(frameDelta float32) {
  147. s.StepPlus(frameDelta, 0, 10)
  148. }
  149. // Step steps the simulation.
  150. // maxSubSteps should be 10 by default
  151. func (s *Simulation) StepPlus(frameDelta float32, timeSinceLastCalled float32, maxSubSteps int) {
  152. if s.paused {
  153. return
  154. }
  155. dt := frameDelta//float32(frameDelta.Seconds())
  156. //if timeSinceLastCalled == 0 { // Fixed, simple stepping
  157. s.internalStep(dt)
  158. // Increment time
  159. //s.time += dt
  160. //} else {
  161. //
  162. // s.accumulator += timeSinceLastCalled
  163. // var substeps = 0
  164. // for s.accumulator >= dt && substeps < maxSubSteps {
  165. // // Do fixed steps to catch up
  166. // s.internalStep(dt)
  167. // s.accumulator -= dt
  168. // substeps++
  169. // }
  170. //
  171. // var t = (s.accumulator % dt) / dt
  172. // for j := 0; j < len(s.bodies); j++ {
  173. // var b = s.bodies[j]
  174. // b.previousPosition.lerp(b.position, t, b.interpolatedPosition)
  175. // b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion)
  176. // b.previousQuaternion.normalize()
  177. // }
  178. // s.time += timeSinceLastCalled
  179. //}
  180. }
  181. // SetPaused sets the paused state of the simulation.
  182. func (s *Simulation) SetPaused(state bool) {
  183. s.paused = state
  184. }
  185. // Paused returns the paused state of the simulation.
  186. func (s *Simulation) Paused() bool {
  187. return s.paused
  188. }
  189. // ClearForces sets all body forces in the world to zero.
  190. func (s *Simulation) ClearForces() {
  191. for i:=0; i < len(s.bodies); i++ {
  192. s.bodies[i].ClearForces()
  193. }
  194. }
  195. // AddConstraint adds a constraint to the simulation.
  196. func (s *Simulation) AddConstraint(c constraint.IConstraint) {
  197. s.constraints = append(s.constraints, c)
  198. }
  199. func (s *Simulation) RemoveConstraint(c constraint.IConstraint) {
  200. // TODO
  201. }
  202. func (s *Simulation) AddMaterial(mat *Material) {
  203. s.materials = append(s.materials, mat)
  204. }
  205. func (s *Simulation) RemoveMaterial(mat *Material) {
  206. // TODO
  207. }
  208. // Adds a contact material to the simulation
  209. func (s *Simulation) AddContactMaterial(cmat *ContactMaterial) {
  210. s.cMaterials = append(s.cMaterials, cmat)
  211. // TODO add contactMaterial materials to contactMaterialTable
  212. // s.contactMaterialTable.set(cmat.materials[0].id, cmat.materials[1].id, cmat)
  213. }
  214. // GetContactMaterial returns the contact material between the specified bodies.
  215. func (s *Simulation) GetContactMaterial(bodyA, bodyB *object.Body) *ContactMaterial {
  216. var cm *ContactMaterial
  217. // TODO
  218. //if bodyA.material != nil && bodyB.material != nil {
  219. // cm = s.contactMaterialTable.get(bodyA.material.id, bodyB.material.id)
  220. // if cm == nil {
  221. // cm = s.defaultContactMaterial
  222. // }
  223. //} else {
  224. cm = s.defaultContactMaterial
  225. //}
  226. return cm
  227. }
  228. // Events =====================
  229. type CollideEvent struct {
  230. body *object.Body
  231. contactEq *equation.Contact
  232. }
  233. // TODO AddBodyEvent, RemoveBodyEvent
  234. type ContactEvent struct {
  235. bodyA *object.Body
  236. bodyB *object.Body
  237. }
  238. const (
  239. BeginContactEvent = "physics.BeginContactEvent"
  240. EndContactEvent = "physics.EndContactEvent"
  241. CollisionEv = "physics.Collision"
  242. )
  243. // ===========================
  244. // ApplySolution applies the specified solution to the bodies under simulation.
  245. // The solution is a set of linear and angular velocity deltas for each body.
  246. // This method alters the solution arrays.
  247. func (s *Simulation) ApplySolution(sol *solver.Solution) {
  248. // Add results to velocity and angular velocity of bodies
  249. for i := 0; i < len(s.bodies); i++ {
  250. s.bodies[i].ApplyVelocityDeltas(&sol.VelocityDeltas[i], &sol.AngularVelocityDeltas[i])
  251. }
  252. }
  253. // Store old collision state info
  254. func (s *Simulation) collisionMatrixTick() {
  255. s.prevCollisionMatrix = s.collisionMatrix
  256. s.collisionMatrix = collision.NewMatrix()
  257. lb := len(s.bodies)
  258. s.collisionMatrix.Set(lb, lb, false)
  259. // TODO verify that the matrices are indeed different
  260. //if s.prevCollisionMatrix == s.collisionMatrix {
  261. // log.Error("SAME")
  262. //}
  263. // TODO
  264. //s.bodyOverlapKeeper.tick()
  265. //s.shapeOverlapKeeper.tick()
  266. }
  267. func (s *Simulation) uniqueBodiesFromPairs(pairs []CollisionPair) []*object.Body {
  268. bodiesUndergoingNarrowphase := make([]*object.Body, 0) // array of indices of s.bodies
  269. for _, pair := range pairs {
  270. alreadyAddedA := false
  271. alreadyAddedB := false
  272. for _, body := range bodiesUndergoingNarrowphase {
  273. if pair.BodyA == body {
  274. alreadyAddedA = true
  275. if alreadyAddedB {
  276. break
  277. }
  278. }
  279. if pair.BodyB == body {
  280. alreadyAddedB = true
  281. if alreadyAddedA {
  282. break
  283. }
  284. }
  285. }
  286. if !alreadyAddedA {
  287. bodiesUndergoingNarrowphase = append(bodiesUndergoingNarrowphase, pair.BodyA)
  288. }
  289. if !alreadyAddedB {
  290. bodiesUndergoingNarrowphase = append(bodiesUndergoingNarrowphase, pair.BodyB)
  291. }
  292. }
  293. return bodiesUndergoingNarrowphase
  294. }
  295. // TODO read https://gafferongames.com/post/fix_your_timestep/
  296. func (s *Simulation) internalStep(dt float32) {
  297. s.dt = dt
  298. // Apply force fields (only to dynamic bodies
  299. for _, b := range s.bodies {
  300. if b.BodyType() == object.Dynamic {
  301. for _, ff := range s.forceFields {
  302. pos := b.Position()
  303. force := ff.ForceAt(&pos)
  304. b.ApplyForceField(&force)
  305. }
  306. }
  307. }
  308. // Find pairs of bodies that are potentially colliding (broadphase)
  309. pairs := s.broadphase.FindCollisionPairs(s.bodies)
  310. // Remove some pairs before proceeding to narrowphase based on constraints' colConn property
  311. // which specifies if constrained bodies should collide with one another
  312. s.prunePairs(pairs) // TODO review/implement
  313. // Precompute world normals/edges only for convex bodies that will undergo narrowphase
  314. for _, body := range s.uniqueBodiesFromPairs(pairs) {
  315. if ch, ok := body.Shape().(*shape.ConvexHull); ok{
  316. ch.ComputeWorldFaceNormalsAndUniqueEdges(body.Quaternion())
  317. }
  318. }
  319. // Switch collision matrices (to keep track of which collisions started/ended)
  320. s.collisionMatrixTick()
  321. // Resolve collisions and generate contact and friction equations
  322. contactEqs, frictionEqs := s.narrowphase.GenerateEquations(pairs)
  323. // Add all friction equations to solver
  324. for i := 0; i < len(frictionEqs); i++ {
  325. s.solver.AddEquation(frictionEqs[i])
  326. }
  327. // Add all contact equations to solver (and update some things)
  328. for i := 0; i < len(contactEqs); i++ {
  329. s.solver.AddEquation(contactEqs[i])
  330. s.updateSleepAndCollisionMatrix(contactEqs[i])
  331. }
  332. // Add all equations from user-added constraints to the solver
  333. userAddedEquations := 0
  334. for i := 0; i < len(s.constraints); i++ {
  335. s.constraints[i].Update()
  336. eqs := s.constraints[i].Equations()
  337. for j := 0; j < len(eqs); j++ {
  338. userAddedEquations++
  339. s.solver.AddEquation(eqs[j])
  340. }
  341. }
  342. // Emit events TODO implement
  343. s.emitContactEvents()
  344. // Wake up bodies
  345. // TODO why not wake bodies up inside s.updateSleepAndCollisionMatrix when setting the WakeUpAfterNarrowphase flag?
  346. // Maybe there we are only looking at bodies that belong to current contact equations...
  347. // and need to wake up all marked bodies
  348. for i := 0; i < len(s.bodies); i++ {
  349. bi := s.bodies[i]
  350. if bi != nil && bi.WakeUpAfterNarrowphase() {
  351. bi.WakeUp()
  352. bi.SetWakeUpAfterNarrowphase(false)
  353. }
  354. }
  355. // If we have any equations to solve
  356. if len(frictionEqs) + len(contactEqs) + userAddedEquations > 0 {
  357. // Update effective mass for all bodies
  358. for i := 0; i < len(s.bodies); i++ {
  359. s.bodies[i].UpdateEffectiveMassProperties()
  360. }
  361. // Solve the constrained system
  362. solution := s.solver.Solve(dt, len(s.bodies))
  363. // Apply linear and angular velocity deltas to bodies
  364. s.ApplySolution(solution)
  365. // Clear all equations added to the solver
  366. s.solver.ClearEquations()
  367. }
  368. // Apply damping (only to dynamic bodies)
  369. // See http://code.google.com/p/bullet/issues/detail?id=74 for details
  370. for _, body := range s.bodies {
  371. if body != nil && body.BodyType() == object.Dynamic {
  372. body.ApplyDamping(dt)
  373. }
  374. }
  375. // TODO s.Dispatch(World_step_preStepEvent)
  376. // Integrate the forces into velocities and the velocities into position deltas for all bodies
  377. // TODO future: quatNormalize := s.stepnumber % (s.quatNormalizeSkip + 1) == 0
  378. for _, body := range s.bodies {
  379. if body != nil {
  380. body.Integrate(dt, true, s.quatNormalizeFast)
  381. }
  382. }
  383. s.ClearForces()
  384. // TODO s.broadphase.dirty = true ?
  385. // Update world time
  386. s.time += dt
  387. s.stepnumber += 1
  388. // TODO s.Dispatch(World_step_postStepEvent)
  389. // Sleeping update
  390. if s.allowSleep {
  391. for i := 0; i < len(s.bodies); i++ {
  392. s.bodies[i].SleepTick(s.time)
  393. }
  394. }
  395. }
  396. // TODO - REVIEW THIS
  397. func (s *Simulation) prunePairs(pairs []CollisionPair) []CollisionPair {
  398. // TODO There is probably a bug here when the same body can have multiple constraints and appear in multiple pairs
  399. //// Remove constrained pairs with collideConnected == false
  400. //pairIdxsToRemove := []int
  401. //for i := 0; i < len(s.constraints); i++ {
  402. // c := s.constraints[i]
  403. // cBodyA := s.bodies[c.BodyA().Index()]
  404. // cBodyB := s.bodies[c.BodyB().Index()]
  405. // if !c.CollideConnected() {
  406. // for i := range pairs {
  407. // if (pairs[i].BodyA == cBodyA && pairs[i].BodyB == cBodyB) ||
  408. // (pairs[i].BodyA == cBodyB && pairs[i].BodyB == cBodyA) {
  409. // pairIdxsToRemove = append(pairIdxsToRemove, i)
  410. //
  411. // }
  412. // }
  413. // }
  414. //}
  415. //
  416. //// Remove pairs
  417. ////var prunedPairs []CollisionPair
  418. //for i := range pairs {
  419. // for _, idx := range pairIdxsToRemove {
  420. // copy(pairs[i:], pairs[i+1:])
  421. // //pairs[len(pairs)-1] = nil
  422. // pairs = pairs[:len(pairs)-1]
  423. // }
  424. //}
  425. return pairs
  426. }
  427. // generateContacts
  428. func (s *Simulation) updateSleepAndCollisionMatrix(contactEq *equation.Contact) {
  429. // Get current collision indices
  430. bodyA := s.bodies[contactEq.BodyA().Index()]
  431. bodyB := s.bodies[contactEq.BodyB().Index()]
  432. // TODO future: update equations with physical material properties
  433. if bodyA.AllowSleep() && bodyA.BodyType() == object.Dynamic && bodyA.SleepState() == object.Sleeping && bodyB.SleepState() == object.Awake && bodyB.BodyType() != object.Static {
  434. velocityB := bodyB.Velocity()
  435. angularVelocityB := bodyB.AngularVelocity()
  436. speedSquaredB := velocityB.LengthSq() + angularVelocityB.LengthSq()
  437. speedLimitSquaredB := math32.Pow(bodyB.SleepSpeedLimit(), 2)
  438. if speedSquaredB >= speedLimitSquaredB*2 {
  439. bodyA.SetWakeUpAfterNarrowphase(true)
  440. }
  441. }
  442. if bodyB.AllowSleep() && bodyB.BodyType() == object.Dynamic && bodyB.SleepState() == object.Sleeping && bodyA.SleepState() == object.Awake && bodyA.BodyType() != object.Static {
  443. velocityA := bodyA.Velocity()
  444. angularVelocityA := bodyA.AngularVelocity()
  445. speedSquaredA := velocityA.LengthSq() + angularVelocityA.LengthSq()
  446. speedLimitSquaredA := math32.Pow(bodyA.SleepSpeedLimit(), 2)
  447. if speedSquaredA >= speedLimitSquaredA*2 {
  448. bodyB.SetWakeUpAfterNarrowphase(true)
  449. }
  450. }
  451. // Now we know that i and j are in contact. Set collision matrix state
  452. s.collisionMatrix.Set(bodyA.Index(), bodyB.Index(), true)
  453. if s.prevCollisionMatrix.Get(bodyA.Index(), bodyB.Index()) == false {
  454. // First contact!
  455. bodyA.Dispatch(CollisionEv, &CollideEvent{bodyB, contactEq})
  456. bodyB.Dispatch(CollisionEv, &CollideEvent{bodyA, contactEq})
  457. }
  458. // TODO this is only for events
  459. //s.bodyOverlapKeeper.set(bodyA.id, bodyB.id)
  460. //s.shapeOverlapKeeper.set(si.id, sj.id)
  461. }
  462. func (s *Simulation) emitContactEvents() {
  463. //TODO
  464. }