narrowphase.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  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/collision/shape"
  7. "github.com/g3n/engine/experimental/physics/equation"
  8. "github.com/g3n/engine/experimental/physics/object"
  9. "github.com/g3n/engine/math32"
  10. )
  11. // Narrowphase
  12. type Narrowphase struct {
  13. simulation *Simulation
  14. currentContactMaterial *ContactMaterial
  15. enableFrictionReduction bool // If true friction is computed as average
  16. debugging bool
  17. }
  18. // NewNarrowphase creates and returns a pointer to a new Narrowphase.
  19. func NewNarrowphase(simulation *Simulation) *Narrowphase {
  20. n := new(Narrowphase)
  21. n.simulation = simulation
  22. //n.enableFrictionReduction = true
  23. // FOR DEBUGGING
  24. //n.debugging = true
  25. return n
  26. }
  27. // createFrictionEquationsFromContact
  28. func (n *Narrowphase) createFrictionEquationsFromContact(contactEquation *equation.Contact) (*equation.Friction, *equation.Friction) {
  29. bodyA := n.simulation.bodies[contactEquation.BodyA().Index()]
  30. bodyB := n.simulation.bodies[contactEquation.BodyB().Index()]
  31. // TODO materials
  32. // friction = n.currentContactMaterial.friction
  33. // if materials are defined then override: friction = matA.friction * matB.friction
  34. //var mug = friction * world.gravity.length()
  35. //var reducedMass = bodyA.InvMass() + bodyB.InvMass()
  36. //if reducedMass > 0 {
  37. // reducedMass = 1/reducedMass
  38. //}
  39. slipForce := float32(0.5) //mug*reducedMass
  40. fricEq1 := equation.NewFriction(bodyA, bodyB, slipForce)
  41. fricEq2 := equation.NewFriction(bodyA, bodyB, slipForce)
  42. fricEq1.SetSpookParams(1e7, 3, n.simulation.dt)
  43. fricEq2.SetSpookParams(1e7, 3, n.simulation.dt)
  44. // Copy over the relative vectors
  45. cRA := contactEquation.RA()
  46. cRB := contactEquation.RB()
  47. fricEq1.SetRA(&cRA)
  48. fricEq1.SetRB(&cRB)
  49. fricEq2.SetRA(&cRA)
  50. fricEq2.SetRB(&cRB)
  51. // Construct and set tangents
  52. cNormal := contactEquation.Normal()
  53. t1, t2 := cNormal.RandomTangents()
  54. fricEq1.SetTangent(t1)
  55. fricEq2.SetTangent(t2)
  56. // Copy enabled state
  57. cEnabled := contactEquation.Enabled()
  58. fricEq1.SetEnabled(cEnabled)
  59. fricEq2.SetEnabled(cEnabled)
  60. return fricEq1, fricEq2
  61. }
  62. // TODO test this
  63. func (n *Narrowphase) createFrictionFromAverage(contactEqs []*equation.Contact) (*equation.Friction, *equation.Friction) {
  64. // The last contactEquation
  65. lastContactEq := contactEqs[len(contactEqs)-1]
  66. // Create a friction equation based on the last contact (we will modify it to take into account all contacts)
  67. fEq1, fEq2 := n.createFrictionEquationsFromContact(lastContactEq)
  68. if (fEq1 == nil && fEq2 == nil) || len(contactEqs) == 1 {
  69. return fEq1, fEq2
  70. }
  71. averageNormal := math32.NewVec3()
  72. averageContactPointA := math32.NewVec3()
  73. averageContactPointB := math32.NewVec3()
  74. bodyA := lastContactEq.BodyA()
  75. //bodyB := lastContactEq.BodyB()
  76. normal := lastContactEq.Normal()
  77. rA := lastContactEq.RA()
  78. rB := lastContactEq.RB()
  79. for _, cEq := range contactEqs {
  80. if cEq.BodyA() != bodyA {
  81. averageNormal.Add(&normal)
  82. averageContactPointA.Add(&rA)
  83. averageContactPointB.Add(&rB)
  84. } else {
  85. averageNormal.Sub(&normal)
  86. averageContactPointA.Add(&rB)
  87. averageContactPointB.Add(&rA)
  88. }
  89. }
  90. invNumContacts := float32(1) / float32(len(contactEqs))
  91. averageContactPointA.MultiplyScalar(invNumContacts)
  92. averageContactPointB.MultiplyScalar(invNumContacts)
  93. // Should be the same for both friction equations
  94. fEq1.SetRA(averageContactPointA)
  95. fEq1.SetRB(averageContactPointB)
  96. fEq2.SetRA(averageContactPointA)
  97. fEq2.SetRB(averageContactPointB)
  98. // Set tangents
  99. averageNormal.Normalize()
  100. t1, t2 := averageNormal.RandomTangents()
  101. fEq1.SetTangent(t1)
  102. fEq2.SetTangent(t2)
  103. return fEq1, fEq2
  104. }
  105. // GenerateEquations is the Narrowphase entry point.
  106. func (n *Narrowphase) GenerateEquations(pairs []CollisionPair) ([]*equation.Contact, []*equation.Friction) {
  107. // TODO don't "make" every time, simply re-slice
  108. allContactEqs := make([]*equation.Contact, 0)
  109. allFrictionEqs := make([]*equation.Friction, 0)
  110. for k := 0; k < len(pairs); k++ {
  111. // Get current collision bodies
  112. bodyA := pairs[k].BodyA
  113. bodyB := pairs[k].BodyB
  114. bodyTypeA := bodyA.BodyType()
  115. bodyTypeB := bodyB.BodyType()
  116. // For now these collisions are ignored
  117. // TODO future: just want to check for collision (in order to dispatch events) and not create equations
  118. justTest := (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Static) ||
  119. (bodyTypeA == object.Static) && (bodyTypeB == object.Kinematic) ||
  120. (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Kinematic)
  121. // Get contacts
  122. if !justTest {
  123. //contactEqs, frictionEqs := n.Resolve(bodyA, bodyB)
  124. contactEqs, frictionEqs := n.ResolveCollision(bodyA, bodyB)
  125. allContactEqs = append(allContactEqs, contactEqs...)
  126. allFrictionEqs = append(allFrictionEqs, frictionEqs...)
  127. }
  128. }
  129. return allContactEqs, allFrictionEqs
  130. }
  131. // ResolveCollision figures out which implementation of collision detection and contact resolution to use depending on the shapes involved.
  132. func (n *Narrowphase) ResolveCollision(bodyA, bodyB *object.Body) ([]*equation.Contact, []*equation.Friction) {
  133. shapeA := bodyA.Shape()
  134. shapeB := bodyB.Shape()
  135. posA := bodyA.Position()
  136. posB := bodyB.Position()
  137. quatA := bodyA.Quaternion()
  138. quatB := bodyB.Quaternion()
  139. switch sA := shapeA.(type) {
  140. case *shape.Sphere:
  141. switch sB := shapeB.(type) {
  142. case *shape.Sphere:
  143. return n.SphereSphere(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  144. case *shape.Plane:
  145. return n.SpherePlane(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  146. case *shape.ConvexHull:
  147. return n.SphereConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  148. }
  149. case *shape.Plane:
  150. switch sB := shapeB.(type) {
  151. case *shape.Sphere:
  152. return n.SpherePlane(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
  153. //case *shape.Plane: // plane-plane collision never happens...
  154. // return n.PlanePlane(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  155. case *shape.ConvexHull:
  156. return n.PlaneConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  157. }
  158. case *shape.ConvexHull:
  159. switch sB := shapeB.(type) {
  160. case *shape.Sphere:
  161. return n.SphereConvex(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
  162. case *shape.Plane:
  163. return n.PlaneConvex(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
  164. case *shape.ConvexHull:
  165. return n.ConvexConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
  166. }
  167. }
  168. return []*equation.Contact{}, []*equation.Friction{}
  169. }
  170. // SphereSphere resolves the collision between two spheres analytically.
  171. func (n *Narrowphase) SphereSphere(bodyA, bodyB *object.Body, sphereA, sphereB *shape.Sphere, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
  172. contactEqs := make([]*equation.Contact, 0, 1)
  173. frictionEqs := make([]*equation.Friction, 0, 2)
  174. radiusA := sphereA.Radius()
  175. radiusB := sphereB.Radius()
  176. if posA.DistanceToSquared(posB) > math32.Pow(radiusA+radiusB, 2) {
  177. // No collision
  178. return contactEqs, frictionEqs
  179. }
  180. // Find penetration axis
  181. penAxis := posB.Clone().Sub(posA).Normalize()
  182. // Create contact equation
  183. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  184. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  185. //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
  186. contactEq.SetNormal(penAxis.Clone())
  187. contactEq.SetRA(penAxis.Clone().MultiplyScalar(radiusB))
  188. contactEq.SetRB(penAxis.Clone().MultiplyScalar(-radiusB))
  189. contactEqs = append(contactEqs, contactEq)
  190. // Create friction equations
  191. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  192. frictionEqs = append(frictionEqs, fEq1, fEq2)
  193. return contactEqs, frictionEqs
  194. }
  195. // SpherePlane resolves the collision between a sphere and a plane analytically.
  196. func (n *Narrowphase) SpherePlane(bodyA, bodyB *object.Body, sphereA *shape.Sphere, planeB *shape.Plane, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
  197. contactEqs := make([]*equation.Contact, 0)
  198. frictionEqs := make([]*equation.Friction, 0)
  199. sphereRadius := sphereA.Radius()
  200. localNormal := planeB.Normal()
  201. normal := localNormal.Clone().ApplyQuaternion(quatB).Negate().Normalize()
  202. // Project down sphere on plane
  203. point_on_plane_to_sphere := math32.NewVec3().SubVectors(posA, posB)
  204. plane_to_sphere_ortho := normal.Clone().MultiplyScalar(normal.Dot(point_on_plane_to_sphere))
  205. if -point_on_plane_to_sphere.Dot(normal) <= sphereRadius {
  206. //if justTest {
  207. // return true
  208. //}
  209. // We will have one contact in this case
  210. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  211. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  212. contactEq.SetNormal(normal) // Normalize() might not be needed
  213. contactEq.SetRA(normal.Clone().MultiplyScalar(sphereRadius)) // Vector from sphere center to contact point
  214. contactEq.SetRB(math32.NewVec3().SubVectors(point_on_plane_to_sphere, plane_to_sphere_ortho)) // The sphere position projected to plane
  215. contactEqs = append(contactEqs, contactEq)
  216. // Create friction equations
  217. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  218. frictionEqs = append(frictionEqs, fEq1, fEq2)
  219. }
  220. return contactEqs, frictionEqs
  221. }
  222. // TODO The second half of this method is untested!!!
  223. func (n *Narrowphase) SphereConvex(bodyA, bodyB *object.Body, sphereA *shape.Sphere, convexB *shape.ConvexHull, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
  224. contactEqs := make([]*equation.Contact, 0)
  225. frictionEqs := make([]*equation.Friction, 0)
  226. // TODO
  227. //v3pool := this.v3pool
  228. //convex_to_sphere := math32.NewVec3().SubVectors(posA, posB)
  229. //normals := sj.faceNormals
  230. //faces := sj.faces
  231. //verts := sj.vertices
  232. //R := si.radius
  233. //penetrating_sides := []
  234. // COMMENTED OUT
  235. // if(convex_to_sphere.norm2() > si.boundingSphereRadius + sj.boundingSphereRadius){
  236. // return;
  237. // }
  238. sphereRadius := sphereA.Radius()
  239. // First check if any vertex of the convex hull is inside the sphere
  240. done := false
  241. convexB.Geometry.ReadVertices(func(vertex math32.Vector3) bool {
  242. worldVertex := vertex.ApplyQuaternion(quatA).Add(posB)
  243. sphereToCorner := math32.NewVec3().SubVectors(worldVertex, posA)
  244. if sphereToCorner.LengthSq() < sphereRadius*sphereRadius {
  245. // Colliding! worldVertex is inside sphere.
  246. // Create contact equation
  247. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  248. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  249. //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
  250. normalizedSphereToCorner := sphereToCorner.Clone().Normalize()
  251. contactEq.SetNormal(normalizedSphereToCorner)
  252. contactEq.SetRA(normalizedSphereToCorner.Clone().MultiplyScalar(sphereRadius))
  253. contactEq.SetRB(worldVertex.Clone().Sub(posB))
  254. contactEqs = append(contactEqs, contactEq)
  255. // Create friction equations
  256. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  257. frictionEqs = append(frictionEqs, fEq1, fEq2)
  258. // Set done flag
  259. done = true
  260. // Break out of loop
  261. return true
  262. }
  263. return false
  264. })
  265. if done {
  266. return contactEqs, frictionEqs
  267. }
  268. //Check side (plane) intersections TODO NOTE THIS IS UNTESTED
  269. convexFaces := convexB.Faces()
  270. convexWorldFaceNormals := convexB.WorldFaceNormals()
  271. for i := 0; i < len(convexFaces); i++ {
  272. worldNormal := convexWorldFaceNormals[i]
  273. face := convexFaces[i]
  274. // Get a world vertex from the face
  275. var worldPoint = face[0].Clone().ApplyQuaternion(quatB).Add(posB)
  276. // Get a point on the sphere, closest to the face normal
  277. var worldSpherePointClosestToPlane = worldNormal.Clone().MultiplyScalar(-sphereRadius).Add(posA)
  278. // Vector from a face point to the closest point on the sphere
  279. var penetrationVec = math32.NewVec3().SubVectors(worldSpherePointClosestToPlane, worldPoint)
  280. // The penetration. Negative value means overlap.
  281. var penetration = penetrationVec.Dot(&worldNormal)
  282. var worldPointToSphere = math32.NewVec3().SubVectors(posA, worldPoint)
  283. if penetration < 0 && worldPointToSphere.Dot(&worldNormal) > 0 {
  284. // Intersects plane. Now check if the sphere is inside the face polygon
  285. worldFace := convexB.WorldFace(face, posB, quatB)
  286. if n.pointBehindFace(worldFace, &worldNormal, posA) { // Is the sphere center behind the face (inside the convex polygon?
  287. // TODO NEVER GETTING INSIDE THIS IF STATEMENT!
  288. ShowWorldFace(n.simulation.Scene(), worldFace[:], &math32.Color{0, 0, 2})
  289. // if justTest {
  290. // return true
  291. //}
  292. // Create contact equation
  293. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  294. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  295. //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
  296. contactEq.SetNormal(worldNormal.Clone().Negate())
  297. contactEq.SetRA(worldNormal.Clone().MultiplyScalar(-sphereRadius))
  298. penetrationVec2 := worldNormal.Clone().MultiplyScalar(-penetration)
  299. penetrationSpherePoint := worldNormal.Clone().MultiplyScalar(-sphereRadius)
  300. contactEq.SetRB(posA.Clone().Sub(posB).Add(penetrationSpherePoint).Add(penetrationVec2))
  301. contactEqs = append(contactEqs, contactEq)
  302. // Create friction equations
  303. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  304. frictionEqs = append(frictionEqs, fEq1, fEq2)
  305. // Exit method (we only expect *one* face contact)
  306. return contactEqs, frictionEqs
  307. } else {
  308. // Edge?
  309. for j := 0; j < len(worldFace); j++ {
  310. // Get two world transformed vertices
  311. v1 := worldFace[(j+1)%3].Clone() //.ApplyQuaternion(quatB).Add(posB)
  312. v2 := worldFace[(j+2)%3].Clone() //.ApplyQuaternion(quatB).Add(posB)
  313. // Construct edge vector
  314. edge := math32.NewVec3().SubVectors(v2, v1)
  315. // Construct the same vector, but normalized
  316. edgeUnit := edge.Clone().Normalize()
  317. // p is xi projected onto the edge
  318. v1ToPosA := math32.NewVec3().SubVectors(posA, v1)
  319. dot := v1ToPosA.Dot(edgeUnit)
  320. p := edgeUnit.Clone().MultiplyScalar(dot).Add(v1)
  321. // Compute a vector from p to the center of the sphere
  322. var posAtoP = math32.NewVec3().SubVectors(p, posA)
  323. // Collision if the edge-sphere distance is less than the radius AND if p is in between v1 and v2
  324. edgeL2 := edge.LengthSq()
  325. patp2 := posAtoP.LengthSq()
  326. if (dot > 0) && (dot*dot < edgeL2) && (patp2 < sphereRadius*sphereRadius) { // Collision if the edge-sphere distance is less than the radius
  327. // Edge contact!
  328. //if justTest {
  329. // return true
  330. //}
  331. // Create contact equation
  332. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  333. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  334. //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
  335. normal := p.Clone().Sub(posA).Normalize()
  336. contactEq.SetNormal(normal)
  337. contactEq.SetRA(normal.Clone().MultiplyScalar(sphereRadius))
  338. contactEq.SetRB(p.Clone().Sub(posB))
  339. contactEqs = append(contactEqs, contactEq)
  340. // Create friction equations
  341. //fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  342. //frictionEqs = append(frictionEqs, fEq1, fEq2)
  343. // Exit method (we only expect *one* edge contact)
  344. return contactEqs, frictionEqs
  345. }
  346. }
  347. }
  348. }
  349. }
  350. return contactEqs, frictionEqs
  351. }
  352. func (n *Narrowphase) pointBehindFace(worldFace [3]math32.Vector3, faceNormal, point *math32.Vector3) bool {
  353. pointInFace := worldFace[0].Clone()
  354. planeDelta := -pointInFace.Dot(faceNormal)
  355. depth := faceNormal.Dot(point) + planeDelta
  356. if depth > 0 {
  357. return false
  358. } else {
  359. return true
  360. }
  361. }
  362. // Checks if a given point is inside the polygon. I believe this is a generalization of checking whether a point is behind a face/plane when the face has more than 3 vertices.
  363. //func (n *Narrowphase) pointInPolygon(verts []math32.Vector3, normal, p *math32.Vector3) bool {
  364. //
  365. // firstTime := true
  366. // positiveResult := true // first value of positive result doesn't matter
  367. // N := len(verts)
  368. // for i := 0; i < N; i++ {
  369. // v := verts[i].Clone()
  370. // // Get edge to the next vertex
  371. // edge := math32.NewVec3().SubVectors(verts[(i+1)%N].Clone(), v)
  372. // // Get cross product between polygon normal and the edge
  373. // edgeCrossNormal := math32.NewVec3().CrossVectors(edge, normal)
  374. // // Get vector between point and current vertex
  375. // vertexToP := math32.NewVec3().SubVectors(p, v)
  376. // // This dot product determines which side of the edge the point is
  377. // r := edgeCrossNormal.Dot(vertexToP)
  378. // // If all such dot products have same sign, we are inside the polygon.
  379. // if firstTime || (r > 0 && positiveResult == true) || (r <= 0 && positiveResult == false) {
  380. // if firstTime {
  381. // positiveResult = r > 0
  382. // firstTime = false
  383. // }
  384. // continue
  385. // } else {
  386. // return false // Encountered some other sign. Exit.
  387. // }
  388. // }
  389. // // If we got here, all dot products were of the same sign.
  390. // return true
  391. //}
  392. // ConvexConvex implements collision detection and contact resolution between two convex hulls.
  393. func (n *Narrowphase) ConvexConvex(bodyA, bodyB *object.Body, convexA, convexB *shape.ConvexHull, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
  394. contactEqs := make([]*equation.Contact, 0)
  395. frictionEqs := make([]*equation.Friction, 0)
  396. // Check if colliding and find penetration axis
  397. penetrating, penAxis := convexA.FindPenetrationAxis(convexB, posA, posB, quatA, quatB)
  398. if !penetrating {
  399. return contactEqs, frictionEqs
  400. }
  401. if n.debugging {
  402. ShowPenAxis(n.simulation.Scene(), &penAxis) //, -1000, 1000)
  403. log.Error("Colliding (%v|%v) penAxis: %v", bodyA.Name(), bodyB.Name(), penAxis)
  404. }
  405. // Colliding! Find contacts.
  406. contacts := convexA.ClipAgainstHull(convexB, posA, posB, quatA, quatB, &penAxis, -100, 100)
  407. // For each contact found create a contact equation and the two associated friction equations
  408. for j := 0; j < len(contacts); j++ {
  409. contact := contacts[j]
  410. if n.debugging {
  411. ShowContact(n.simulation.Scene(), &contact) // TODO DEBUGGING
  412. }
  413. // Note - contact Normals point from B to A (contacts live in B)
  414. // Create contact equation and append it
  415. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  416. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  417. contactEq.SetEnabled(bodyA.CollisionResponse() && bodyB.CollisionResponse())
  418. contactEq.SetNormal(penAxis.Clone())
  419. contactEq.SetRA(contact.Normal.Clone().MultiplyScalar(-contact.Depth).Add(&contact.Point).Sub(posA))
  420. contactEq.SetRB(contact.Point.Clone().Sub(posB))
  421. contactEqs = append(contactEqs, contactEq)
  422. // If enableFrictionReduction is true then skip creating friction equations for individual contacts
  423. // We will create average friction equations later based on all contacts
  424. if !n.enableFrictionReduction {
  425. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  426. frictionEqs = append(frictionEqs, fEq1, fEq2)
  427. }
  428. }
  429. // If enableFrictionReduction is true then we skipped creating friction equations for individual contacts
  430. // We now want to create average friction equations based on all contact points.
  431. // If we only have one contact however, then friction is small and we don't need to create the friction equations at all.
  432. // TODO
  433. if n.enableFrictionReduction && len(contactEqs) > 1 {
  434. //fEq1, fEq2 := n.createFrictionFromAverage(contactEqs)
  435. //frictionEqs = append(frictionEqs, fEq1, fEq2)
  436. }
  437. return contactEqs, frictionEqs
  438. }
  439. //// TODO ?
  440. //func (n *Narrowphase) GetAveragePointLocal(target) {
  441. //
  442. // target = target || new Vec3()
  443. // n := this.vertices.length
  444. // verts := this.vertices
  445. // for i := 0; i < n; i++ {
  446. // target.vadd(verts[i],target)
  447. // }
  448. // target.mult(1/n,target)
  449. // return target
  450. //}
  451. // Checks whether p is inside the polyhedra. Must be in local coords.
  452. // The point lies outside of the convex hull of the other points if and only if
  453. // the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
  454. // p is A point given in local coordinates
  455. //func (n *Narrowphase) PointIsInside(p) {
  456. //
  457. // verts := this.vertices
  458. // faces := this.faces
  459. // normals := this.faceNormals
  460. // positiveResult := null
  461. // N := this.faces.length
  462. // pointInside := ConvexPolyhedron_pointIsInside
  463. // this.getAveragePointLocal(pointInside)
  464. // for i := 0; i < N; i++ {
  465. // numVertices := this.faces[i].length
  466. // n := normals[i]
  467. // v := verts[faces[i][0]] // We only need one point in the face
  468. //
  469. // // This dot product determines which side of the edge the point is
  470. // vToP := ConvexPolyhedron_vToP
  471. // p.vsub(v,vToP)
  472. // r1 := n.dot(vToP)
  473. //
  474. // vToPointInside := ConvexPolyhedron_vToPointInside
  475. // pointInside.vsub(v,vToPointInside)
  476. // r2 := n.dot(vToPointInside)
  477. //
  478. // if (r1<0 && r2>0) || (r1>0 && r2<0) {
  479. // return false // Encountered some other sign. Exit.
  480. // }
  481. // }
  482. //
  483. // // If we got here, all dot products were of the same sign.
  484. // return positiveResult ? 1 : -1
  485. //}
  486. // TODO
  487. func (n *Narrowphase) PlaneConvex(bodyA, bodyB *object.Body, planeA *shape.Plane, convexB *shape.ConvexHull, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
  488. contactEqs := make([]*equation.Contact, 0)
  489. frictionEqs := make([]*equation.Friction, 0)
  490. //planeShape,
  491. //convexShape,
  492. //planePosition,
  493. //convexPosition,
  494. //planeQuat,
  495. //convexQuat,
  496. //planeBody,
  497. //convexBody,
  498. //si,
  499. //sj,
  500. //justTest) {
  501. //
  502. //// Simply return the points behind the plane.
  503. //worldVertex := planeConvex_v
  504. //worldNormal := planeConvex_normal
  505. //worldNormal.set(0,0,1)
  506. //planeQuat.vmult(worldNormal,worldNormal) // Turn normal according to plane orientation
  507. //
  508. //var numContacts = 0
  509. //var relpos = planeConvex_relpos
  510. //for i := 0; i < len(convexShape.vertices); i++ {
  511. //
  512. // // Get world convex vertex
  513. // worldVertex.copy(convexShape.vertices[i])
  514. // convexQuat.vmult(worldVertex, worldVertex)
  515. // convexPosition.vadd(worldVertex, worldVertex)
  516. // worldVertex.vsub(planePosition, relpos)
  517. //
  518. // var dot = worldNormal.dot(relpos)
  519. // if dot <= 0.0 {
  520. // if justTest {
  521. // return true
  522. // }
  523. //
  524. // var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj)
  525. //
  526. // // Get vertex position projected on plane
  527. // var projected = planeConvex_projected
  528. // worldNormal.mult(worldNormal.dot(relpos),projected)
  529. // worldVertex.vsub(projected, projected)
  530. // projected.vsub(planePosition, r.ri) // From plane to vertex projected on plane
  531. //
  532. // r.ni.copy(worldNormal) // Contact normal is the plane normal out from plane
  533. //
  534. // // rj is now just the vector from the convex center to the vertex
  535. // worldVertex.vsub(convexPosition, r.rj)
  536. //
  537. // // Make it relative to the body
  538. // r.ri.vadd(planePosition, r.ri)
  539. // r.ri.vsub(planeBody.position, r.ri)
  540. // r.rj.vadd(convexPosition, r.rj)
  541. // r.rj.vsub(convexBody.position, r.rj)
  542. //
  543. // this.result.push(r)
  544. // numContacts++
  545. // if !this.enableFrictionReduction {
  546. // this.createFrictionEquationsFromContact(r, this.frictionResult)
  547. // }
  548. // }
  549. //}
  550. //
  551. //if this.enableFrictionReduction && numContacts {
  552. // this.createFrictionFromAverage(numContacts)
  553. //}
  554. return contactEqs, frictionEqs
  555. }