narrowphase.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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/physics/object"
  7. "github.com/g3n/engine/physics/collision"
  8. "github.com/g3n/engine/physics/equation"
  9. "github.com/g3n/engine/math32"
  10. "github.com/g3n/engine/physics/material"
  11. )
  12. // Narrowphase
  13. type Narrowphase struct {
  14. simulation *Simulation
  15. currentContactMaterial *material.ContactMaterial
  16. enableFrictionReduction bool // If true friction is computed as average
  17. debugging bool
  18. }
  19. type Pair struct {
  20. bodyA *object.Body
  21. bodyB *object.Body
  22. }
  23. // NewNarrowphase creates and returns a pointer to a new Narrowphase.
  24. func NewNarrowphase(simulation *Simulation) *Narrowphase {
  25. n := new(Narrowphase)
  26. n.simulation = simulation
  27. //n.enableFrictionReduction = true
  28. // FOR DEBUGGING
  29. n.debugging = true
  30. return n
  31. }
  32. func (n *Narrowphase) GetContacts(pairs []collision.Pair) ([]*equation.Contact, []*equation.Friction) {
  33. allContactEqs := make([]*equation.Contact, 0)
  34. allFrictionEqs := make([]*equation.Friction, 0)
  35. for k := 0; k < len(pairs); k++ {
  36. // Get current collision bodies
  37. bodyA := pairs[k].BodyA
  38. bodyB := pairs[k].BodyB
  39. bodyTypeA := bodyA.BodyType()
  40. bodyTypeB := bodyB.BodyType()
  41. // For now these collisions are ignored
  42. // TODO future: just want to check for collision (in order to dispatch events) and not create equations
  43. justTest := (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Static) ||
  44. (bodyTypeA == object.Static) && (bodyTypeB == object.Kinematic) ||
  45. (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Kinematic)
  46. // Get contacts
  47. if !justTest {
  48. _, contactEqs, frictionEqs := n.Resolve(bodyA, bodyB)
  49. allContactEqs = append(allContactEqs, contactEqs...)
  50. allFrictionEqs = append(allFrictionEqs, frictionEqs...)
  51. }
  52. }
  53. return allContactEqs, allFrictionEqs
  54. }
  55. // Convex - Convex collision detection
  56. //func (n *Narrowphase) Resolve(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest) {
  57. func (n *Narrowphase) Resolve(bodyA, bodyB *object.Body) (bool, []*equation.Contact, []*equation.Friction) {
  58. contactEqs := make([]*equation.Contact, 0)
  59. frictionEqs := make([]*equation.Friction, 0)
  60. // Check if colliding and find penetration axis
  61. penetrating, penAxis := n.FindPenetrationAxis(bodyA, bodyB)
  62. if penetrating {
  63. // Colliding! Find contacts.
  64. ShowPenAxis(n.simulation.Scene(), &penAxis) //, -1000, 1000)
  65. log.Error("Colliding (%v|%v) penAxis: %v", bodyA.Name(), bodyB.Name(), penAxis)
  66. contacts := n.ClipAgainstHull(bodyA, bodyB, &penAxis, -100, 100)
  67. log.Error(" .... contacts: %v", contacts)
  68. posA := bodyA.Position()
  69. posB := bodyB.Position()
  70. for j := 0; j < len(contacts); j++ {
  71. contact := contacts[j]
  72. ShowContact(n.simulation.Scene(), &contact) // TODO DEBUGGING
  73. // Note - contact Normals point from B to A (contacts live in B)
  74. // Create contact equation and append it
  75. contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
  76. contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
  77. contactEq.SetEnabled(bodyA.CollisionResponse() && bodyB.CollisionResponse())
  78. contactEq.SetNormal(penAxis.Clone())
  79. log.Error("contact.Depth: %v", contact.Depth)
  80. contactEq.SetRA(contact.Normal.Clone().MultiplyScalar(contact.Depth).Add(&contact.Point).Sub(&posA))
  81. contactEq.SetRB(contact.Point.Clone().Sub(&posB))
  82. contactEqs = append(contactEqs, contactEq)
  83. // If enableFrictionReduction is true then skip creating friction equations for individual contacts
  84. // We will create average friction equations later based on all contacts
  85. // TODO
  86. if !n.enableFrictionReduction {
  87. fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
  88. frictionEqs = append(frictionEqs, fEq1, fEq2)
  89. }
  90. }
  91. // If enableFrictionReduction is true then we skipped creating friction equations for individual contacts
  92. // We now want to create average friction equations based on all contact points.
  93. // If we only have one contact however, then friction is small and we don't need to create the friction equations at all.
  94. // TODO
  95. if n.enableFrictionReduction && len(contactEqs) > 1 {
  96. //fEq1, fEq2 := n.createFrictionFromAverage(contactEqs)
  97. //frictionEqs = append(frictionEqs, fEq1, fEq2)
  98. }
  99. }
  100. return false, contactEqs, frictionEqs
  101. }
  102. func (n *Narrowphase) createFrictionEquationsFromContact(contactEquation *equation.Contact) (*equation.Friction, *equation.Friction) { //}, outArray) bool {
  103. bodyA := n.simulation.bodies[contactEquation.BodyA().Index()]
  104. bodyB := n.simulation.bodies[contactEquation.BodyB().Index()]
  105. // TODO
  106. // friction = n.currentContactMaterial.friction
  107. // if materials are defined then override: friction = matA.friction * matB.friction
  108. //var mug = friction * world.gravity.length()
  109. //var reducedMass = bodyA.InvMass() + bodyB.InvMass()
  110. //if reducedMass > 0 {
  111. // reducedMass = 1/reducedMass
  112. //}
  113. slipForce := float32(0.5) //mug*reducedMass
  114. fricEq1 := equation.NewFriction(bodyA, bodyB, slipForce)
  115. fricEq2 := equation.NewFriction(bodyA, bodyB, slipForce)
  116. fricEq1.SetSpookParams(1e7, 3, n.simulation.dt)
  117. fricEq2.SetSpookParams(1e7, 3, n.simulation.dt)
  118. // Copy over the relative vectors
  119. cRA := contactEquation.RA()
  120. cRB := contactEquation.RB()
  121. fricEq1.SetRA(&cRA)
  122. fricEq1.SetRB(&cRB)
  123. fricEq2.SetRA(&cRA)
  124. fricEq2.SetRB(&cRB)
  125. // Construct tangents
  126. cNormal := contactEquation.Normal()
  127. t1, t2 := cNormal.RandomTangents()
  128. fricEq1.SetTangent(t1)
  129. fricEq2.SetTangent(t2)
  130. // Copy enabled state
  131. cEnabled := contactEquation.Enabled()
  132. fricEq1.SetEnabled(cEnabled)
  133. fricEq2.SetEnabled(cEnabled)
  134. return fricEq1, fricEq2
  135. }
  136. func (n *Narrowphase) createFrictionFromAverage(contactEqs []*equation.Contact) (*equation.Friction, *equation.Friction) {
  137. // The last contactEquation
  138. lastContactEq := contactEqs[len(contactEqs)-1]
  139. // Create a friction equation based on the last contact (we will modify it to take into account all contacts)
  140. fEq1, fEq2 := n.createFrictionEquationsFromContact(lastContactEq)
  141. if (fEq1 == nil && fEq2 == nil) || len(contactEqs) == 1 {
  142. return fEq1, fEq2
  143. }
  144. averageNormal := math32.NewVec3()
  145. averageContactPointA := math32.NewVec3()
  146. averageContactPointB := math32.NewVec3()
  147. bodyA := lastContactEq.BodyA()
  148. //bodyB := lastContactEq.BodyB()
  149. normal := lastContactEq.Normal()
  150. rA := lastContactEq.RA()
  151. rB := lastContactEq.RB()
  152. for _, cEq := range contactEqs {
  153. if cEq.BodyA() != bodyA {
  154. averageNormal.Add(&normal)
  155. averageContactPointA.Add(&rA)
  156. averageContactPointB.Add(&rB)
  157. } else {
  158. averageNormal.Sub(&normal)
  159. averageContactPointA.Add(&rB)
  160. averageContactPointB.Add(&rA)
  161. }
  162. }
  163. invNumContacts := float32(1) / float32(len(contactEqs))
  164. averageContactPointA.MultiplyScalar(invNumContacts)
  165. averageContactPointB.MultiplyScalar(invNumContacts)
  166. // Should be the same for both friction equations
  167. fEq1.SetRA(averageContactPointA)
  168. fEq1.SetRB(averageContactPointB)
  169. fEq2.SetRA(averageContactPointA)
  170. fEq2.SetRB(averageContactPointB)
  171. // Set tangents
  172. averageNormal.Normalize()
  173. t1, t2 := averageNormal.RandomTangents()
  174. fEq1.SetTangent(t1)
  175. fEq2.SetTangent(t2)
  176. return fEq1, fEq2
  177. }
  178. //
  179. // Penetration Axis =============================================
  180. //
  181. // FindPenetrationAxis finds the penetration axis between two convex bodies.
  182. // The normal points from bodyA to bodyB.
  183. // Returns false if there is no penetration. If there is a penetration - returns true and the penetration axis.
  184. func (n *Narrowphase) FindPenetrationAxis(bodyA, bodyB *object.Body) (bool, math32.Vector3) {
  185. // Keep track of the smaller depth found so far
  186. // Note that the penetration axis is the one that causes
  187. // the smallest penetration depth when the two hulls are squished onto that axis!
  188. // (may seem a bit counter-intuitive)
  189. depthMin := math32.Inf(1)
  190. var penetrationAxis math32.Vector3
  191. var depth float32
  192. // Assume the geometries are penetrating.
  193. // As soon as (and if) we figure out that they are not, then return false.
  194. penetrating := true
  195. worldFaceNormalsA := bodyA.WorldFaceNormals()
  196. worldFaceNormalsB := bodyB.WorldFaceNormals()
  197. // Check world normals of body A
  198. for _, worldFaceNormal := range worldFaceNormalsA {
  199. // Check whether the face is colliding with geomB
  200. penetrating, depth = n.TestPenetrationAxis(&worldFaceNormal, bodyA, bodyB)
  201. if !penetrating {
  202. return false, penetrationAxis // penetrationAxis doesn't matter since not penetrating
  203. }
  204. if depth < depthMin {
  205. depthMin = depth
  206. penetrationAxis.Copy(&worldFaceNormal)
  207. }
  208. }
  209. // Check world normals of body B
  210. for _, worldFaceNormal := range worldFaceNormalsB {
  211. // Check whether the face is colliding with geomB
  212. penetrating, depth = n.TestPenetrationAxis(&worldFaceNormal, bodyA, bodyB)
  213. if !penetrating {
  214. return false, penetrationAxis // penetrationAxis doesn't matter since not penetrating
  215. }
  216. if depth < depthMin {
  217. depthMin = depth
  218. penetrationAxis.Copy(&worldFaceNormal)
  219. }
  220. }
  221. worldUniqueEdgesA := bodyA.WorldUniqueEdges()
  222. worldUniqueEdgesB := bodyB.WorldUniqueEdges()
  223. // Check all combinations of unique world edges
  224. for _, worldUniqueEdgeA := range worldUniqueEdgesA {
  225. for _, worldUniqueEdgeB := range worldUniqueEdgesB {
  226. // Cross edges
  227. edgeCross := math32.NewVec3().CrossVectors(&worldUniqueEdgeA, &worldUniqueEdgeB)
  228. // If the edges are not aligned
  229. tol := float32(1e-6)
  230. if edgeCross.Length() > tol { // Cross product is not close to zero
  231. edgeCross.Normalize()
  232. penetrating, depth = n.TestPenetrationAxis(edgeCross, bodyA, bodyB)
  233. if !penetrating {
  234. return false, penetrationAxis
  235. }
  236. if depth < depthMin {
  237. depthMin = depth
  238. penetrationAxis.Copy(edgeCross)
  239. }
  240. }
  241. }
  242. }
  243. posA := bodyA.Position()
  244. posB := bodyB.Position()
  245. deltaC := math32.NewVec3().SubVectors(&posA, &posB)
  246. if deltaC.Dot(&penetrationAxis) > 0.0 {
  247. penetrationAxis.Negate()
  248. }
  249. return true, penetrationAxis
  250. }
  251. // Both hulls are projected onto the axis and the overlap size (penetration depth) is returned if there is one.
  252. // return {number} The overlap depth, or FALSE if no penetration.
  253. func (n *Narrowphase) TestPenetrationAxis(worldAxis *math32.Vector3, bodyA, bodyB *object.Body) (bool, float32) {
  254. maxA, minA := n.ProjectOntoWorldAxis(bodyA, worldAxis)
  255. maxB, minB := n.ProjectOntoWorldAxis(bodyB, worldAxis)
  256. if maxA < minB || maxB < minA {
  257. return false, 0 // Separated
  258. }
  259. d0 := maxA - minB
  260. d1 := maxB - minA
  261. if d0 < d1 {
  262. return true, d0
  263. } else {
  264. return true, d1
  265. }
  266. }
  267. // ProjectOntoWorldAxis projects the geometry onto the specified world axis.
  268. func (n *Narrowphase) ProjectOntoWorldAxis(body *object.Body, axis *math32.Vector3) (float32, float32) {
  269. // Transform the axis to local
  270. quatConj := body.Quaternion().Conjugate()
  271. localAxis := axis.Clone().ApplyQuaternion(quatConj)
  272. max, min := body.GetGeometry().ProjectOntoAxis(localAxis)
  273. // Offset to obtain values relative to world origin
  274. bodyPos := body.Position()
  275. localOrigin := math32.NewVec3().Sub(&bodyPos).ApplyQuaternion(quatConj)
  276. add := localOrigin.Dot(localAxis)
  277. min -= add
  278. max -= add
  279. return max, min
  280. }
  281. //
  282. // Contact Finding =============================================
  283. //
  284. // Contact describes a contact point.
  285. type Contact struct {
  286. Point math32.Vector3
  287. Normal math32.Vector3
  288. Depth float32
  289. }
  290. //{array} result The an array of contact point objects, see clipFaceAgainstHull
  291. func (n *Narrowphase) ClipAgainstHull(bodyA, bodyB *object.Body, penAxis *math32.Vector3, minDist, maxDist float32) []Contact {
  292. var contacts []Contact
  293. // Invert penetration axis so it points from b to a
  294. invPenAxis := penAxis.Clone().Negate()
  295. // Find face of B that is closest (i.e. that is most aligned with the penetration axis)
  296. closestFaceBidx := -1
  297. dmax := math32.Inf(-1)
  298. worldFaceNormalsB := bodyB.WorldFaceNormals()
  299. for i, worldFaceNormal := range worldFaceNormalsB {
  300. // Note - normals must be pointing out of the body so that they align with the penetration axis in the line below
  301. d := worldFaceNormal.Dot(invPenAxis)
  302. if d > dmax {
  303. dmax = d
  304. closestFaceBidx = i
  305. }
  306. }
  307. // If found a closest face (sometimes we don't find one)
  308. if closestFaceBidx >= 0 {
  309. // Copy and transform face vertices to world coordinates
  310. faces := bodyB.Faces()
  311. worldClosestFaceB := n.WorldFace(faces[closestFaceBidx], bodyB)
  312. contacts = n.ClipFaceAgainstHull(penAxis, bodyA, worldClosestFaceB, minDist, maxDist)
  313. }
  314. return contacts
  315. }
  316. func (n *Narrowphase) WorldFace(face [3]math32.Vector3, body *object.Body) [3]math32.Vector3 {
  317. var result [3]math32.Vector3
  318. result[0] = face[0]
  319. result[1] = face[1]
  320. result[2] = face[2]
  321. pos := body.Position()
  322. result[0].ApplyQuaternion(body.Quaternion()).Add(&pos)
  323. result[1].ApplyQuaternion(body.Quaternion()).Add(&pos)
  324. result[2].ApplyQuaternion(body.Quaternion()).Add(&pos)
  325. return result
  326. }
  327. func (n *Narrowphase) WorldFaceNormal(normal *math32.Vector3, body *object.Body) math32.Vector3 {
  328. pos := body.Position()
  329. result := normal.Clone().ApplyQuaternion(body.Quaternion()).Add(&pos)
  330. return *result
  331. }
  332. // TODO move to geometry ?
  333. // Clip a face against a hull.
  334. //@param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
  335. //@param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
  336. func (n *Narrowphase) ClipFaceAgainstHull(penAxis *math32.Vector3, bodyA *object.Body, worldClosestFaceB [3]math32.Vector3, minDist, maxDist float32) []Contact {
  337. contacts := make([]Contact, 0)
  338. // Find the face of A with normal closest to the separating axis (i.e. that is most aligned with the penetration axis)
  339. closestFaceAidx := -1
  340. dmax := math32.Inf(-1)
  341. worldFaceNormalsA := bodyA.WorldFaceNormals()
  342. for i, worldFaceNormal := range worldFaceNormalsA {
  343. // Note - normals must be pointing out of the body so that they align with the penetration axis in the line below
  344. d := worldFaceNormal.Dot(penAxis)
  345. if d > dmax {
  346. dmax = d
  347. closestFaceAidx = i
  348. }
  349. }
  350. if closestFaceAidx < 0 {
  351. // Did not find any closest face...
  352. return contacts
  353. }
  354. //console.log("closest A: ",worldClosestFaceA);
  355. // Get the face and construct connected faces
  356. facesA := bodyA.Faces()
  357. //worldClosestFaceA := n.WorldFace(facesA[closestFaceAidx], bodyA)
  358. closestFaceA := facesA[closestFaceAidx]
  359. connectedFaces := make([]int, 0) // indexes of the connected faces
  360. for faceIdx := 0; faceIdx < len(facesA); faceIdx++ {
  361. // Skip worldClosestFaceA
  362. if faceIdx == closestFaceAidx {
  363. continue
  364. }
  365. // Test that face has not already been added
  366. for _, cfidx := range connectedFaces {
  367. if cfidx == faceIdx {
  368. continue
  369. }
  370. }
  371. face := facesA[faceIdx]
  372. // Loop through face vertices and see if any of them are also present in the closest face
  373. // If a vertex is shared and this connected face hasn't been recorded yet - record and break inner loop
  374. for pConnFaceVidx := 0; pConnFaceVidx < len(face); pConnFaceVidx++ {
  375. var goToNextFace bool
  376. // Test if face shares a vertex with closetFaceA - add it to connectedFaces if so and break out of both loops
  377. for closFaceVidx := 0; closFaceVidx < len(closestFaceA); closFaceVidx++ {
  378. if closestFaceA[closFaceVidx].Equals(&face[pConnFaceVidx]) {
  379. connectedFaces = append(connectedFaces, faceIdx)
  380. goToNextFace = true
  381. break
  382. }
  383. }
  384. if goToNextFace {
  385. break
  386. }
  387. }
  388. }
  389. // DEBUGGING
  390. //log.Error("CONN-FACES: %v", len(connectedFaces))
  391. for _, fidx := range connectedFaces {
  392. wFace := n.WorldFace(facesA[fidx], bodyA)
  393. ShowWorldFace(n.simulation.Scene(), wFace[:], &math32.Color{0.8,0.8,0.8})
  394. }
  395. worldClosestFaceA := n.WorldFace(closestFaceA, bodyA)
  396. //log.Error("worldClosestFaceA: %v", worldClosestFaceA)
  397. //log.Error("worldClosestFaceB: %v", worldClosestFaceB)
  398. ShowWorldFace(n.simulation.Scene(), worldClosestFaceA[:], &math32.Color{2,0,0})
  399. ShowWorldFace(n.simulation.Scene(), worldClosestFaceB[:], &math32.Color{0,2,0})
  400. clippedFace := make([]math32.Vector3, len(worldClosestFaceB))
  401. for i, v := range worldClosestFaceB {
  402. clippedFace[i] = v
  403. }
  404. // TODO port simplified loop to cannon.js once done and verified
  405. // https://github.com/schteppe/cannon.js/issues/378
  406. // https://github.com/TheRohans/cannon.js/commit/62a1ce47a851b7045e68f7b120b9e4ecb0d91aab#r29106924
  407. posA := bodyA.Position()
  408. quatA := bodyA.Quaternion()
  409. // Iterate over connected faces and clip the planes associated with their normals
  410. for _, cfidx := range connectedFaces {
  411. connFace := facesA[cfidx]
  412. connFaceNormal := worldFaceNormalsA[cfidx]
  413. // Choose a vertex in the connected face and use it to find the plane constant
  414. worldFirstVertex := connFace[0].Clone().ApplyQuaternion(quatA).Add(&posA)
  415. planeDelta := - worldFirstVertex.Dot(&connFaceNormal)
  416. clippedFace = n.ClipFaceAgainstPlane(clippedFace, connFaceNormal.Clone(), planeDelta)
  417. }
  418. // Plot clipped face
  419. log.Error("worldClosestFaceBClipped: %v", clippedFace)
  420. ShowWorldFace(n.simulation.Scene(), clippedFace, &math32.Color{0,0,2})
  421. closestFaceAnormal := worldFaceNormalsA[closestFaceAidx]
  422. worldFirstVertex := worldClosestFaceA[0].Clone()//.ApplyQuaternion(quatA).Add(&posA)
  423. planeDelta := -worldFirstVertex.Dot(&closestFaceAnormal)
  424. for _, vertex := range clippedFace {
  425. depth := closestFaceAnormal.Dot(&vertex) + planeDelta
  426. // Cap distance
  427. if depth <= minDist {
  428. depth = minDist
  429. }
  430. if depth <= maxDist {
  431. if depth <= 0 {
  432. contacts = append(contacts, Contact{
  433. Point: vertex,
  434. Normal: closestFaceAnormal,
  435. Depth: depth,
  436. })
  437. }
  438. }
  439. }
  440. return contacts
  441. }
  442. // Clip a face in a hull against the back of a plane.
  443. // @param {Number} planeConstant The constant in the mathematical plane equation
  444. func (n *Narrowphase) ClipFaceAgainstPlane(face []math32.Vector3, planeNormal *math32.Vector3, planeConstant float32) []math32.Vector3 {
  445. // inVertices are the verts making up the face of hullB
  446. clippedFace := make([]math32.Vector3, 0)
  447. if len(face) < 2 {
  448. return face
  449. }
  450. firstVertex := face[len(face)-1]
  451. dotFirst := planeNormal.Dot(&firstVertex) + planeConstant
  452. for vi := 0; vi < len(face); vi++ {
  453. lastVertex := face[vi]
  454. dotLast := planeNormal.Dot(&lastVertex) + planeConstant
  455. if dotFirst < 0 { // Inside hull
  456. if dotLast < 0 { // Start < 0, end < 0, so output lastVertex
  457. clippedFace = append(clippedFace, lastVertex)
  458. } else { // Start < 0, end >= 0, so output intersection
  459. newv := firstVertex.Clone().Lerp(&lastVertex, dotFirst / (dotFirst - dotLast))
  460. clippedFace = append(clippedFace, *newv)
  461. }
  462. } else { // Outside hull
  463. if dotLast < 0 { // Start >= 0, end < 0 so output intersection and end
  464. newv := firstVertex.Clone().Lerp(&lastVertex, dotFirst / (dotFirst - dotLast))
  465. clippedFace = append(clippedFace, *newv)
  466. clippedFace = append(clippedFace, lastVertex)
  467. }
  468. }
  469. firstVertex = lastVertex
  470. dotFirst = dotLast
  471. }
  472. return clippedFace
  473. }
  474. //// TODO ?
  475. //func (n *Narrowphase) GetAveragePointLocal(target) {
  476. //
  477. // target = target || new Vec3()
  478. // n := this.vertices.length
  479. // verts := this.vertices
  480. // for i := 0; i < n; i++ {
  481. // target.vadd(verts[i],target)
  482. // }
  483. // target.mult(1/n,target)
  484. // return target
  485. //}
  486. //
  487. //
  488. //// Checks whether p is inside the polyhedra. Must be in local coords.
  489. //// The point lies outside of the convex hull of the other points if and only if
  490. //// the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
  491. //// p is A point given in local coordinates
  492. //func (n *Narrowphase) PointIsInside(p) {
  493. //
  494. // verts := this.vertices
  495. // faces := this.faces
  496. // normals := this.faceNormals
  497. // positiveResult := null
  498. // N := this.faces.length
  499. // pointInside := ConvexPolyhedron_pointIsInside
  500. // this.getAveragePointLocal(pointInside)
  501. // for i := 0; i < N; i++ {
  502. // numVertices := this.faces[i].length
  503. // n := normals[i]
  504. // v := verts[faces[i][0]] // We only need one point in the face
  505. //
  506. // // This dot product determines which side of the edge the point is
  507. // vToP := ConvexPolyhedron_vToP
  508. // p.vsub(v,vToP)
  509. // r1 := n.dot(vToP)
  510. //
  511. // vToPointInside := ConvexPolyhedron_vToPointInside
  512. // pointInside.vsub(v,vToPointInside)
  513. // r2 := n.dot(vToPointInside)
  514. //
  515. // if (r1<0 && r2>0) || (r1>0 && r2<0) {
  516. // return false // Encountered some other sign. Exit.
  517. // }
  518. // }
  519. //
  520. // // If we got here, all dot products were of the same sign.
  521. // return positiveResult ? 1 : -1
  522. //}
  523. // TODO
  524. //func (n *Narrowphase) planevConvex(
  525. // planeShape,
  526. // convexShape,
  527. // planePosition,
  528. // convexPosition,
  529. // planeQuat,
  530. // convexQuat,
  531. // planeBody,
  532. // convexBody,
  533. // si,
  534. // sj,
  535. // justTest) {
  536. //
  537. // // Simply return the points behind the plane.
  538. // worldVertex := planeConvex_v
  539. // worldNormal := planeConvex_normal
  540. // worldNormal.set(0,0,1)
  541. // planeQuat.vmult(worldNormal,worldNormal) // Turn normal according to plane orientation
  542. //
  543. // var numContacts = 0
  544. // var relpos = planeConvex_relpos
  545. // for i := 0; i < len(convexShape.vertices); i++ {
  546. //
  547. // // Get world convex vertex
  548. // worldVertex.copy(convexShape.vertices[i])
  549. // convexQuat.vmult(worldVertex, worldVertex)
  550. // convexPosition.vadd(worldVertex, worldVertex)
  551. // worldVertex.vsub(planePosition, relpos)
  552. //
  553. // var dot = worldNormal.dot(relpos)
  554. // if dot <= 0.0 {
  555. // if justTest {
  556. // return true
  557. // }
  558. //
  559. // var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj)
  560. //
  561. // // Get vertex position projected on plane
  562. // var projected = planeConvex_projected
  563. // worldNormal.mult(worldNormal.dot(relpos),projected)
  564. // worldVertex.vsub(projected, projected)
  565. // projected.vsub(planePosition, r.ri) // From plane to vertex projected on plane
  566. //
  567. // r.ni.copy(worldNormal) // Contact normal is the plane normal out from plane
  568. //
  569. // // rj is now just the vector from the convex center to the vertex
  570. // worldVertex.vsub(convexPosition, r.rj)
  571. //
  572. // // Make it relative to the body
  573. // r.ri.vadd(planePosition, r.ri)
  574. // r.ri.vsub(planeBody.position, r.ri)
  575. // r.rj.vadd(convexPosition, r.rj)
  576. // r.rj.vsub(convexBody.position, r.rj)
  577. //
  578. // this.result.push(r)
  579. // numContacts++
  580. // if !this.enableFrictionReduction {
  581. // this.createFrictionEquationsFromContact(r, this.frictionResult)
  582. // }
  583. // }
  584. // }
  585. //
  586. // if this.enableFrictionReduction && numContacts {
  587. // this.createFrictionFromAverage(numContacts)
  588. // }
  589. //}