Skip to content

Commit

Permalink
[#795] Fix bug in raycasting (#824)
Browse files Browse the repository at this point in the history
Closes #795 

## Changes:

- Fix raycast bug
- Add test for raycast demonstrating bug
- Rewrite raycasts to be slightly more efficient by avoiding branching
- Add a new method to calculate time to impact in raycasts
  • Loading branch information
eonarheim authored and kamranayub committed Jun 6, 2017
1 parent 7396103 commit 38452d8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 13 deletions.
49 changes: 36 additions & 13 deletions src/engine/Collision/BoundingBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,23 +120,46 @@ export class BoundingBox implements ICollidable {
var tmin = -Infinity;
var tmax = +Infinity;

if (ray.dir.x !== 0) {
var tx1 = (this.left - ray.pos.x) / ray.dir.x;
var tx2 = (this.right - ray.pos.x) / ray.dir.x;
tmin = Math.max(tmin, Math.min(tx1, tx2));
tmax = Math.min(tmax, Math.max(tx1, tx2));
}

if (ray.dir.y !== 0) {
var ty1 = (this.top - ray.pos.y) / ray.dir.y;
var ty2 = (this.bottom - ray.pos.y) / ray.dir.y;
tmin = Math.max(tmin, Math.min(ty1, ty2));
tmax = Math.min(tmax, Math.max(ty1, ty2));
}
var xinv = ray.dir.x === 0 ? Number.MAX_VALUE : (1 / ray.dir.x);
var yinv = ray.dir.y === 0 ? Number.MAX_VALUE : (1 / ray.dir.y);

var tx1 = (this.left - ray.pos.x) * xinv;
var tx2 = (this.right - ray.pos.x) * xinv;
tmin = Math.min(tx1, tx2);
tmax = Math.max(tx1, tx2);

var ty1 = (this.top - ray.pos.y) * yinv;
var ty2 = (this.bottom - ray.pos.y) * yinv;
tmin = Math.max(tmin, Math.min(ty1, ty2));
tmax = Math.min(tmax, Math.max(ty1, ty2));

return tmax >= Math.max(0, tmin) && tmin < farClipDistance;
}

public rayCastTime(ray: Ray, farClipDistance = Infinity): number {
// algorithm from https://tavianator.com/fast-branchless-raybounding-box-intersections/
var tmin = -Infinity;
var tmax = +Infinity;

var xinv = ray.dir.x === 0 ? Number.MAX_VALUE : (1 / ray.dir.x);
var yinv = ray.dir.y === 0 ? Number.MAX_VALUE : (1 / ray.dir.y);

var tx1 = (this.left - ray.pos.x) * xinv;
var tx2 = (this.right - ray.pos.x) * xinv;
tmin = Math.min(tx1, tx2);
tmax = Math.max(tx1, tx2);

var ty1 = (this.top - ray.pos.y) * yinv;
var ty2 = (this.bottom - ray.pos.y) * yinv;
tmin = Math.max(tmin, Math.min(ty1, ty2));
tmax = Math.min(tmax, Math.max(ty1, ty2));

if (tmax >= Math.max(0, tmin) && tmin < farClipDistance) {
return tmin;
}
return -1;
}

/**
* Tests whether a point is contained within the bounding box
* @param p The point to test
Expand Down
7 changes: 7 additions & 0 deletions src/spec/BoundingBoxSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ describe('A Bounding Box', () => {
expect(bb.rayCast(ray)).toBe(false);
});

it('ray cast can miss a box far away', () => {
var bb = new ex.BoundingBox(1176, 48, 1200, 72);

var ray = new ex.Ray(new ex.Vector(48, 72), ex.Vector.Down);
expect(bb.rayCast(ray)).toBe(false);
});

it('ray cast can hit bounding box on the edge', () => {
var bb = new ex.BoundingBox(0, 0, 10, 10);

Expand Down

0 comments on commit 38452d8

Please sign in to comment.