| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- // Copyright 2016 The G3N Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package physics
- import (
- "github.com/g3n/engine/experimental/physics/object"
- "github.com/g3n/engine/experimental/physics/equation"
- "github.com/g3n/engine/math32"
- "github.com/g3n/engine/experimental/physics/shape"
- )
- // Narrowphase
- type Narrowphase struct {
- simulation *Simulation
- currentContactMaterial *ContactMaterial
- enableFrictionReduction bool // If true friction is computed as average
- debugging bool
- }
- // NewNarrowphase creates and returns a pointer to a new Narrowphase.
- func NewNarrowphase(simulation *Simulation) *Narrowphase {
- n := new(Narrowphase)
- n.simulation = simulation
- //n.enableFrictionReduction = true
- // FOR DEBUGGING
- //n.debugging = true
- return n
- }
- // createFrictionEquationsFromContact
- func (n *Narrowphase) createFrictionEquationsFromContact(contactEquation *equation.Contact) (*equation.Friction, *equation.Friction) {
- bodyA := n.simulation.bodies[contactEquation.BodyA().Index()]
- bodyB := n.simulation.bodies[contactEquation.BodyB().Index()]
- // TODO materials
- // friction = n.currentContactMaterial.friction
- // if materials are defined then override: friction = matA.friction * matB.friction
- //var mug = friction * world.gravity.length()
- //var reducedMass = bodyA.InvMass() + bodyB.InvMass()
- //if reducedMass > 0 {
- // reducedMass = 1/reducedMass
- //}
- slipForce := float32(0.5) //mug*reducedMass
- fricEq1 := equation.NewFriction(bodyA, bodyB, slipForce)
- fricEq2 := equation.NewFriction(bodyA, bodyB, slipForce)
- fricEq1.SetSpookParams(1e7, 3, n.simulation.dt)
- fricEq2.SetSpookParams(1e7, 3, n.simulation.dt)
- // Copy over the relative vectors
- cRA := contactEquation.RA()
- cRB := contactEquation.RB()
- fricEq1.SetRA(&cRA)
- fricEq1.SetRB(&cRB)
- fricEq2.SetRA(&cRA)
- fricEq2.SetRB(&cRB)
- // Construct and set tangents
- cNormal := contactEquation.Normal()
- t1, t2 := cNormal.RandomTangents()
- fricEq1.SetTangent(t1)
- fricEq2.SetTangent(t2)
- // Copy enabled state
- cEnabled := contactEquation.Enabled()
- fricEq1.SetEnabled(cEnabled)
- fricEq2.SetEnabled(cEnabled)
- return fricEq1, fricEq2
- }
- // TODO test this
- func (n *Narrowphase) createFrictionFromAverage(contactEqs []*equation.Contact) (*equation.Friction, *equation.Friction) {
- // The last contactEquation
- lastContactEq := contactEqs[len(contactEqs)-1]
- // Create a friction equation based on the last contact (we will modify it to take into account all contacts)
- fEq1, fEq2 := n.createFrictionEquationsFromContact(lastContactEq)
- if (fEq1 == nil && fEq2 == nil) || len(contactEqs) == 1 {
- return fEq1, fEq2
- }
- averageNormal := math32.NewVec3()
- averageContactPointA := math32.NewVec3()
- averageContactPointB := math32.NewVec3()
- bodyA := lastContactEq.BodyA()
- //bodyB := lastContactEq.BodyB()
- normal := lastContactEq.Normal()
- rA := lastContactEq.RA()
- rB := lastContactEq.RB()
- for _, cEq := range contactEqs {
- if cEq.BodyA() != bodyA {
- averageNormal.Add(&normal)
- averageContactPointA.Add(&rA)
- averageContactPointB.Add(&rB)
- } else {
- averageNormal.Sub(&normal)
- averageContactPointA.Add(&rB)
- averageContactPointB.Add(&rA)
- }
- }
- invNumContacts := float32(1) / float32(len(contactEqs))
- averageContactPointA.MultiplyScalar(invNumContacts)
- averageContactPointB.MultiplyScalar(invNumContacts)
- // Should be the same for both friction equations
- fEq1.SetRA(averageContactPointA)
- fEq1.SetRB(averageContactPointB)
- fEq2.SetRA(averageContactPointA)
- fEq2.SetRB(averageContactPointB)
- // Set tangents
- averageNormal.Normalize()
- t1, t2 := averageNormal.RandomTangents()
- fEq1.SetTangent(t1)
- fEq2.SetTangent(t2)
- return fEq1, fEq2
- }
- // GenerateEquations is the Narrowphase entry point.
- func (n *Narrowphase) GenerateEquations(pairs []CollisionPair) ([]*equation.Contact, []*equation.Friction) {
- // TODO don't "make" every time, simply re-slice
- allContactEqs := make([]*equation.Contact, 0)
- allFrictionEqs := make([]*equation.Friction, 0)
- for k := 0; k < len(pairs); k++ {
- // Get current collision bodies
- bodyA := pairs[k].BodyA
- bodyB := pairs[k].BodyB
- bodyTypeA := bodyA.BodyType()
- bodyTypeB := bodyB.BodyType()
- // For now these collisions are ignored
- // TODO future: just want to check for collision (in order to dispatch events) and not create equations
- justTest := (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Static) ||
- (bodyTypeA == object.Static) && (bodyTypeB == object.Kinematic) ||
- (bodyTypeA == object.Kinematic) && (bodyTypeB == object.Kinematic)
- // Get contacts
- if !justTest {
- //contactEqs, frictionEqs := n.Resolve(bodyA, bodyB)
- contactEqs, frictionEqs := n.ResolveCollision(bodyA, bodyB)
- allContactEqs = append(allContactEqs, contactEqs...)
- allFrictionEqs = append(allFrictionEqs, frictionEqs...)
- }
- }
- return allContactEqs, allFrictionEqs
- }
- // ResolveCollision figures out which implementation of collision detection and contact resolution to use depending on the shapes involved.
- func (n *Narrowphase) ResolveCollision(bodyA, bodyB *object.Body) ([]*equation.Contact, []*equation.Friction) {
- shapeA := bodyA.Shape()
- shapeB := bodyB.Shape()
- posA := bodyA.Position()
- posB := bodyB.Position()
- quatA := bodyA.Quaternion()
- quatB := bodyB.Quaternion()
- switch sA := shapeA.(type) {
- case *shape.Sphere:
- switch sB := shapeB.(type) {
- case *shape.Sphere:
- return n.SphereSphere(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- case *shape.Plane:
- return n.SpherePlane(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- case *shape.ConvexHull:
- return n.SphereConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- }
- case *shape.Plane:
- switch sB := shapeB.(type) {
- case *shape.Sphere:
- return n.SpherePlane(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
- //case *shape.Plane: // plane-plane collision never happens...
- // return n.PlanePlane(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- case *shape.ConvexHull:
- return n.PlaneConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- }
- case *shape.ConvexHull:
- switch sB := shapeB.(type) {
- case *shape.Sphere:
- return n.SphereConvex(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
- case *shape.Plane:
- return n.PlaneConvex(bodyB, bodyA, sB, sA, &posB, &posA, quatB, quatA)
- case *shape.ConvexHull:
- return n.ConvexConvex(bodyA, bodyB, sA, sB, &posA, &posB, quatA, quatB)
- }
- }
- return []*equation.Contact{}, []*equation.Friction{}
- }
- // SphereSphere resolves the collision between two spheres analytically.
- func (n *Narrowphase) SphereSphere(bodyA, bodyB *object.Body, sphereA, sphereB *shape.Sphere, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
- contactEqs := make([]*equation.Contact, 0, 1)
- frictionEqs := make([]*equation.Friction, 0, 2)
- radiusA := sphereA.Radius()
- radiusB := sphereB.Radius()
- if posA.DistanceToSquared(posB) > math32.Pow(radiusA + radiusB, 2) {
- // No collision
- return contactEqs, frictionEqs
- }
- // Find penetration axis
- penAxis := posB.Clone().Sub(posA).Normalize()
- // Create contact equation
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
- contactEq.SetNormal(penAxis.Clone())
- contactEq.SetRA(penAxis.Clone().MultiplyScalar(radiusB))
- contactEq.SetRB(penAxis.Clone().MultiplyScalar(-radiusB))
- contactEqs = append(contactEqs, contactEq)
- // Create friction equations
- fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- frictionEqs = append(frictionEqs, fEq1, fEq2)
- return contactEqs, frictionEqs
- }
- // SpherePlane resolves the collision between a sphere and a plane analytically.
- 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) {
- contactEqs := make([]*equation.Contact, 0)
- frictionEqs := make([]*equation.Friction, 0)
- sphereRadius := sphereA.Radius()
- localNormal := planeB.Normal()
- normal := localNormal.Clone().ApplyQuaternion(quatB).Negate().Normalize()
- // Project down sphere on plane
- point_on_plane_to_sphere := math32.NewVec3().SubVectors(posA, posB)
- plane_to_sphere_ortho := normal.Clone().MultiplyScalar(normal.Dot(point_on_plane_to_sphere))
- if -point_on_plane_to_sphere.Dot(normal) <= sphereRadius {
- //if justTest {
- // return true
- //}
- // We will have one contact in this case
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- contactEq.SetNormal(normal) // Normalize() might not be needed
- contactEq.SetRA(normal.Clone().MultiplyScalar(sphereRadius)) // Vector from sphere center to contact point
- contactEq.SetRB(math32.NewVec3().SubVectors(point_on_plane_to_sphere, plane_to_sphere_ortho)) // The sphere position projected to plane
- contactEqs = append(contactEqs, contactEq)
- // Create friction equations
- fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- frictionEqs = append(frictionEqs, fEq1, fEq2)
- }
- return contactEqs, frictionEqs
- }
- // TODO The second half of this method is untested!!!
- 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) {
- contactEqs := make([]*equation.Contact, 0)
- frictionEqs := make([]*equation.Friction, 0)
- // TODO
- //v3pool := this.v3pool
- //convex_to_sphere := math32.NewVec3().SubVectors(posA, posB)
- //normals := sj.faceNormals
- //faces := sj.faces
- //verts := sj.vertices
- //R := si.radius
- //penetrating_sides := []
- // COMMENTED OUT
- // if(convex_to_sphere.norm2() > si.boundingSphereRadius + sj.boundingSphereRadius){
- // return;
- // }
- sphereRadius := sphereA.Radius()
- // First check if any vertex of the convex hull is inside the sphere
- done := false
- convexB.GetGeometry().ReadVertices(func(vertex math32.Vector3) bool {
- worldVertex := vertex.ApplyQuaternion(quatA).Add(posB)
- sphereToCorner := math32.NewVec3().SubVectors(worldVertex, posA)
- if sphereToCorner.LengthSq() < sphereRadius * sphereRadius {
- // Colliding! worldVertex is inside sphere.
- // Create contact equation
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
- normalizedSphereToCorner := sphereToCorner.Clone().Normalize()
- contactEq.SetNormal(normalizedSphereToCorner)
- contactEq.SetRA(normalizedSphereToCorner.Clone().MultiplyScalar(sphereRadius))
- contactEq.SetRB(worldVertex.Clone().Sub(posB))
- contactEqs = append(contactEqs, contactEq)
- // Create friction equations
- fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- frictionEqs = append(frictionEqs, fEq1, fEq2)
- // Set done flag
- done = true
- // Break out of loop
- return true
- }
- return false
- })
- if done {
- return contactEqs, frictionEqs
- }
- //Check side (plane) intersections TODO NOTE THIS IS UNTESTED
- convexFaces := convexB.Faces()
- convexWorldFaceNormals := convexB.WorldFaceNormals()
- for i := 0; i < len(convexFaces); i++ {
- worldNormal := convexWorldFaceNormals[i]
- face := convexFaces[i]
- // Get a world vertex from the face
- var worldPoint = face[0].Clone().ApplyQuaternion(quatB).Add(posB)
- // Get a point on the sphere, closest to the face normal
- var worldSpherePointClosestToPlane = worldNormal.Clone().MultiplyScalar(-sphereRadius).Add(posA)
- // Vector from a face point to the closest point on the sphere
- var penetrationVec = math32.NewVec3().SubVectors(worldSpherePointClosestToPlane, worldPoint)
- // The penetration. Negative value means overlap.
- var penetration = penetrationVec.Dot(&worldNormal)
- var worldPointToSphere = math32.NewVec3().SubVectors(posA, worldPoint)
- if penetration < 0 && worldPointToSphere.Dot(&worldNormal) > 0 {
- // Intersects plane. Now check if the sphere is inside the face polygon
- worldFace := convexB.WorldFace(face, posB, quatB)
- if n.pointBehindFace(worldFace, &worldNormal, posA) { // Is the sphere center behind the face (inside the convex polygon?
- // TODO NEVER GETTING INSIDE THIS IF STATEMENT!
- ShowWorldFace(n.simulation.Scene(), worldFace[:], &math32.Color{0,0,2})
- // if justTest {
- // return true
- //}
- // Create contact equation
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
- contactEq.SetNormal(worldNormal.Clone().Negate())
- contactEq.SetRA(worldNormal.Clone().MultiplyScalar(-sphereRadius))
- penetrationVec2 := worldNormal.Clone().MultiplyScalar(-penetration)
- penetrationSpherePoint := worldNormal.Clone().MultiplyScalar(-sphereRadius)
- contactEq.SetRB(posA.Clone().Sub(posB).Add(penetrationSpherePoint).Add(penetrationVec2))
- contactEqs = append(contactEqs, contactEq)
- // Create friction equations
- fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- frictionEqs = append(frictionEqs, fEq1, fEq2)
- // Exit method (we only expect *one* face contact)
- return contactEqs, frictionEqs
- } else {
- // Edge?
- for j := 0; j < len(worldFace); j++ {
- // Get two world transformed vertices
- v1 := worldFace[(j+1)%3].Clone()//.ApplyQuaternion(quatB).Add(posB)
- v2 := worldFace[(j+2)%3].Clone()//.ApplyQuaternion(quatB).Add(posB)
- // Construct edge vector
- edge := math32.NewVec3().SubVectors(v2, v1)
- // Construct the same vector, but normalized
- edgeUnit := edge.Clone().Normalize()
- // p is xi projected onto the edge
- v1ToPosA := math32.NewVec3().SubVectors(posA, v1)
- dot := v1ToPosA.Dot(edgeUnit)
- p := edgeUnit.Clone().MultiplyScalar(dot).Add(v1)
- // Compute a vector from p to the center of the sphere
- var posAtoP = math32.NewVec3().SubVectors(p, posA)
- // Collision if the edge-sphere distance is less than the radius AND if p is in between v1 and v2
- edgeL2 := edge.LengthSq()
- patp2 := posAtoP.LengthSq()
- if (dot > 0) && (dot*dot < edgeL2) && (patp2 < sphereRadius*sphereRadius) { // Collision if the edge-sphere distance is less than the radius
- // Edge contact!
- //if justTest {
- // return true
- //}
- // Create contact equation
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- //contactEq.SetEnabled(sphereA.CollisionResponse() && sphereB.CollisionResponse()) // TODO
- normal := p.Clone().Sub(posA).Normalize()
- contactEq.SetNormal(normal)
- contactEq.SetRA(normal.Clone().MultiplyScalar(sphereRadius))
- contactEq.SetRB(p.Clone().Sub(posB))
- contactEqs = append(contactEqs, contactEq)
- // Create friction equations
- //fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- //frictionEqs = append(frictionEqs, fEq1, fEq2)
- // Exit method (we only expect *one* edge contact)
- return contactEqs, frictionEqs
- }
- }
- }
- }
- }
- return contactEqs, frictionEqs
- }
- func (n *Narrowphase) pointBehindFace(worldFace [3]math32.Vector3, faceNormal, point *math32.Vector3) bool {
- pointInFace := worldFace[0].Clone()
- planeDelta := -pointInFace.Dot(faceNormal)
- depth := faceNormal.Dot(point) + planeDelta
- if depth > 0 {
- return false
- } else {
- return true
- }
- }
- // 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.
- //func (n *Narrowphase) pointInPolygon(verts []math32.Vector3, normal, p *math32.Vector3) bool {
- //
- // firstTime := true
- // positiveResult := true // first value of positive result doesn't matter
- // N := len(verts)
- // for i := 0; i < N; i++ {
- // v := verts[i].Clone()
- // // Get edge to the next vertex
- // edge := math32.NewVec3().SubVectors(verts[(i+1)%N].Clone(), v)
- // // Get cross product between polygon normal and the edge
- // edgeCrossNormal := math32.NewVec3().CrossVectors(edge, normal)
- // // Get vector between point and current vertex
- // vertexToP := math32.NewVec3().SubVectors(p, v)
- // // This dot product determines which side of the edge the point is
- // r := edgeCrossNormal.Dot(vertexToP)
- // // If all such dot products have same sign, we are inside the polygon.
- // if firstTime || (r > 0 && positiveResult == true) || (r <= 0 && positiveResult == false) {
- // if firstTime {
- // positiveResult = r > 0
- // firstTime = false
- // }
- // continue
- // } else {
- // return false // Encountered some other sign. Exit.
- // }
- // }
- // // If we got here, all dot products were of the same sign.
- // return true
- //}
- // ConvexConvex implements collision detection and contact resolution between two convex hulls.
- func (n *Narrowphase) ConvexConvex(bodyA, bodyB *object.Body, convexA, convexB *shape.ConvexHull, posA, posB *math32.Vector3, quatA, quatB *math32.Quaternion) ([]*equation.Contact, []*equation.Friction) {
- contactEqs := make([]*equation.Contact, 0)
- frictionEqs := make([]*equation.Friction, 0)
- // Check if colliding and find penetration axis
- penetrating, penAxis := convexA.FindPenetrationAxis(convexB, posA, posB, quatA, quatB)
- if !penetrating {
- return contactEqs, frictionEqs
- }
- if n.debugging {
- ShowPenAxis(n.simulation.Scene(), &penAxis) //, -1000, 1000)
- log.Error("Colliding (%v|%v) penAxis: %v", bodyA.Name(), bodyB.Name(), penAxis)
- }
- // Colliding! Find contacts.
- contacts := convexA.ClipAgainstHull(convexB, posA, posB, quatA, quatB, &penAxis, -100, 100)
- // For each contact found create a contact equation and the two associated friction equations
- for j := 0; j < len(contacts); j++ {
- contact := contacts[j]
- if n.debugging {
- ShowContact(n.simulation.Scene(), &contact) // TODO DEBUGGING
- }
- // Note - contact Normals point from B to A (contacts live in B)
- // Create contact equation and append it
- contactEq := equation.NewContact(bodyA, bodyB, 0, 1e6)
- contactEq.SetSpookParams(1e6, 3, n.simulation.dt)
- contactEq.SetEnabled(bodyA.CollisionResponse() && bodyB.CollisionResponse())
- contactEq.SetNormal(penAxis.Clone())
- contactEq.SetRA(contact.Normal.Clone().MultiplyScalar(-contact.Depth).Add(&contact.Point).Sub(posA))
- contactEq.SetRB(contact.Point.Clone().Sub(posB))
- contactEqs = append(contactEqs, contactEq)
- // If enableFrictionReduction is true then skip creating friction equations for individual contacts
- // We will create average friction equations later based on all contacts
- if !n.enableFrictionReduction {
- fEq1, fEq2 := n.createFrictionEquationsFromContact(contactEq)
- frictionEqs = append(frictionEqs, fEq1, fEq2)
- }
- }
- // If enableFrictionReduction is true then we skipped creating friction equations for individual contacts
- // We now want to create average friction equations based on all contact points.
- // If we only have one contact however, then friction is small and we don't need to create the friction equations at all.
- // TODO
- if n.enableFrictionReduction && len(contactEqs) > 1 {
- //fEq1, fEq2 := n.createFrictionFromAverage(contactEqs)
- //frictionEqs = append(frictionEqs, fEq1, fEq2)
- }
- return contactEqs, frictionEqs
- }
- //// TODO ?
- //func (n *Narrowphase) GetAveragePointLocal(target) {
- //
- // target = target || new Vec3()
- // n := this.vertices.length
- // verts := this.vertices
- // for i := 0; i < n; i++ {
- // target.vadd(verts[i],target)
- // }
- // target.mult(1/n,target)
- // return target
- //}
- // Checks whether p is inside the polyhedra. Must be in local coords.
- // The point lies outside of the convex hull of the other points if and only if
- // the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
- // p is A point given in local coordinates
- //func (n *Narrowphase) PointIsInside(p) {
- //
- // verts := this.vertices
- // faces := this.faces
- // normals := this.faceNormals
- // positiveResult := null
- // N := this.faces.length
- // pointInside := ConvexPolyhedron_pointIsInside
- // this.getAveragePointLocal(pointInside)
- // for i := 0; i < N; i++ {
- // numVertices := this.faces[i].length
- // n := normals[i]
- // v := verts[faces[i][0]] // We only need one point in the face
- //
- // // This dot product determines which side of the edge the point is
- // vToP := ConvexPolyhedron_vToP
- // p.vsub(v,vToP)
- // r1 := n.dot(vToP)
- //
- // vToPointInside := ConvexPolyhedron_vToPointInside
- // pointInside.vsub(v,vToPointInside)
- // r2 := n.dot(vToPointInside)
- //
- // if (r1<0 && r2>0) || (r1>0 && r2<0) {
- // return false // Encountered some other sign. Exit.
- // }
- // }
- //
- // // If we got here, all dot products were of the same sign.
- // return positiveResult ? 1 : -1
- //}
- // TODO
- 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) {
- contactEqs := make([]*equation.Contact, 0)
- frictionEqs := make([]*equation.Friction, 0)
- //planeShape,
- //convexShape,
- //planePosition,
- //convexPosition,
- //planeQuat,
- //convexQuat,
- //planeBody,
- //convexBody,
- //si,
- //sj,
- //justTest) {
- //
- //// Simply return the points behind the plane.
- //worldVertex := planeConvex_v
- //worldNormal := planeConvex_normal
- //worldNormal.set(0,0,1)
- //planeQuat.vmult(worldNormal,worldNormal) // Turn normal according to plane orientation
- //
- //var numContacts = 0
- //var relpos = planeConvex_relpos
- //for i := 0; i < len(convexShape.vertices); i++ {
- //
- // // Get world convex vertex
- // worldVertex.copy(convexShape.vertices[i])
- // convexQuat.vmult(worldVertex, worldVertex)
- // convexPosition.vadd(worldVertex, worldVertex)
- // worldVertex.vsub(planePosition, relpos)
- //
- // var dot = worldNormal.dot(relpos)
- // if dot <= 0.0 {
- // if justTest {
- // return true
- // }
- //
- // var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj)
- //
- // // Get vertex position projected on plane
- // var projected = planeConvex_projected
- // worldNormal.mult(worldNormal.dot(relpos),projected)
- // worldVertex.vsub(projected, projected)
- // projected.vsub(planePosition, r.ri) // From plane to vertex projected on plane
- //
- // r.ni.copy(worldNormal) // Contact normal is the plane normal out from plane
- //
- // // rj is now just the vector from the convex center to the vertex
- // worldVertex.vsub(convexPosition, r.rj)
- //
- // // Make it relative to the body
- // r.ri.vadd(planePosition, r.ri)
- // r.ri.vsub(planeBody.position, r.ri)
- // r.rj.vadd(convexPosition, r.rj)
- // r.rj.vsub(convexBody.position, r.rj)
- //
- // this.result.push(r)
- // numContacts++
- // if !this.enableFrictionReduction {
- // this.createFrictionEquationsFromContact(r, this.frictionResult)
- // }
- // }
- //}
- //
- //if this.enableFrictionReduction && numContacts {
- // this.createFrictionFromAverage(numContacts)
- //}
- return contactEqs, frictionEqs
- }
|