ray-aabb-intersection
56 |57 | Determine the point of intersection between a ray and axis-aligned bounding box (AABB). Theoretically works in an arbitrary number of dimensions! 58 |
59 |60 | 61 | Check it out on GitHub 62 | 63 |
64 |├── .gitignore ├── .npmignore ├── index.js ├── LICENSE.md ├── package.json ├── bench.js ├── demo.js ├── README.md └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | test 7 | test.js 8 | demo/ 9 | .npmignore 10 | LICENSE.md -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = intersection 2 | module.exports.distance = distance 3 | 4 | function intersection (out, ro, rd, aabb) { 5 | var d = distance(ro, rd, aabb) 6 | if (d === Infinity) { 7 | out = null 8 | } else { 9 | out = out || [] 10 | for (var i = 0; i < ro.length; i++) { 11 | out[i] = ro[i] + rd[i] * d 12 | } 13 | } 14 | 15 | return out 16 | } 17 | 18 | function distance (ro, rd, aabb) { 19 | var dims = ro.length 20 | var lo = -Infinity 21 | var hi = +Infinity 22 | 23 | for (var i = 0; i < dims; i++) { 24 | var dimLo = (aabb[0][i] - ro[i]) / rd[i] 25 | var dimHi = (aabb[1][i] - ro[i]) / rd[i] 26 | 27 | if (dimLo > dimHi) { 28 | var tmp = dimLo 29 | dimLo = dimHi 30 | dimHi = tmp 31 | } 32 | 33 | if (dimHi < lo || dimLo > hi) { 34 | return Infinity 35 | } 36 | 37 | if (dimLo > lo) lo = dimLo 38 | if (dimHi < hi) hi = dimHi 39 | } 40 | 41 | return lo > hi ? Infinity : lo 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Hugh Kennedy 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ray-aabb-intersection", 3 | "version": "1.0.1", 4 | "description": "Determine the point of intersection between a ray and axis-aligned bounding box (AABB)", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Hugh Kennedy", 9 | "email": "hughskennedy@gmail.com", 10 | "url": "https://github.com/hughsk" 11 | }, 12 | "dependencies": {}, 13 | "devDependencies": { 14 | "benchmark": "^1.0.0", 15 | "browserify": "^11.2.0", 16 | "budo": "^5.1.0", 17 | "canvas-fit": "^1.5.0", 18 | "garnish": "^3.2.1", 19 | "gl-vec3": "^1.0.3", 20 | "raf": "^3.1.0", 21 | "standard": "^5.3.1", 22 | "touch-position": "^1.0.3" 23 | }, 24 | "scripts": { 25 | "bench": "node bench", 26 | "start": "budo demo.js:bundle.js | garnish", 27 | "bundle": "browserify demo.js -o bundle.js", 28 | "test": "standard index.js demo.js" 29 | }, 30 | "keywords": [ 31 | "aabb,", 32 | "axis,", 33 | "aligned,", 34 | "bounding,", 35 | "box,", 36 | "cube,", 37 | "ray,", 38 | "line,", 39 | "collision,", 40 | "intersection", 41 | "ecosystem:stackgl" 42 | ], 43 | "repository": { 44 | "type": "git", 45 | "url": "git://github.com/stackgl/ray-aabb-intersection.git" 46 | }, 47 | "homepage": "https://github.com/stackgl/ray-aabb-intersection", 48 | "bugs": { 49 | "url": "https://github.com/stackgl/ray-aabb-intersection/issues" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /bench.js: -------------------------------------------------------------------------------- 1 | const intersect = require('./') 2 | const Suite = require('benchmark').Suite 3 | 4 | const suite = new Suite() 5 | const tests = [ 6 | { 7 | name: 'x axis 3d', 8 | aabb: [[-1, -1, -1], [+1, +1, +1]], 9 | ro: [-2, 0, 0], 10 | rd: [+1, 0, 0] 11 | }, 12 | { 13 | name: 'y axis 3d', 14 | aabb: [[-1, -1, -1], [+1, +1, +1]], 15 | ro: [0, -2, 0], 16 | rd: [0, +1, 0] 17 | }, 18 | { 19 | name: 'z axis 3d', 20 | aabb: [[-1, -1, -1], [+1, +1, +1]], 21 | ro: [0, 0, -2], 22 | rd: [0, 0, +1] 23 | }, 24 | { 25 | name: 'miss 3d', 26 | aabb: [[-1, -1, -1], [+1, +1, +1]], 27 | ro: [0, 0, -2], 28 | rd: [0, 0, -1] 29 | } 30 | ] 31 | 32 | tests.forEach(function (params) { 33 | const out = new Float32Array(3) 34 | const aabb = params.aabb 35 | const rd = params.rd 36 | const ro = params.ro 37 | 38 | suite.add(params.name + ' (distance)', function () { 39 | intersect.distance(ro, rd, aabb) 40 | }) 41 | 42 | suite.add(params.name + ' (distance + calc)', function () { 43 | const d = intersect.distance(ro, rd, aabb) 44 | out[0] = ro[0] + d * rd[0] 45 | out[1] = ro[1] + d * rd[1] 46 | out[2] = ro[2] + d * rd[2] 47 | }) 48 | 49 | suite.add(params.name + ' (out)', function () { 50 | intersect(out, ro, rd, aabb) 51 | }) 52 | }) 53 | 54 | suite.on('cycle', function (event) { 55 | console.log(String(event.target)) 56 | }) 57 | 58 | suite.on('complete', function () { 59 | console.log('Fastest is ' + this.filter('fastest').pluck('name')) 60 | }) 61 | 62 | suite.run() 63 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | const canvas = document.body.appendChild(document.createElement('canvas')) 2 | const cursor = require('touch-position')(canvas) 3 | const normalize = require('gl-vec3/normalize') 4 | const ctx = canvas.getContext('2d') 5 | const intersection = require('./') 6 | const raf = require('raf') 7 | 8 | const aabb = [ 9 | [-1, -1], 10 | [+1, +1] 11 | ] 12 | 13 | render() 14 | function render () { 15 | raf(render) 16 | 17 | const width = canvas.width 18 | const height = canvas.height 19 | const scale = 15 20 | const o = [ 21 | 5 * Math.cos(Date.now() / 768), 22 | 5 * Math.sin(Date.now() / 368) 23 | ] 24 | 25 | ctx.fillStyle = '#f00' 26 | ctx.fillRect(0, 0, width, height) 27 | 28 | ctx.save() 29 | ctx.translate(width / 2, height / 2) 30 | ctx.scale(15, 15) 31 | 32 | aabb[0][0] = (Math.sin(Date.now() / 1000) - 2) * 2 33 | aabb[0][1] = (Math.sin(Date.now() / 1000) - 2) * 2 34 | aabb[1][0] = -aabb[0][0] 35 | aabb[1][1] = -aabb[0][1] 36 | aabb[0][0] += o[0] 37 | aabb[0][1] += o[1] 38 | aabb[1][0] += o[0] 39 | aabb[1][1] += o[1] 40 | 41 | const t = [ 42 | Math.abs(aabb[0][0] - aabb[1][0]), 43 | Math.abs(aabb[0][1] - aabb[1][1]) 44 | ] 45 | 46 | ctx.fillStyle = '#000' 47 | ctx.fillRect( 48 | aabb[0][0], 49 | aabb[0][1], 50 | t[0], t[1] 51 | ) 52 | 53 | var x = (cursor[0] - width / 2) / scale 54 | var y = (cursor[1] - height / 2) / scale 55 | 56 | ctx.fillStyle = '#ff0' 57 | ctx.fillRect(x - 0.5, y - 0.5, 1, 1) 58 | 59 | var ro = [x, y] 60 | var rd = normalize([-x, -y], []) 61 | 62 | var d = intersection.distance(ro, rd, aabb) 63 | if (d === Infinity) d = 100 64 | 65 | ctx.strokeStyle = '#ff0' 66 | ctx.lineWidth = 0.2 67 | ctx.beginPath() 68 | ctx.moveTo(ro[0], ro[1]) 69 | ctx.lineTo(ro[0] += d * rd[0], ro[1] += d * rd[1]) 70 | ctx.stroke() 71 | 72 | ctx.fillRect(ro[0] - 0.25, ro[1] - 0.25, 0.5, 0.5) 73 | 74 | ctx.restore() 75 | } 76 | 77 | window.addEventListener('resize' 78 | , require('canvas-fit')(canvas) 79 | , false 80 | ) 81 | 82 | canvas.addEventListener('touchstart', function (ev) { 83 | ev.preventDefault() 84 | }) 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ray-aabb-intersection 2 | 3 | [](http://github.com/badges/stability-badges) 4 | 5 | Determine the point of intersection between a ray and axis-aligned bounding box (AABB). Theoretically works in an arbitrary number of dimensions! 6 | 7 | Many thanks to [**@BSVino**](http://github.com/BSVino) for providing the [original C++ implementation](https://github.com/BSVino/MathForGameDevelopers/blob/line-box-intersection/math/collision.cpp) and [accompanying](https://www.youtube.com/watch?v=USjbg5QXk3g) [videos](https://www.youtube.com/watch?v=3vONlLYtHUE). 8 | 9 | [**view demo**](http://stack.gl/ray-aabb-intersection/) 10 | 11 | ## Usage 12 | 13 | [](https://www.npmjs.com/package/ray-aabb-intersection) 14 | 15 | ### `out = intersection(out, origin, dir, aabb)` 16 | 17 | Determines if the given ray `(origin, direction)` intersects with the `aabb`. 18 | 19 | If no intersection occurs, returns `null`. Otherwise, the intersection point is stored in `out` and then returned. 20 | 21 | ``` javascript 22 | const origin = new Float32Array([0, 4, 0]) 23 | const dir = new Float32Array([0, 1, 0]) 24 | const out = new Float32Array(3) 25 | 26 | const aabb = [ 27 | [-1, -1, -1], 28 | [+1, +1, +1] 29 | ] 30 | 31 | intersection(out, origin, dir, aabb) 32 | ``` 33 | 34 | ### `d = intersection.distance(origin, dir, aabb)` 35 | 36 | Returns the distance from the given ray `(origin, direction)` to the supplied `aabb`. If no intersection occurs, returns `Infinity`. 37 | 38 | Note that the `direction` vector should be normalized. 39 | 40 | ## See Also 41 | 42 | * [ray-aabb](http://github.com/tmpvar/ray-aabb) 43 | * [ray-sphere-intersection](http://github.com/mattdesl/ray-sphere-intersection) 44 | * [ray-plane-intersection](http://github.com/mattdesl/ray-plane-intersection) 45 | * [ray-triangle-intersection](http://github.com/substack/ray-triangle-intersection) 46 | * [camera-picking-ray](https://github.com/Jam3/camera-picking-ray) 47 | 48 | ## License 49 | 50 | MIT, see [LICENSE.md](http://github.com/stackgl/ray-aabb-intersection/blob/master/LICENSE.md) for details. 51 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |57 | Determine the point of intersection between a ray and axis-aligned bounding box (AABB). Theoretically works in an arbitrary number of dimensions! 58 |
59 |60 | 61 | Check it out on GitHub 62 | 63 |
64 |