├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── index.js ├── package.json └── test.js /.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 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Jam3 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # camera-project 2 | 3 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 4 | 5 | Projects a 3D world point into 2D window space. 6 | 7 | ```js 8 | var mat4 = require('gl-mat4') 9 | var project = require('camera-project') 10 | 11 | //projection * view matrix 12 | var combinedProjView = mat4.multiply([], projection, view) 13 | 14 | //viewport bounds 15 | var viewport = [x, y, width, height] 16 | 17 | //3D world point 18 | var point = [0, -1, 2.5] 19 | 20 | //vec4 output 21 | var output = [] 22 | 23 | project(output, point, viewport, combinedProjView) 24 | ``` 25 | 26 | The output `z` component contains the window space depth, and `w` is the value of `(1 / clip.w)`. Assumes [depth range](https://www.opengl.org/wiki/GLAPI/glDepthRange) is 0 to 1. 27 | 28 | ## Usage 29 | 30 | [![NPM](https://nodei.co/npm/camera-project.png)](https://www.npmjs.com/package/camera-project) 31 | 32 | #### `vec4 = project(out, point, viewport, combined)` 33 | 34 | Projects the 3D `point` into window space using the `viewport` bounds (screen x, y, width, height) and `combined` matrix (result of multiplying `projection * view` matrices). 35 | 36 | The result is stored in `out` and returned. 37 | 38 | ## See Also 39 | 40 | - [camera-unproject](https://www.npmjs.com/package/camera-unproject) 41 | 42 | ## License 43 | 44 | MIT, see [LICENSE.md](http://github.com/Jam3/camera-project/blob/master/LICENSE.md) for details. 45 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var transformMat4 = require('gl-vec4/transformMat4') 2 | var set = require('gl-vec4/set') 3 | 4 | var NEAR_RANGE = 0 5 | var FAR_RANGE = 1 6 | var tmp4 = [0, 0, 0, 0] 7 | 8 | module.exports = cameraProject 9 | function cameraProject (out, vec, viewport, combinedProjView) { 10 | var vX = viewport[0], 11 | vY = viewport[1], 12 | vWidth = viewport[2], 13 | vHeight = viewport[3], 14 | n = NEAR_RANGE, 15 | f = FAR_RANGE 16 | 17 | // convert: clip space -> NDC -> window coords 18 | // implicit 1.0 for w component 19 | set(tmp4, vec[0], vec[1], vec[2], 1.0) 20 | 21 | // transform into clip space 22 | transformMat4(tmp4, tmp4, combinedProjView) 23 | 24 | // now transform into NDC 25 | var w = tmp4[3] 26 | if (w !== 0) { // how to handle infinity here? 27 | tmp4[0] = tmp4[0] / w 28 | tmp4[1] = tmp4[1] / w 29 | tmp4[2] = tmp4[2] / w 30 | } 31 | 32 | // and finally into window coordinates 33 | // the foruth component is (1/clip.w) 34 | // which is the same as gl_FragCoord.w 35 | out[0] = vX + vWidth / 2 * tmp4[0] + (0 + vWidth / 2) 36 | out[1] = vY + vHeight / 2 * tmp4[1] + (0 + vHeight / 2) 37 | out[2] = (f - n) / 2 * tmp4[2] + (f + n) / 2 38 | out[3] = w === 0 ? 0 : 1 / w 39 | return out 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "camera-project", 3 | "version": "1.0.2", 4 | "description": "project 3D point into 2D window space", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Matt DesLauriers", 9 | "email": "dave.des@gmail.com", 10 | "url": "https://github.com/mattdesl" 11 | }, 12 | "dependencies": { 13 | "gl-vec4": "^1.0.1" 14 | }, 15 | "devDependencies": { 16 | "gl-mat4": "^1.1.3", 17 | "gl-vec3": "^1.0.3", 18 | "standard": "^3.8.0", 19 | "tape": "^4.0.0" 20 | }, 21 | "scripts": { 22 | "test": "standard && node test.js" 23 | }, 24 | "keywords": [ 25 | "project", 26 | "projection", 27 | "camera", 28 | "cameras", 29 | "view", 30 | "matrix", 31 | "projection", 32 | "matrices", 33 | "unproject", 34 | "mouse", 35 | "pick", 36 | "ray", 37 | "2d", 38 | "3d", 39 | "views", 40 | "window", 41 | "space", 42 | "ndc", 43 | "clip", 44 | "coordinates" 45 | ], 46 | "repository": { 47 | "type": "git", 48 | "url": "git://github.com/Jam3/camera-project.git" 49 | }, 50 | "homepage": "https://github.com/Jam3/camera-project", 51 | "bugs": { 52 | "url": "https://github.com/Jam3/camera-project/issues" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var project = require('./') 2 | var test = require('tape') 3 | 4 | var mat4 = require('gl-mat4') 5 | var vec3 = require('gl-vec3') 6 | 7 | // Needs some more tests! 8 | test('project 3D point into 2D window space', function (t) { 9 | var viewport = [0, 0, 128, 256] 10 | 11 | var proj = mat4.create() 12 | var view = mat4.create() 13 | var position = [0, 0, -3] 14 | var direction = [0, 0, -1] 15 | var up = [0, 1, 0] 16 | var center = [0, 0, 0] 17 | 18 | mat4.perspective(proj, Math.PI / 4, viewport[2] / viewport[3], 0.01, 100) 19 | 20 | // build view matrix 21 | vec3.add(center, position, direction) 22 | mat4.lookAt(view, position, center, up) 23 | 24 | var combined = mat4.multiply([], proj, view) 25 | 26 | var point3d = [0, 0, 5] 27 | var out = project([], point3d, viewport, combined) 28 | t.equal(out[0], viewport[2] / 2, 'x position') 29 | t.equal(out[1], viewport[3] / 2, 'y position') 30 | t.end() 31 | }) 32 | --------------------------------------------------------------------------------