Created
October 16, 2019 22:24
-
-
Save mwmwmw/617150a2d51e8e966c9359d14c4cab45 to your computer and use it in GitHub Desktop.
A basic line with distance collider. It's called a pill collider because of the pill shape it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Vector3, Object3D, BufferGeometry, Math as M, Group, LineBasicMaterial, Line, Line3, CylinderBufferGeometry, BufferAttribute, SphereBufferGeometry } from "three"; | |
export function Pill(start, end, radius) { | |
Object3D.call(this); | |
this.radius = radius; | |
this.type = "Pill"; | |
this._start = start; | |
this._end = end; | |
var geometry = new BufferGeometry(); | |
var line = new BufferGeometry(); | |
this.line = line; | |
this.geometry = geometry; | |
var vertices = new Float32Array([ | |
start.x, | |
start.y, | |
start.z, | |
end.x, | |
end.y, | |
end.z | |
]); | |
this.line.addAttribute("position", new BufferAttribute(vertices, 3)); | |
this.delta = function(target = new Vector3()) { | |
return target.copy(this.end).sub(this.start); | |
}; | |
Object.defineProperty(this, "start", { | |
get: function() { | |
var arr = line.attributes.position.array; | |
return this.localToWorld(this._start.set(arr[0], arr[1], arr[2])); | |
} | |
}); | |
Object.defineProperty(this, "end", { | |
get: function() { | |
var arr = line.attributes.position.array; | |
return this.localToWorld(this._end.set(arr[3], arr[4], arr[5])); | |
} | |
}); | |
} | |
Pill.prototype = Object.assign(Object.create(Object3D.prototype), { | |
constructor: Pill | |
}); | |
export function PillHelper(pill) { | |
Object3D.call(this); | |
this.type = "PillHelper"; | |
this.pill = pill; | |
var start = pill.start; | |
var end = pill.end; | |
var radius = pill.radius; | |
var cylinder = new CylinderBufferGeometry( radius, radius, start.distanceTo(end), 8,1, false ); | |
var sphere = new SphereBufferGeometry( radius, 8, 4 ); | |
var sphere2 = new SphereBufferGeometry( radius, 8, 4 ); | |
sphere.translate(0,-start.distanceTo(end)*0.5,0); | |
sphere2.translate(0,start.distanceTo(end)*0.5,0); | |
this.material = new LineBasicMaterial({ color: Math.random() * 0xffffff }); | |
var l3 = new Line3(start, end); | |
var center = l3.getCenter(new Vector3()) | |
this.group = new Group(); | |
this.group.add(new Line(sphere, this.material)); | |
this.group.add(new Line(sphere2, this.material)); | |
this.group.add(new Line(cylinder, this.material)); | |
this.group.position.copy(center); | |
this.group.lookAt(start); | |
this.group.rotateX(M.degToRad(90)) | |
this.add(this.group) | |
this.update = function () { | |
this.position.copy(this.pill.position); | |
this.rotation.copy(this.pill.rotation); | |
this.scale.copy(this.pill.scale) | |
} | |
this.update(); | |
} | |
PillHelper.prototype = Object.assign(Object.create(Object3D.prototype), { | |
constructor: PillHelper | |
}); | |
function clamp(n = 0, min = 0, max = 1) { | |
if (n < min) return min; | |
if (n > max) return max; | |
return n; | |
} | |
export function testPill(pill1, pill2, c1 = new Vector3(), c2 = new Vector3()) { | |
var dist = closestPoint(pill1, pill2, c1, c2); | |
var radius = pill1.radius + pill2.radius; | |
//console.log(dist, radius * radius); | |
return dist <= radius * radius; | |
} | |
var d1a = new Vector3(); | |
var d2a = new Vector3(); | |
export function closestPoint(line1, line2, c1 = new Vector3(), c2 = new Vector3()) { | |
var d1 = line1.delta(d1a); | |
var d2 = line2.delta(d2a); | |
var r = line1.start.clone().sub(line2.start); | |
var a = d1.dot(d1); | |
var e = d2.dot(d2); | |
var f = d2.dot(r); | |
var s = 0; | |
var t = 0; | |
if (a <= Number.EPSILON && e <= Number.EPSILON) { | |
var s = 0; | |
var t = 0; | |
c1.copy(line1.start); | |
c2.copy(line2.start); | |
var dist = c1.clone().sub(c2); | |
return dist.dot(dist); | |
} | |
if (a <= Number.EPSILON) { | |
s = 0; | |
t = f / e; | |
t = clamp(t); | |
} else { | |
var c = d1.clone().dot(r); | |
if (e <= Number.EPSILON) { | |
t = 0; | |
s = clamp(-c / a); | |
} else { | |
var b = d1.clone().dot(d2); | |
var denom = a * e - b * b; | |
if (denom != 0) { | |
s = clamp((b * f - c * e) / denom); | |
} else { | |
s = 0; | |
} | |
t = (b * s + f) / e; | |
if (t < 0) { | |
t = 0; | |
s = clamp(-c / a); | |
} else if (t > 1) { | |
t = 1; | |
s = clamp((b - c) / a); | |
} | |
} | |
} | |
c1.copy(line1.start.clone().add(d1.multiplyScalar(s))); | |
c2.copy(line2.start.clone().add(d2.multiplyScalar(t))); | |
var dist = c1.clone().sub(c2); | |
return dist.dot(dist); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment