simulation.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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. "time"
  7. "github.com/g3n/engine/physics/equation"
  8. "github.com/g3n/engine/physics/solver"
  9. "github.com/g3n/engine/physics/constraint"
  10. "github.com/g3n/engine/physics/collision"
  11. "github.com/g3n/engine/math32"
  12. "github.com/g3n/engine/physics/object"
  13. "github.com/g3n/engine/physics/material"
  14. )
  15. type ICollidable interface {
  16. Collided() bool
  17. Static() bool
  18. //GetCollisions() []*Collision
  19. }
  20. type CollisionGroup struct {
  21. // TODO future
  22. }
  23. // Simulation represents a physics simulation.
  24. type Simulation struct {
  25. forceFields []ForceField
  26. bodies []*object.Body
  27. nilBodies []int // Array keeps track of which indices of the 'bodies' array are nil
  28. collisionMatrix collision.Matrix // Boolean triangular matrix indicating which pairs of bodies are colliding
  29. prevCollisionMatrix collision.Matrix // CollisionMatrix from the previous step.
  30. allowSleep bool // Makes bodies go to sleep when they've been inactive
  31. contactEqs []*equation.Contact // All the current contacts (instances of ContactEquation) in the world.
  32. frictionEqs []*equation.Friction
  33. quatNormalizeSkip int // How often to normalize quaternions. Set to 0 for every step, 1 for every second etc..
  34. // A larger value increases performance.
  35. // If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
  36. 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.
  37. time float32 // The wall-clock time since simulation start
  38. stepnumber int // Number of timesteps taken since start
  39. default_dt float32 // Default and last timestep sizes
  40. 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.
  41. accumulator float32 // Time accumulator for interpolation. See http://gafferongames.com/game-physics/fix-your-timestep/
  42. broadphase *collision.Broadphase // The broadphase algorithm to use. Default is NaiveBroadphase
  43. narrowphase *Narrowphase // The narrowphase algorithm to use
  44. solver solver.ISolver // The solver algorithm to use. Default is GSSolver
  45. constraints []constraint.IConstraint // All constraints
  46. materials []*material.Material // All added materials
  47. cMaterials []*material.ContactMaterial
  48. //contactMaterialTable map[intPair]*ContactMaterial // Used to look up a ContactMaterial given two instances of Material.
  49. //defaultMaterial *Material
  50. defaultContactMaterial *material.ContactMaterial
  51. doProfiling bool
  52. }
  53. // NewSimulation creates and returns a pointer to a new physics simulation.
  54. func NewSimulation() *Simulation {
  55. s := new(Simulation)
  56. s.time = 0
  57. s.dt = -1
  58. s.default_dt = 1/60
  59. // Set up broadphase, narrowphase, and solver
  60. s.broadphase = collision.NewBroadphase()
  61. s.narrowphase = NewNarrowphase(s)
  62. s.solver = solver.NewGaussSeidel()
  63. //s.contactMaterialTable = make(map[intPair]*ContactMaterial)
  64. //s.defaultMaterial = NewMaterial
  65. s.defaultContactMaterial = material.NewContactMaterial()
  66. return s
  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) {
  87. // Do nothing if body already present
  88. for _, existingBody := range s.bodies {
  89. if existingBody == body {
  90. return // Do nothing
  91. }
  92. }
  93. var idx int
  94. nilLen := len(s.nilBodies)
  95. if nilLen > 0 {
  96. idx = s.nilBodies[nilLen]
  97. s.nilBodies = s.nilBodies[0:nilLen-1]
  98. } else {
  99. s.bodies = append(s.bodies, body)
  100. }
  101. body.SetIndex(idx)
  102. // TODO dispatch add-body event
  103. //s.Dispatch(AddBodyEvent, BodyEvent{body})
  104. }
  105. // RemoveBody removes the specified body from the simulation.
  106. // Returns true if found, false otherwise.
  107. func (s *Simulation) RemoveBody(body *object.Body) bool {
  108. for idx, current := range s.bodies {
  109. if current == body {
  110. s.bodies[idx] = nil
  111. // TODO dispatch remove-body event
  112. //s.Dispatch(AddBodyEvent, BodyEvent{body})
  113. return true
  114. }
  115. }
  116. return false
  117. }
  118. // Clean removes nil bodies from the bodies array, recalculates the body indices and updates the collision matrix.
  119. //func (s *Simulation) Clean() {
  120. //
  121. // // TODO Remove nil bodies from array
  122. // //copy(s.bodies[pos:], s.bodies[pos+1:])
  123. // //s.bodies[len(s.bodies)-1] = nil
  124. // //s.bodies = s.bodies[:len(s.bodies)-1]
  125. //
  126. // // Recompute body indices (each body has a .index int property)
  127. // for i:=0; i<len(s.bodies); i++ {
  128. // s.bodies[i].SetIndex(i)
  129. // }
  130. //
  131. // // TODO Update collision matrix
  132. //
  133. //}
  134. // Bodies returns the slice of bodies under simulation.
  135. // The slice may contain nil values!
  136. func (s *Simulation) Bodies() []*object.Body{
  137. return s.bodies
  138. }
  139. // Step steps the simulation.
  140. func (s *Simulation) Step(frameDelta time.Duration) {
  141. // Check for collisions
  142. //collisions := s.CheckCollisions()
  143. //if len(collisions) > 0 {
  144. // // Backtrack to 0 penetration
  145. // s.Backtrack()
  146. //}
  147. // Apply static forces/inertia/impulses (only to objects that did not collide)
  148. //s.applyForceFields()
  149. // s.applyDrag(frameDelta) // TODO
  150. // Apply impact forces/inertia/impulses to objects that collided
  151. //s.applyImpactForces(frameDelta)
  152. // Update object positions based on calculated final speeds
  153. //s.updatePositions(frameDelta)
  154. }
  155. // ClearForces sets all body forces in the world to zero.
  156. func (s *Simulation) ClearForces() {
  157. for i:=0; i < len(s.bodies); i++ {
  158. s.bodies[i].ClearForces()
  159. }
  160. }
  161. // Add a constraint to the simulation.
  162. func (s *Simulation) AddConstraint(c constraint.IConstraint) {
  163. s.constraints = append(s.constraints, c)
  164. }
  165. func (s *Simulation) RemoveConstraint(c constraint.IConstraint) {
  166. // TODO
  167. }
  168. func (s *Simulation) AddMaterial(mat *material.Material) {
  169. s.materials = append(s.materials, mat)
  170. }
  171. func (s *Simulation) RemoveMaterial(mat *material.Material) {
  172. // TODO
  173. }
  174. // Adds a contact material to the simulation
  175. func (s *Simulation) AddContactMaterial(cmat *material.ContactMaterial) {
  176. s.cMaterials = append(s.cMaterials, cmat)
  177. // TODO add contactMaterial materials to contactMaterialTable
  178. // s.contactMaterialTable.set(cmat.materials[0].id, cmat.materials[1].id, cmat)
  179. }
  180. // GetContactMaterial returns the contact material between the specified bodies.
  181. func (s *Simulation) GetContactMaterial(bodyA, bodyB *object.Body) *material.ContactMaterial {
  182. var cm *material.ContactMaterial
  183. // TODO
  184. //if bodyA.material != nil && bodyB.material != nil {
  185. // cm = s.contactMaterialTable.get(bodyA.material.id, bodyB.material.id)
  186. // if cm == nil {
  187. // cm = s.defaultContactMaterial
  188. // }
  189. //} else {
  190. cm = s.defaultContactMaterial
  191. //}
  192. return cm
  193. }
  194. // Events =====================
  195. type CollideEvent struct {
  196. body *object.Body
  197. contactEq *equation.Contact
  198. }
  199. // TODO AddBodyEvent, RemoveBodyEvent
  200. type ContactEvent struct {
  201. bodyA *object.Body
  202. bodyB *object.Body
  203. }
  204. const (
  205. BeginContactEvent = "physics.BeginContactEvent"
  206. EndContactEvent = "physics.EndContactEvent"
  207. CollisionEv = "physics.Collision"
  208. )
  209. // ===========================
  210. // Note - this method alters the solution arrays
  211. func (s *Simulation) ApplySolution(sol *solver.Solution) {
  212. // Add results to velocity and angular velocity of bodies
  213. for i := 0; i < len(s.bodies); i++ {
  214. s.bodies[i].ApplyVelocityDeltas(&sol.VelocityDeltas[i], &sol.AngularVelocityDeltas[i])
  215. }
  216. }
  217. // Store old collision state info
  218. func (s *Simulation) collisionMatrixTick() {
  219. s.prevCollisionMatrix = s.collisionMatrix
  220. s.collisionMatrix = collision.NewMatrix()
  221. // TODO
  222. //s.bodyOverlapKeeper.tick()
  223. //s.shapeOverlapKeeper.tick()
  224. }
  225. // TODO read https://gafferongames.com/post/fix_your_timestep/
  226. func (s *Simulation) internalStep(dt float32) {
  227. // Apply force fields and compute world normals/edges
  228. for _, b := range s.bodies {
  229. // Only apply to dynamic bodies
  230. if b.BodyType() == object.Dynamic {
  231. for _, ff := range s.forceFields {
  232. pos := b.Position()
  233. force := ff.ForceAt(&pos)
  234. b.ApplyForceField(&force)
  235. }
  236. }
  237. // Compute for the new rotation
  238. // TODO optimization: only need to compute the below for objects that will go through narrowphase
  239. b.ComputeWorldFaceNormalsAndUniqueEdges()
  240. }
  241. // TODO update subsystems ?
  242. // Find pairs of bodies that are potentially colliding
  243. pairs := s.broadphase.FindCollisionPairs(s.bodies)
  244. // Remove some pairs before proceeding to narrophase based on constraints' colConn property
  245. // which specified if constrained bodies should collide with one another
  246. s.prunePairs(pairs) // TODO review
  247. //
  248. s.collisionMatrixTick()
  249. // Generate contacts
  250. s.generateContacts(pairs)
  251. s.emitContactEvents()
  252. // Wake up bodies
  253. // TODO why not wake bodies up inside s.generateContacs when setting the WakeUpAfterNarrowphase flag?
  254. // Maybe there we are only looking at bodies that belong to current contact equations...
  255. // and need to wake up all marked bodies
  256. for i := 0; i < len(s.bodies); i++ {
  257. bi := s.bodies[i]
  258. if bi != nil && bi.WakeUpAfterNarrowphase() {
  259. bi.WakeUp()
  260. bi.SetWakeUpAfterNarrowphase(false)
  261. }
  262. }
  263. // Add user-added constraints
  264. userAddedEquations := 0
  265. for i := 0; i < len(s.constraints); i++ {
  266. c := s.constraints[i]
  267. c.Update()
  268. eqs := c.Equations()
  269. for j := 0; j < len(eqs); j++ {
  270. userAddedEquations++
  271. s.solver.AddEquation(eqs[j])
  272. }
  273. }
  274. // Update solve mass for all bodies
  275. // NOTE: This was originally inside the beginning of solver.Solve()
  276. if len(s.frictionEqs) + len(s.contactEqs) + userAddedEquations > 0 {
  277. for i := 0; i < len(s.bodies); i++ {
  278. s.bodies[i].UpdateEffectiveMassProperties()
  279. }
  280. }
  281. // Solve the constrained system
  282. solution := s.solver.Solve(dt, len(s.bodies))
  283. s.ApplySolution(solution) // Applies velocity deltas
  284. s.solver.ClearEquations()
  285. // Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details
  286. for i := 0; i < len(s.bodies); i++ {
  287. bi := s.bodies[i]
  288. if bi != nil && bi.BodyType() == object.Dynamic { // Only apply damping to dynamic bodies
  289. bi.ApplyDamping(dt)
  290. }
  291. }
  292. // TODO s.Dispatch(World_step_preStepEvent)
  293. // Integrate the forces into velocities into position deltas
  294. quatNormalize := s.stepnumber % (s.quatNormalizeSkip + 1) == 0
  295. for i := 0; i < len(s.bodies); i++ {
  296. s.bodies[i].Integrate(dt, quatNormalize, s.quatNormalizeFast)
  297. }
  298. s.ClearForces()
  299. // TODO s.broadphase.dirty = true ?
  300. // Update world time
  301. s.time += dt
  302. s.stepnumber += 1
  303. // TODO s.Dispatch(World_step_postStepEvent)
  304. // Sleeping update
  305. if s.allowSleep {
  306. for i := 0; i < len(s.bodies); i++ {
  307. s.bodies[i].SleepTick(s.time)
  308. }
  309. }
  310. }
  311. // TODO - REVIEW THIS
  312. func (s *Simulation) prunePairs(pairs []collision.Pair) []collision.Pair {
  313. // TODO There is probably a bug here when the same body can have multiple constraints and appear in multiple pairs
  314. //// Remove constrained pairs with collideConnected == false
  315. //pairIdxsToRemove := []int
  316. //for i := 0; i < len(s.constraints); i++ {
  317. // c := s.constraints[i]
  318. // cBodyA := s.bodies[c.BodyA().Index()]
  319. // cBodyB := s.bodies[c.BodyB().Index()]
  320. // if !c.CollideConnected() {
  321. // for i := range pairs {
  322. // if (pairs[i].BodyA == cBodyA && pairs[i].BodyB == cBodyB) ||
  323. // (pairs[i].BodyA == cBodyB && pairs[i].BodyB == cBodyA) {
  324. // pairIdxsToRemove = append(pairIdxsToRemove, i)
  325. //
  326. // }
  327. // }
  328. // }
  329. //}
  330. //
  331. //// Remove pairs
  332. ////var prunedPairs []Pair
  333. //for i := range pairs {
  334. // for _, idx := range pairIdxsToRemove {
  335. // copy(pairs[i:], pairs[i+1:])
  336. // //pairs[len(pairs)-1] = nil
  337. // pairs = pairs[:len(pairs)-1]
  338. // }
  339. //}
  340. return pairs
  341. }
  342. // generateContacts
  343. func (s *Simulation) generateContacts(pairs []collision.Pair) {
  344. // Find all contacts and generate contact and friction equations (narrowphase)
  345. s.contactEqs, s.frictionEqs = s.narrowphase.GetContacts(pairs)
  346. // Add all friction equations to solver
  347. for i := 0; i < len(s.frictionEqs); i++ {
  348. s.solver.AddEquation(s.frictionEqs[i])
  349. }
  350. for k := 0; k < len(s.contactEqs); k++ {
  351. // Current contact
  352. contactEq := s.contactEqs[k]
  353. // Get current collision indices
  354. bodyA := s.bodies[contactEq.BodyA().Index()]
  355. bodyB := s.bodies[contactEq.BodyB().Index()]
  356. // TODO future: update equations with physical material properties
  357. s.solver.AddEquation(contactEq)
  358. if bodyA.AllowSleep() && bodyA.BodyType() == object.Dynamic && bodyA.SleepState() == object.Sleeping && bodyB.SleepState() == object.Awake && bodyB.BodyType() != object.Static {
  359. velocityB := bodyB.Velocity()
  360. angularVelocityB := bodyB.AngularVelocity()
  361. speedSquaredB := velocityB.LengthSq() + angularVelocityB.LengthSq()
  362. speedLimitSquaredB := math32.Pow(bodyB.SleepSpeedLimit(), 2)
  363. if speedSquaredB >= speedLimitSquaredB*2 {
  364. bodyA.SetWakeUpAfterNarrowphase(true)
  365. }
  366. }
  367. if bodyB.AllowSleep() && bodyB.BodyType() == object.Dynamic && bodyB.SleepState() == object.Sleeping && bodyA.SleepState() == object.Awake && bodyA.BodyType() != object.Static {
  368. velocityA := bodyA.Velocity()
  369. angularVelocityA := bodyA.AngularVelocity()
  370. speedSquaredA := velocityA.LengthSq() + angularVelocityA.LengthSq()
  371. speedLimitSquaredA := math32.Pow(bodyA.SleepSpeedLimit(), 2)
  372. if speedSquaredA >= speedLimitSquaredA*2 {
  373. bodyB.SetWakeUpAfterNarrowphase(true)
  374. }
  375. }
  376. // Now we know that i and j are in contact. Set collision matrix state
  377. s.collisionMatrix.Set(bodyA.Index(), bodyB.Index(), true)
  378. if s.prevCollisionMatrix.Get(bodyA.Index(), bodyB.Index()) == false {
  379. // First contact!
  380. bodyA.Dispatch(CollisionEv, &CollideEvent{bodyB, contactEq})
  381. bodyB.Dispatch(CollisionEv, &CollideEvent{bodyA, contactEq})
  382. }
  383. // TODO this is only for events
  384. //s.bodyOverlapKeeper.set(bodyA.id, bodyB.id)
  385. //s.shapeOverlapKeeper.set(si.id, sj.id)
  386. }
  387. }
  388. func (s *Simulation) emitContactEvents() {
  389. //TODO
  390. }