-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathcollisionthrow.ts
87 lines (73 loc) · 2.54 KB
/
collisionthrow.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { Vector3 } from "three"
import { Ball } from "../ball"
import { Collision } from "./collision"
import { I, m, R } from "./constants"
/**
* Based on
* https://billiards.colostate.edu/technical_proofs/new/TP_A-14.pdf
*
*/
export class CollisionThrow {
normalImpulse: number
tangentialImpulse: number
private dynamicFriction(vRel: number): number {
return 0.01 + 0.108 * Math.exp(-1.088 * vRel)
}
public updateVelocities(a: Ball, b: Ball) {
const contact = Collision.positionsAtContact(a, b)
a.ballmesh.trace.forceTrace(contact.a)
b.ballmesh.trace.forceTrace(contact.b)
const ab = contact.b.sub(contact.a).normalize()
const abTangent = new Vector3(-ab.y, ab.x, 0)
const e = 0.99
const vPoint = a.vel
.clone()
.sub(b.vel)
.add(
ab
.clone()
.multiplyScalar(-R)
.cross(a.rvel)
.sub(ab.clone().multiplyScalar(R).cross(b.rvel))
)
const vRelNormalMag = ab.dot(vPoint)
const vRel = vPoint.addScaledVector(ab, -vRelNormalMag)
const vRelMag = vRel.length()
const vRelTangential = abTangent.dot(vRel) // slip velocity perpendicular to line of impact
const μ = this.dynamicFriction(vRelMag)
// let normalImpulse = vRelNormalMag;
// let tangentialImpulse = Math.min((μ * vRelNormalMag) / vRelMag, 1 / 7) * (-vRelTangential)
// matches paper when throwAngle = Math.atan2(tangentialImpulse, normalImpulse)
// Normal impulse (inelastic collision)
this.normalImpulse = (-(1 + e) * vRelNormalMag) / (2 / m)
// Tangential impulse (frictional constraint) reduced by 1/3 until understood
this.tangentialImpulse =
0.3 *
Math.min((μ * Math.abs(this.normalImpulse)) / vRelMag, 1 / 7) *
-vRelTangential
// Impulse vectors
const impulseNormal = ab.clone().multiplyScalar(this.normalImpulse)
const impulseTangential = abTangent
.clone()
.multiplyScalar(this.tangentialImpulse)
// Apply impulses to linear velocities
a.vel
.addScaledVector(impulseNormal, 1 / m)
.addScaledVector(impulseTangential, 1 / m)
b.vel
.addScaledVector(impulseNormal, -1 / m)
.addScaledVector(impulseTangential, -1 / m)
// Angular velocity updates
const angularImpulseA = ab
.clone()
.multiplyScalar(-R)
.cross(impulseTangential)
const angularImpulseB = ab
.clone()
.multiplyScalar(R)
.cross(impulseTangential)
a.rvel.addScaledVector(angularImpulseA, 1 / I)
b.rvel.addScaledVector(angularImpulseB, 1 / I)
return vRelNormalMag
}
}