├── .github ├── labels.json └── workflows │ └── set-default-labels.yml ├── README.md └── webvr ├── README.md ├── aframe-demo ├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── metal003.png └── package.json ├── basic-display-info └── index.html ├── field-of-view-test └── index.html ├── raw-webgl-controller-example ├── cubetexture.png ├── glUtils.js ├── index.html ├── metal003.png ├── sylvester.js ├── webgl-demo.js └── webgl.css ├── raw-webgl-example ├── cubetexture.png ├── glUtils.js ├── index.html ├── metal003.png ├── sylvester.js ├── webgl-demo.js └── webgl.css ├── stage-parameters-test └── index.html └── vr-controller-basic-info └── index.html /.github/labels.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "good first issue", 4 | "color": "028c46", 5 | "description": "A good issue for newcomers to get started with." 6 | }, 7 | { 8 | "name": "help wanted", 9 | "color": "028c46", 10 | "description": "If you know something about this, we would love your help!" 11 | }, 12 | { 13 | "name": "needs info", 14 | "color": "028c46", 15 | "description": "This needs more information to review or act on." 16 | }, 17 | { 18 | "name": "needs triage", 19 | "color": "028c46", 20 | "description": "Triage needed by staff and/or partners. Automatically applied when an issue is opened." 21 | }, 22 | { 23 | "name": "expert help needed", 24 | "color": "028c46", 25 | "description": "This needs more information from a subject matter expert (SME)." 26 | }, 27 | { 28 | "name": "idle", 29 | "color": "028c46", 30 | "description": "Issues and pull requests with no activity for three months." 31 | }, 32 | { 33 | "name": "on hold", 34 | "color": "028c46", 35 | "description": "Waiting on something else before this can be moved forward." 36 | }, 37 | { 38 | "name": "for later", 39 | "color": "028c46", 40 | "description": "Not planned at this time." 41 | }, 42 | { 43 | "name": "needs content update", 44 | "color": "028c46", 45 | "description": "Needs update to the content to support this change." 46 | }, 47 | { 48 | "name": "chore", 49 | "color": "028c46", 50 | "description": "A routine task." 51 | }, 52 | { 53 | "name": "enhancement", 54 | "color": "028c46", 55 | "description": "Improves an existing feature." 56 | }, 57 | { 58 | "name": "bug", 59 | "color": "c05964", 60 | "description": "Indicates an unexpected problem or unintended behavior." 61 | }, 62 | { 63 | "name": "wontfix", 64 | "color": "c05964", 65 | "description": "Deemed to be outside the scope of the project or would require significant time and resources to fix." 66 | }, 67 | { 68 | "name": "effort: small", 69 | "color": "866dc1", 70 | "description": "Task is a small effort." 71 | }, 72 | { 73 | "name": "effort: medium", 74 | "color": "866dc1", 75 | "description": "Task is a medium effort." 76 | }, 77 | { 78 | "name": "effort: large", 79 | "color": "866dc1", 80 | "description": "Task is large effort." 81 | }, 82 | { 83 | "name": "p0", 84 | "color": "6e8bc1", 85 | "description": "Urgent. We will address this as soon as possible." 86 | }, 87 | { 88 | "name": "p1", 89 | "color": "6e8bc1", 90 | "description": "We will address this soon and will provide capacity from our team for it in the next few releases." 91 | }, 92 | { 93 | "name": "p2", 94 | "color": "6e8bc1", 95 | "description": "We want to address this but may have other higher priority items." 96 | }, 97 | { 98 | "name": "p3", 99 | "color": "6e8bc1", 100 | "description": "We don't have visibility when this will be addressed." 101 | } 102 | ] 103 | -------------------------------------------------------------------------------- /.github/workflows/set-default-labels.yml: -------------------------------------------------------------------------------- 1 | name: set-default-labels 2 | on: [workflow_dispatch] 3 | 4 | jobs: 5 | set-default-labels: 6 | uses: mdn/workflows/.github/workflows/set-default-labels.yml@main 7 | with: 8 | target-repo: "mdn/webvr-tests" 9 | should-delete-labels: true 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webvr-tests 2 | 3 | > **NOTE** The API in this repository has been deprecated. We will archive this repository on March, 2024. 4 | 5 | A set of simple tests for testing WebVR functionality. See https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API for the latest on the documentation. 6 | -------------------------------------------------------------------------------- /webvr/README.md: -------------------------------------------------------------------------------- 1 | # webvr-tests 2 | Simple tests for testing WebVR functionality. See [https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API](https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API) for the latest on the documentation. 3 | 4 | The tests are as follows: 5 | 6 | * [basic-display-info](https://mdn.github.io/webvr-tests/basic-display-info/) — Demo that detects all VRDisplays connected to the computer and displays all their basic capabilities. 7 | * [field-of-view-test](https://mdn.github.io/webvr-tests/field-of-view-test/) — Demo that detects the first VRDisplay connected to the computer and displays its field of view information. 8 | * [stage-parameters-test](https://mdn.github.io/webvr-tests/stage-parameters-test/) — Demo that detects the first VRDisplay connected to the computer and displays its stage parameterss. 9 | * [raw-webgl-example](https://mdn.github.io/webvr-tests/raw-webgl-example/) — A quick 'n' dirty example that shows the basics of how to use the WebVR API. 10 | * [vr-controller-basic-info](https://mdn.github.io/webvr-tests/vr-controller-basic-info/) — Demo that detects and outputs information about VRDisplays and associated controllers connected to your computer. 11 | * [raw-webgl-controller-example](https://mdn.github.io/webvr-tests/raw-webgl-controller-example/) — A quick 'n' dirty example that shows the basics of how to use the WebVR API along with the Gamepad API to control objects in 3D space. 12 | * [aframe-demo](https://mdn.github.io/webvr-tests/aframe-demo/) — A simple WebVR demo that uses [Mozilla's A-Frame](https://aframe.io/) framework to create a scene. 13 | -------------------------------------------------------------------------------- /webvr/aframe-demo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sw[mnop] 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules 35 | jspm_packages 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | -------------------------------------------------------------------------------- /webvr/aframe-demo/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2015 A-Frame. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /webvr/aframe-demo/README.md: -------------------------------------------------------------------------------- 1 | # A-Frame Boilerplate 2 | 3 | Boilerplate for creating WebVR scenes with [A-Frame](https://aframe.io). 4 | 5 | Alternatively, check out the [A-Frame Starter on 6 | glitch.com](https://glitch.com/~aframe) for a more interactive way on getting 7 | started. 8 | 9 | ## Getting Started 10 | 11 | There are two easy options for obtaining this A-Frame scene. It's then up to you to make it your own! 12 | 13 | ### Option 1: Download the ZIP kit 📦 14 | 15 | [](https://github.com/aframevr/aframe-boilerplate/archive/master.zip) 16 | 17 | After you have __[downloaded and extracted this `.zip` file](https://github.com/aframevr/aframe-boilerplate/archive/master.zip)__ containing the contents of this repo, open the resulting directory, and you'll be have your scene ready in these few steps: 18 | 19 | npm install && npm start 20 | open http://localhost:3000/ 21 | 22 |
23 | 24 | ### Option 2: Fork this Git repo 🍴🐙 25 | 26 | Alternatively, you can __[fork this repo](https://github.com/aframevr/aframe-boilerplate/fork)__ to get started, if you'd like to maintain a Git workflow. 27 | 28 | After you have __[forked this repo](https://github.com/aframevr/aframe-boilerplate/fork)__, clone a copy of your fork locally and you'll be have your scene ready in these few steps: 29 | 30 | git clone https://github.com/aframevr/aframe-boilerplate.git 31 | cd aframe-boilerplate && rm -rf .git && npm install && npm start 32 | open http://localhost:3000/ 33 | 34 | > :iphone: **Mobile pro tip:** Upon starting the development server, the URL will be logged to the console. Load that URL from a browser on your mobile device. (If your mobile phone and computer are not on the same LAN, consider using [ngrok](https://ngrok.com/) for local development and testing. [Browsersync](https://www.browsersync.io/) is also worth a gander.) 35 | 36 |
37 | 38 | ### Option 3: Fork this CodePen example 🍴💾✒️ 39 | 40 | Or, you can simply __[fork this CodePen example](http://codepen.io/team/mozvr/pen/BjygdO?editors=100)__ to dive right in. Enjoy! 41 | 42 | 43 | ## Publishing your scene 44 | 45 | If you don't already know, GitHub offers free and awesome publishing of static sites through __[https://pages.github.com/](GitHub Pages)__. 46 | 47 | To publish your scene to your personal GitHub Pages: 48 | 49 | npm run deploy 50 | 51 | And, it'll now be live at __http://`your_username`.github.io/__ :) 52 | 53 |
54 | 55 | To know which GitHub repo to deploy to, the `deploy` script first looks at the optional [`repository` key](https://docs.npmjs.com/files/package.json#repository) in the [`package.json` file](package.json) (see [npm docs](https://docs.npmjs.com/files/package.json#repository) for sample usage). If the `repository` key is missing, the script falls back to using the local git repo's remote origin URL (you can run the local command `git remote -v` to see all your remotes; also, you may refer to the [GitHub docs](https://help.github.com/articles/about-remote-repositories/) for more information). 56 | 57 |
58 | 59 | ## Still need Help? 60 | 61 | ### Installation 62 | 63 | First make sure you have Node installed. 64 | 65 | On Mac OS X, it's recommended to use [Homebrew](http://brew.sh/) to install Node + [npm](https://www.npmjs.com): 66 | 67 | brew install node 68 | 69 | To install the Node dependencies: 70 | 71 | npm install 72 | 73 | 74 | ### Local Development 75 | 76 | To serve the site from a simple Node development server: 77 | 78 | npm start 79 | 80 | Then launch the site from your favourite browser: 81 | 82 | [__http://localhost:3000/__](http://localhost:3000/) 83 | 84 | If you wish to serve the site from a different port: 85 | 86 | PORT=8000 npm start 87 | 88 | 89 | ## License 90 | 91 | This program is free software and is distributed under an [MIT License](LICENSE). 92 | -------------------------------------------------------------------------------- /webvr/aframe-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A-Frame demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /webvr/aframe-demo/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/webvr-tests/bb5c886e2c877211562bb360630d15ab56336155/webvr/aframe-demo/metal003.png -------------------------------------------------------------------------------- /webvr/aframe-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-hello-world-boilerplate", 3 | "description": "Boilerplate with A-Frame's 'Hello, World!' of WebVR.", 4 | "version": "0.3.0", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "budo --live --verbose --port 3000 --open", 8 | "deploy": "ghpages", 9 | "ghpages": "ghpages" 10 | }, 11 | "devDependencies": { 12 | "budo": "^7.0.0", 13 | "ghpages": "0.0.3" 14 | }, 15 | "keywords": [ 16 | "aframe", 17 | "aframe-example", 18 | "aframe-boilerplate", 19 | "aframe-scene", 20 | "webvr", 21 | "vr" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /webvr/basic-display-info/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRDisplay basic test 9 | 10 | 11 | 12 | 13 |

VRDisplay basic test

14 | 15 |

16 | 17 | 19 | 20 | 21 | 22 | 112 | 113 | -------------------------------------------------------------------------------- /webvr/field-of-view-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRFieldOfView basic test 9 | 10 | 11 | 12 | 13 |

VRFieldOfView basic test

14 | 15 |

16 | 17 | 19 | 20 | 21 | 22 | 70 | 71 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/cubetexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/webvr-tests/bb5c886e2c877211562bb360630d15ab56336155/webvr/raw-webgl-controller-example/cubetexture.png -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/glUtils.js: -------------------------------------------------------------------------------- 1 | // augment Sylvester some 2 | Matrix.Translation = function (v) 3 | { 4 | if (v.elements.length == 2) { 5 | var r = Matrix.I(3); 6 | r.elements[2][0] = v.elements[0]; 7 | r.elements[2][1] = v.elements[1]; 8 | return r; 9 | } 10 | 11 | if (v.elements.length == 3) { 12 | var r = Matrix.I(4); 13 | r.elements[0][3] = v.elements[0]; 14 | r.elements[1][3] = v.elements[1]; 15 | r.elements[2][3] = v.elements[2]; 16 | return r; 17 | } 18 | 19 | throw "Invalid length for Translation"; 20 | } 21 | 22 | Matrix.prototype.flatten = function () 23 | { 24 | var result = []; 25 | if (this.elements.length == 0) 26 | return []; 27 | 28 | 29 | for (var j = 0; j < this.elements[0].length; j++) 30 | for (var i = 0; i < this.elements.length; i++) 31 | result.push(this.elements[i][j]); 32 | return result; 33 | } 34 | 35 | Matrix.prototype.ensure4x4 = function() 36 | { 37 | if (this.elements.length == 4 && 38 | this.elements[0].length == 4) 39 | return this; 40 | 41 | if (this.elements.length > 4 || 42 | this.elements[0].length > 4) 43 | return null; 44 | 45 | for (var i = 0; i < this.elements.length; i++) { 46 | for (var j = this.elements[i].length; j < 4; j++) { 47 | if (i == j) 48 | this.elements[i].push(1); 49 | else 50 | this.elements[i].push(0); 51 | } 52 | } 53 | 54 | for (var i = this.elements.length; i < 4; i++) { 55 | if (i == 0) 56 | this.elements.push([1, 0, 0, 0]); 57 | else if (i == 1) 58 | this.elements.push([0, 1, 0, 0]); 59 | else if (i == 2) 60 | this.elements.push([0, 0, 1, 0]); 61 | else if (i == 3) 62 | this.elements.push([0, 0, 0, 1]); 63 | } 64 | 65 | return this; 66 | }; 67 | 68 | Matrix.prototype.make3x3 = function() 69 | { 70 | if (this.elements.length != 4 || 71 | this.elements[0].length != 4) 72 | return null; 73 | 74 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]], 75 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]], 76 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]); 77 | }; 78 | 79 | Vector.prototype.flatten = function () 80 | { 81 | return this.elements; 82 | }; 83 | 84 | function mht(m) { 85 | var s = ""; 86 | if (m.length == 16) { 87 | for (var i = 0; i < 4; i++) { 88 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
"; 89 | } 90 | } else if (m.length == 9) { 91 | for (var i = 0; i < 3; i++) { 92 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
"; 93 | } 94 | } else { 95 | return m.toString(); 96 | } 97 | return s; 98 | } 99 | 100 | // 101 | // gluLookAt 102 | // 103 | function makeLookAt(ex, ey, ez, 104 | cx, cy, cz, 105 | ux, uy, uz) 106 | { 107 | var eye = $V([ex, ey, ez]); 108 | var center = $V([cx, cy, cz]); 109 | var up = $V([ux, uy, uz]); 110 | 111 | var mag; 112 | 113 | var z = eye.subtract(center).toUnitVector(); 114 | var x = up.cross(z).toUnitVector(); 115 | var y = z.cross(x).toUnitVector(); 116 | 117 | var m = $M([[x.e(1), x.e(2), x.e(3), 0], 118 | [y.e(1), y.e(2), y.e(3), 0], 119 | [z.e(1), z.e(2), z.e(3), 0], 120 | [0, 0, 0, 1]]); 121 | 122 | var t = $M([[1, 0, 0, -ex], 123 | [0, 1, 0, -ey], 124 | [0, 0, 1, -ez], 125 | [0, 0, 0, 1]]); 126 | return m.x(t); 127 | } 128 | 129 | // 130 | // glOrtho 131 | // 132 | function makeOrtho(left, right, 133 | bottom, top, 134 | znear, zfar) 135 | { 136 | var tx = -(right+left)/(right-left); 137 | var ty = -(top+bottom)/(top-bottom); 138 | var tz = -(zfar+znear)/(zfar-znear); 139 | 140 | return $M([[2/(right-left), 0, 0, tx], 141 | [0, 2/(top-bottom), 0, ty], 142 | [0, 0, -2/(zfar-znear), tz], 143 | [0, 0, 0, 1]]); 144 | } 145 | 146 | // 147 | // gluPerspective 148 | // 149 | function makePerspective(fovy, aspect, znear, zfar) 150 | { 151 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 152 | var ymin = -ymax; 153 | var xmin = ymin * aspect; 154 | var xmax = ymax * aspect; 155 | 156 | return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); 157 | } 158 | 159 | // 160 | // glFrustum 161 | // 162 | function makeFrustum(left, right, 163 | bottom, top, 164 | znear, zfar) 165 | { 166 | var X = 2*znear/(right-left); 167 | var Y = 2*znear/(top-bottom); 168 | var A = (right+left)/(right-left); 169 | var B = (top+bottom)/(top-bottom); 170 | var C = -(zfar+znear)/(zfar-znear); 171 | var D = -2*zfar*znear/(zfar-znear); 172 | 173 | return $M([[X, 0, A, 0], 174 | [0, Y, B, 0], 175 | [0, 0, C, D], 176 | [0, 0, -1, 0]]); 177 | } 178 | 179 | // 180 | // glOrtho 181 | // 182 | function makeOrtho(left, right, bottom, top, znear, zfar) 183 | { 184 | var tx = - (right + left) / (right - left); 185 | var ty = - (top + bottom) / (top - bottom); 186 | var tz = - (zfar + znear) / (zfar - znear); 187 | 188 | return $M([[2 / (right - left), 0, 0, tx], 189 | [0, 2 / (top - bottom), 0, ty], 190 | [0, 0, -2 / (zfar - znear), tz], 191 | [0, 0, 0, 1]]); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Raw WebGL/WebVR Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | Your browser doesn't appear to support the <canvas> element. 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 | 46 | 47 | 48 | 49 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/webvr-tests/bb5c886e2c877211562bb360630d15ab56336155/webvr/raw-webgl-controller-example/metal003.png -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/sylvester.js: -------------------------------------------------------------------------------- 1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/webgl-demo.js: -------------------------------------------------------------------------------- 1 | var canvas; // The canvas element 2 | var gl; // The WebGL context 3 | 4 | var cubeVerticesBuffer; 5 | var cubeVerticesTextureCoordBuffer; 6 | var cubeVerticesIndexBuffer; 7 | var cubeVerticesIndexBuffer; 8 | var cubeRotation = 0.0; 9 | var lastCubeUpdateTime = 0; 10 | 11 | var cubeImage; 12 | var cubeTexture; 13 | 14 | var mvMatrix; 15 | var shaderProgram; // The WebGLProgram we will create, which will render the cube 16 | var vertexPositionAttribute; 17 | var textureCoordAttribute; 18 | var perspectiveMatrix; 19 | 20 | // WebVR variables 21 | 22 | var frameData = new VRFrameData(); 23 | var vrDisplay; 24 | var btn = document.querySelector('.stop-start'); 25 | var normalSceneFrame; 26 | var vrSceneFrame; 27 | 28 | var poseStatsBtn = document.querySelector('.pose-stats'); 29 | var poseStatsSection = document.querySelector('section'); 30 | poseStatsSection.style.visibility = 'hidden'; // hide it initially 31 | 32 | var posStats = document.querySelector('.pos'); 33 | var orientStats = document.querySelector('.orient'); 34 | var linVelStats = document.querySelector('.lin-vel'); 35 | var linAccStats = document.querySelector('.lin-acc'); 36 | var angVelStats = document.querySelector('.ang-vel'); 37 | var angAccStats = document.querySelector('.ang-acc'); 38 | var poseStatsDisplayed = false; 39 | 40 | // 41 | // start 42 | // 43 | // Called when the body has loaded is created to get the ball rolling. 44 | 45 | document.body.onload = start; 46 | 47 | function start() { 48 | canvas = document.getElementById("glcanvas"); 49 | 50 | initWebGL(canvas); // Initialize the GL context 51 | 52 | // Only continue if WebGL is available and working 53 | 54 | if (gl) { 55 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque 56 | gl.clearDepth(1.0); // Clear everything 57 | gl.enable(gl.DEPTH_TEST); // Enable depth testing 58 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things 59 | 60 | // Initialize the shaders; this is where all the lighting for the 61 | // vertices and so forth is established. 62 | 63 | initShaders(); 64 | 65 | // Here's where we call the routine that builds all the objects 66 | // we'll be drawing. 67 | 68 | initBuffers(); 69 | 70 | // Next, load and set up the textures we'll be using. 71 | 72 | initTextures(); 73 | 74 | // draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser 75 | 76 | canvas.width = window.innerWidth; 77 | canvas.height = window.innerHeight; 78 | drawScene(); 79 | 80 | // WebVR: Check to see if WebVR is supported 81 | if(navigator.getVRDisplays) { 82 | console.log('WebVR 1.1 supported'); 83 | // Then get the displays attached to the computer 84 | navigator.getVRDisplays().then(function(displays) { 85 | // If a display is available, use it to present the scene 86 | if(displays.length > 0) { 87 | vrDisplay = displays[0]; 88 | console.log('Display found'); 89 | // Starting the presentation when the button is clicked: It can only be called in response to a user gesture 90 | btn.addEventListener('click', function() { 91 | if(btn.textContent === 'Start VR display') { 92 | vrDisplay.requestPresent([{ source: canvas }]).then(function() { 93 | console.log('Presenting to WebVR display'); 94 | 95 | // Set the canvas size to the size of the vrDisplay viewport 96 | 97 | var leftEye = vrDisplay.getEyeParameters('left'); 98 | var rightEye = vrDisplay.getEyeParameters('right'); 99 | 100 | canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2; 101 | canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight); 102 | 103 | // stop the normal presentation, and start the vr presentation 104 | window.cancelAnimationFrame(normalSceneFrame); 105 | drawVRScene(); 106 | 107 | btn.textContent = 'Exit VR display'; 108 | }); 109 | } else { 110 | vrDisplay.exitPresent(); 111 | console.log('Stopped presenting to WebVR display'); 112 | 113 | btn.textContent = 'Start VR display'; 114 | 115 | // Stop the VR presentation, and start the normal presentation 116 | vrDisplay.cancelAnimationFrame(vrSceneFrame); 117 | drawScene(); 118 | } 119 | }); 120 | } 121 | }); 122 | } else { 123 | info.textContent = 'WebVR API not supported by this browser.'; 124 | } 125 | } 126 | } 127 | 128 | // 129 | // initWebGL 130 | // 131 | // Initialize WebGL, returning the GL context or null if 132 | // WebGL isn't available or could not be initialized. 133 | // 134 | function initWebGL() { 135 | gl = null; 136 | 137 | try { 138 | gl = canvas.getContext("experimental-webgl"); 139 | } 140 | catch(e) { 141 | } 142 | 143 | // If we don't have a GL context, give up now 144 | 145 | if (!gl) { 146 | alert("Unable to initialize WebGL. Your browser may not support it."); 147 | } 148 | } 149 | 150 | // 151 | // initBuffers 152 | // 153 | // Initialize the buffers we'll need. For this demo, we just have 154 | // one object -- a simple two-dimensional cube. 155 | // 156 | function initBuffers() { 157 | 158 | // Create a buffer for the cube's vertices. 159 | 160 | cubeVerticesBuffer = gl.createBuffer(); 161 | 162 | // Select the cubeVerticesBuffer as the one to apply vertex 163 | // operations to from here out. 164 | 165 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 166 | 167 | // Now create an array of vertices for the cube. 168 | 169 | var vertices = [ 170 | // Front face 171 | -1.0, -1.0, 1.0, 172 | 1.0, -1.0, 1.0, 173 | 1.0, 1.0, 1.0, 174 | -1.0, 1.0, 1.0, 175 | 176 | // Back face 177 | -1.0, -1.0, -1.0, 178 | -1.0, 1.0, -1.0, 179 | 1.0, 1.0, -1.0, 180 | 1.0, -1.0, -1.0, 181 | 182 | // Top face 183 | -1.0, 1.0, -1.0, 184 | -1.0, 1.0, 1.0, 185 | 1.0, 1.0, 1.0, 186 | 1.0, 1.0, -1.0, 187 | 188 | // Bottom face 189 | -1.0, -1.0, -1.0, 190 | 1.0, -1.0, -1.0, 191 | 1.0, -1.0, 1.0, 192 | -1.0, -1.0, 1.0, 193 | 194 | // Right face 195 | 1.0, -1.0, -1.0, 196 | 1.0, 1.0, -1.0, 197 | 1.0, 1.0, 1.0, 198 | 1.0, -1.0, 1.0, 199 | 200 | // Left face 201 | -1.0, -1.0, -1.0, 202 | -1.0, -1.0, 1.0, 203 | -1.0, 1.0, 1.0, 204 | -1.0, 1.0, -1.0 205 | ]; 206 | 207 | // Now pass the list of vertices into WebGL to build the shape. We 208 | // do this by creating a Float32Array from the JavaScript array, 209 | // then use it to fill the current vertex buffer. 210 | 211 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 212 | 213 | // Map the texture onto the cube's faces. 214 | 215 | cubeVerticesTextureCoordBuffer = gl.createBuffer(); 216 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 217 | 218 | var textureCoordinates = [ 219 | // Front 220 | 0.0, 0.0, 221 | 1.0, 0.0, 222 | 1.0, 1.0, 223 | 0.0, 1.0, 224 | // Back 225 | 0.0, 0.0, 226 | 1.0, 0.0, 227 | 1.0, 1.0, 228 | 0.0, 1.0, 229 | // Top 230 | 0.0, 0.0, 231 | 1.0, 0.0, 232 | 1.0, 1.0, 233 | 0.0, 1.0, 234 | // Bottom 235 | 0.0, 0.0, 236 | 1.0, 0.0, 237 | 1.0, 1.0, 238 | 0.0, 1.0, 239 | // Right 240 | 0.0, 0.0, 241 | 1.0, 0.0, 242 | 1.0, 1.0, 243 | 0.0, 1.0, 244 | // Left 245 | 0.0, 0.0, 246 | 1.0, 0.0, 247 | 1.0, 1.0, 248 | 0.0, 1.0 249 | ]; 250 | 251 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), 252 | gl.STATIC_DRAW); 253 | 254 | // Build the element array buffer; this specifies the indices 255 | // into the vertex array for each face's vertices. 256 | 257 | cubeVerticesIndexBuffer = gl.createBuffer(); 258 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 259 | 260 | // This array defines each face as two triangles, using the 261 | // indices into the vertex array to specify each triangle's 262 | // position. 263 | 264 | var cubeVertexIndices = [ 265 | 0, 1, 2, 0, 2, 3, // front 266 | 4, 5, 6, 4, 6, 7, // back 267 | 8, 9, 10, 8, 10, 11, // top 268 | 12, 13, 14, 12, 14, 15, // bottom 269 | 16, 17, 18, 16, 18, 19, // right 270 | 20, 21, 22, 20, 22, 23 // left 271 | ]; 272 | 273 | // Now send the element array to GL 274 | 275 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 276 | new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 277 | } 278 | 279 | // 280 | // initTextures 281 | // 282 | // Initialize the textures we'll be using, then initiate a load of 283 | // the texture images. The handleTextureLoaded() callback will finish 284 | // the job; it gets called each time a texture finishes loading. 285 | // 286 | function initTextures() { 287 | cubeTexture = gl.createTexture(); 288 | cubeImage = new Image(); 289 | cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }; 290 | cubeImage.src = "metal003.png"; 291 | } 292 | 293 | function handleTextureLoaded(image, texture) { 294 | console.log("handleTextureLoaded, image = " + image); 295 | gl.bindTexture(gl.TEXTURE_2D, texture); 296 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, 297 | gl.UNSIGNED_BYTE, image); 298 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 299 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 300 | gl.generateMipmap(gl.TEXTURE_2D); 301 | gl.bindTexture(gl.TEXTURE_2D, null); 302 | } 303 | 304 | // 305 | // drawScene 306 | 307 | 308 | function drawScene() { 309 | // Request the next frame of the animation 310 | normalSceneFrame = window.requestAnimationFrame(drawScene); 311 | 312 | // Clear the canvas before we start drawing on it. 313 | 314 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 315 | 316 | gl.viewport(0, 0, canvas.width, canvas.height); 317 | 318 | // Establish the perspective with which we want to view the 319 | // scene. Our field of view is 45 degrees, with a width/height 320 | // ratio of 640:480, and we only want to see objects between 0.1 units 321 | // and 100 units away from the camera. 322 | 323 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 324 | 325 | // Set the drawing position to the "identity" point, which is 326 | // the center of the scene. 327 | 328 | loadIdentity(); 329 | 330 | // Now move the drawing position a bit to where we want to start 331 | // drawing the cube. 332 | 333 | mvTranslate([-0.0, 0.0, -9.0]); 334 | 335 | // Save the current matrix, then rotate before we draw. 336 | 337 | mvPushMatrix(); 338 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 339 | 340 | // Draw the cube by binding the array buffer to the cube's vertices 341 | // array, setting attributes, and pushing it to GL. 342 | 343 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 344 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 345 | 346 | // Set the texture coordinates attribute for the vertices. 347 | 348 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 349 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 350 | 351 | // Specify the texture to map onto the faces. 352 | 353 | gl.activeTexture(gl.TEXTURE0); 354 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 355 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 356 | 357 | // Draw the cube. 358 | 359 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 360 | setMatrixUniforms(); 361 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 362 | 363 | // Restore the original matrix 364 | 365 | mvPopMatrix(); 366 | 367 | // Update the rotation for the next draw, if it's time to do so. 368 | 369 | var currentTime = (new Date).getTime(); 370 | if (lastCubeUpdateTime) { 371 | var delta = currentTime - lastCubeUpdateTime; 372 | 373 | cubeRotation += (30 * delta) / 1000.0; 374 | } 375 | 376 | lastCubeUpdateTime = currentTime; 377 | } 378 | 379 | 380 | // 381 | // WebVR: Draw the scene for the WebVR display. 382 | // 383 | function drawVRScene() { 384 | // WebVR: Request the next frame of the animation 385 | vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene); 386 | 387 | // Populate frameData with the data of the next frame to display 388 | vrDisplay.getFrameData(frameData); 389 | 390 | // Get the position, orientation, etc. of the gamepads 391 | 392 | var gamepads = navigator.getGamepads(); 393 | var gp = gamepads[0]; 394 | 395 | if(gp) { 396 | var gpPose = gp.pose; 397 | var curPos = gpPose.position; 398 | var curOrient = gpPose.orientation; 399 | if(poseStatsDisplayed) { 400 | displayPoseStats(gpPose); 401 | } 402 | } 403 | 404 | // Clear the canvas before we start drawing on it. 405 | 406 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 407 | 408 | // WebVR: Create the required projection and view matrix locations needed 409 | // for passing into the uniformMatrix4fv methods below 410 | 411 | var projectionMatrixLocation = gl.getUniformLocation(shaderProgram, "projMatrix"); 412 | var viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix"); 413 | 414 | // WebVR: Render the left eye’s view to the left half of the canvas 415 | gl.viewport(0, 0, canvas.width * 0.5, canvas.height); 416 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.leftProjectionMatrix); 417 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix); 418 | drawGeometry(); 419 | 420 | // WebVR: Render the right eye’s view to the right half of the canvas 421 | gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); 422 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.rightProjectionMatrix); 423 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix); 424 | drawGeometry(); 425 | 426 | function drawGeometry() { 427 | // Establish the perspective with which we want to view the 428 | // scene. Our field of view is 45 degrees, with a width/height 429 | // ratio of 640:480, and we only want to see objects between 0.1 units 430 | // and 100 units away from the camera. 431 | 432 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 433 | 434 | // Set the drawing position to the "identity" point, which is 435 | // the center of the scene. 436 | 437 | loadIdentity(); 438 | 439 | // Now move the drawing position a bit to where we want to start 440 | // drawing the cube. 441 | 442 | if(gp && gpPose.hasPosition) { 443 | mvTranslate([ 444 | 0.0 + (curPos[0] * 15) - (curOrient[1] * 15), 445 | 0.0 + (curPos[1] * 15) + (curOrient[0] * 15), 446 | -15.0 + (curPos[2] * 25) 447 | ]); 448 | } else if(gp) { 449 | mvTranslate([ 450 | 0.0 + (curOrient[1] * 15), 451 | 0.0 + (curOrient[0] * 15), 452 | -15.0 453 | ]); 454 | } else { 455 | mvTranslate([ 456 | 0.0, 457 | 0.0, 458 | -15.0 459 | ]); 460 | } 461 | 462 | // Save the current matrix, then rotate before we draw. 463 | 464 | mvPushMatrix(); 465 | 466 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 467 | 468 | // Draw the cube by binding the array buffer to the cube's vertices 469 | // array, setting attributes, and pushing it to GL. 470 | 471 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 472 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 473 | 474 | // Set the texture coordinates attribute for the vertices. 475 | 476 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 477 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 478 | 479 | // Specify the texture to map onto the faces. 480 | 481 | gl.activeTexture(gl.TEXTURE0); 482 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 483 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 484 | 485 | // Draw the cube. 486 | 487 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 488 | setMatrixUniforms(); 489 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 490 | 491 | // Restore the original matrix 492 | 493 | mvPopMatrix(); 494 | } 495 | 496 | // Update the rotation for the next draw, if it's time to do so. 497 | 498 | var currentTime = (new Date).getTime(); 499 | if (lastCubeUpdateTime) { 500 | var delta = currentTime - lastCubeUpdateTime; 501 | 502 | cubeRotation += (30 * delta) / 1000.0; 503 | } 504 | 505 | lastCubeUpdateTime = currentTime; 506 | 507 | // WebVR: Indicate that we are ready to present the rendered frame to the VR display 508 | vrDisplay.submitFrame(); 509 | } 510 | 511 | // 512 | // initShaders 513 | // 514 | // Initialize the shaders, so WebGL knows how to light our scene. 515 | // 516 | function initShaders() { 517 | var fragmentShader = getShader(gl, "shader-fs"); 518 | var vertexShader = getShader(gl, "shader-vs"); 519 | 520 | // Create the shader program 521 | 522 | shaderProgram = gl.createProgram(); // Create our program, set it to be the value of shaderProgram 523 | gl.attachShader(shaderProgram, vertexShader); 524 | gl.attachShader(shaderProgram, fragmentShader); 525 | gl.linkProgram(shaderProgram); 526 | 527 | // If creating the shader program failed, alert 528 | 529 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 530 | alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shader)); 531 | } 532 | 533 | gl.useProgram(shaderProgram); // Specify the WebGL program we want to use for the rendering 534 | 535 | vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 536 | gl.enableVertexAttribArray(vertexPositionAttribute); 537 | 538 | textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 539 | gl.enableVertexAttribArray(textureCoordAttribute); 540 | } 541 | 542 | // 543 | // getShader 544 | // 545 | // Loads a shader program by scouring the current document, 546 | // looking for a script with the specified ID. 547 | // 548 | function getShader(gl, id) { 549 | var shaderScript = document.getElementById(id); 550 | 551 | // Didn't find an element with the specified ID; abort. 552 | 553 | if (!shaderScript) { 554 | return null; 555 | } 556 | 557 | // Walk through the source element's children, building the 558 | // shader source string. 559 | 560 | var theSource = ""; 561 | var currentChild = shaderScript.firstChild; 562 | 563 | while(currentChild) { 564 | if (currentChild.nodeType == 3) { 565 | theSource += currentChild.textContent; 566 | } 567 | 568 | currentChild = currentChild.nextSibling; 569 | } 570 | 571 | // Now figure out what type of shader script we have, 572 | // based on its MIME type. 573 | 574 | var shader; 575 | 576 | if (shaderScript.type == "x-shader/x-fragment") { 577 | shader = gl.createShader(gl.FRAGMENT_SHADER); 578 | } else if (shaderScript.type == "x-shader/x-vertex") { 579 | shader = gl.createShader(gl.VERTEX_SHADER); 580 | } else { 581 | return null; // Unknown shader type 582 | } 583 | 584 | // Send the source to the shader object 585 | 586 | gl.shaderSource(shader, theSource); 587 | 588 | // Compile the shader program 589 | 590 | gl.compileShader(shader); 591 | 592 | // See if it compiled successfully 593 | 594 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 595 | alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); 596 | return null; 597 | } 598 | 599 | return shader; 600 | } 601 | 602 | // 603 | // Matrix utility functions 604 | // 605 | 606 | function loadIdentity() { 607 | mvMatrix = Matrix.I(4); 608 | } 609 | 610 | function multMatrix(m) { 611 | mvMatrix = mvMatrix.x(m); 612 | } 613 | 614 | function mvTranslate(v) { 615 | multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4()); 616 | } 617 | 618 | function setMatrixUniforms() { 619 | var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 620 | gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten())); 621 | 622 | var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); 623 | gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten())); 624 | } 625 | 626 | var mvMatrixStack = []; 627 | 628 | function mvPushMatrix(m) { 629 | if (m) { 630 | mvMatrixStack.push(m.dup()); 631 | mvMatrix = m.dup(); 632 | } else { 633 | mvMatrixStack.push(mvMatrix.dup()); 634 | } 635 | } 636 | 637 | function mvPopMatrix() { 638 | if (!mvMatrixStack.length) { 639 | throw("Can't pop from an empty matrix stack."); 640 | } 641 | 642 | mvMatrix = mvMatrixStack.pop(); 643 | return mvMatrix; 644 | } 645 | 646 | function mvRotate(angle, v) { 647 | var inRadians = angle * Math.PI / 180.0; 648 | var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); 649 | multMatrix(m); 650 | } 651 | 652 | // WebVR: Sample event handler 653 | 654 | window.addEventListener('vrdisplaypresentchange', function(e) { 655 | console.log('Display ' + e.display.displayId + ' presentation has changed. Reason given: ' + e.reason + '.'); 656 | }); 657 | 658 | // WebVR: Controls readout of pose stats panel 659 | 660 | poseStatsBtn.addEventListener('click', function() { 661 | if(!poseStatsDisplayed) { 662 | poseStatsDisplayed = true; 663 | poseStatsSection.style.visibility = 'visible'; 664 | poseStatsBtn.textContent = 'Hide pose stats'; 665 | } else { 666 | poseStatsDisplayed = false; 667 | poseStatsSection.style.visibility = 'hidden'; 668 | poseStatsBtn.textContent = 'Show pose stats'; 669 | } 670 | }); 671 | 672 | function displayPoseStats(pose) { 673 | var pos = pose.position; 674 | var orient = pose.orientation; 675 | var linVel = pose.linearVelocity; 676 | var linAcc = pose.linearAcceleration; 677 | var angVel = pose.angularVelocity; 678 | var angAcc = pose.angularAcceleration; 679 | 680 | if(pose.hasPosition) { 681 | posStats.textContent = 'Position: x ' + pos[0].toFixed(3) + ', y ' + pos[1].toFixed(3) + ', z ' + pos[2].toFixed(3); 682 | } else { 683 | posStats.textContent = 'Position not reported'; 684 | } 685 | 686 | if(pose.hasOrientation) { 687 | orientStats.textContent = 'Orientation: x ' + orient[0].toFixed(3) + ', y ' + orient[1].toFixed(3) + ', z ' + orient[2].toFixed(3); 688 | } else { 689 | orientStats.textContent = 'Orientation not reported'; 690 | } 691 | 692 | linVelStats.textContent = 'Linear velocity: x ' + linVel[0].toFixed(3) + ', y ' + linVel[1].toFixed(3) + ', z ' + linVel[2].toFixed(3); 693 | angVelStats.textContent = 'Angular velocity: x ' + angVel[0].toFixed(3) + ', y ' + angVel[1].toFixed(3) + ', z ' + angVel[2].toFixed(3); 694 | 695 | if(linAcc) { 696 | linAccStats.textContent = 'Linear acceleration: x ' + linAcc[0].toFixed(3) + ', y ' + linAcc[1].toFixed(3) + ', z ' + linAcc[2].toFixed(3); 697 | } else { 698 | linAccStats.textContent = 'Linear acceleration not reported'; 699 | } 700 | 701 | if(angAcc) { 702 | angAccStats.textContent = 'Angular acceleration: x ' + angAcc[0].toFixed(3) + ', y ' + angAcc[1].toFixed(3) + ', z ' + angAcc[2].toFixed(3); 703 | } else { 704 | angAccStats.textContent = 'Angular acceleration not reported'; 705 | } 706 | } 707 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/webgl.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | font-family: sans-serif; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | height: inherit; 9 | overflow: hidden; 10 | } 11 | 12 | canvas { 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | button { 18 | position: absolute; 19 | top: 3px; 20 | } 21 | 22 | .stop-start { 23 | right: 3px; 24 | } 25 | 26 | .pose-stats { 27 | right: 120px; 28 | } 29 | 30 | section { 31 | position: absolute; 32 | background-color: rgb(255,255,255,0.5); 33 | color: black; 34 | bottom: 3px; 35 | right: 3px; 36 | display: flex; 37 | } 38 | 39 | section p { 40 | padding: 5px 10px; 41 | margin: 0; 42 | font-size: 11px; 43 | width: 230px; 44 | text-align: center; 45 | } -------------------------------------------------------------------------------- /webvr/raw-webgl-example/cubetexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/webvr-tests/bb5c886e2c877211562bb360630d15ab56336155/webvr/raw-webgl-example/cubetexture.png -------------------------------------------------------------------------------- /webvr/raw-webgl-example/glUtils.js: -------------------------------------------------------------------------------- 1 | // augment Sylvester some 2 | Matrix.Translation = function (v) 3 | { 4 | if (v.elements.length == 2) { 5 | var r = Matrix.I(3); 6 | r.elements[2][0] = v.elements[0]; 7 | r.elements[2][1] = v.elements[1]; 8 | return r; 9 | } 10 | 11 | if (v.elements.length == 3) { 12 | var r = Matrix.I(4); 13 | r.elements[0][3] = v.elements[0]; 14 | r.elements[1][3] = v.elements[1]; 15 | r.elements[2][3] = v.elements[2]; 16 | return r; 17 | } 18 | 19 | throw "Invalid length for Translation"; 20 | } 21 | 22 | Matrix.prototype.flatten = function () 23 | { 24 | var result = []; 25 | if (this.elements.length == 0) 26 | return []; 27 | 28 | 29 | for (var j = 0; j < this.elements[0].length; j++) 30 | for (var i = 0; i < this.elements.length; i++) 31 | result.push(this.elements[i][j]); 32 | return result; 33 | } 34 | 35 | Matrix.prototype.ensure4x4 = function() 36 | { 37 | if (this.elements.length == 4 && 38 | this.elements[0].length == 4) 39 | return this; 40 | 41 | if (this.elements.length > 4 || 42 | this.elements[0].length > 4) 43 | return null; 44 | 45 | for (var i = 0; i < this.elements.length; i++) { 46 | for (var j = this.elements[i].length; j < 4; j++) { 47 | if (i == j) 48 | this.elements[i].push(1); 49 | else 50 | this.elements[i].push(0); 51 | } 52 | } 53 | 54 | for (var i = this.elements.length; i < 4; i++) { 55 | if (i == 0) 56 | this.elements.push([1, 0, 0, 0]); 57 | else if (i == 1) 58 | this.elements.push([0, 1, 0, 0]); 59 | else if (i == 2) 60 | this.elements.push([0, 0, 1, 0]); 61 | else if (i == 3) 62 | this.elements.push([0, 0, 0, 1]); 63 | } 64 | 65 | return this; 66 | }; 67 | 68 | Matrix.prototype.make3x3 = function() 69 | { 70 | if (this.elements.length != 4 || 71 | this.elements[0].length != 4) 72 | return null; 73 | 74 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]], 75 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]], 76 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]); 77 | }; 78 | 79 | Vector.prototype.flatten = function () 80 | { 81 | return this.elements; 82 | }; 83 | 84 | function mht(m) { 85 | var s = ""; 86 | if (m.length == 16) { 87 | for (var i = 0; i < 4; i++) { 88 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
"; 89 | } 90 | } else if (m.length == 9) { 91 | for (var i = 0; i < 3; i++) { 92 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
"; 93 | } 94 | } else { 95 | return m.toString(); 96 | } 97 | return s; 98 | } 99 | 100 | // 101 | // gluLookAt 102 | // 103 | function makeLookAt(ex, ey, ez, 104 | cx, cy, cz, 105 | ux, uy, uz) 106 | { 107 | var eye = $V([ex, ey, ez]); 108 | var center = $V([cx, cy, cz]); 109 | var up = $V([ux, uy, uz]); 110 | 111 | var mag; 112 | 113 | var z = eye.subtract(center).toUnitVector(); 114 | var x = up.cross(z).toUnitVector(); 115 | var y = z.cross(x).toUnitVector(); 116 | 117 | var m = $M([[x.e(1), x.e(2), x.e(3), 0], 118 | [y.e(1), y.e(2), y.e(3), 0], 119 | [z.e(1), z.e(2), z.e(3), 0], 120 | [0, 0, 0, 1]]); 121 | 122 | var t = $M([[1, 0, 0, -ex], 123 | [0, 1, 0, -ey], 124 | [0, 0, 1, -ez], 125 | [0, 0, 0, 1]]); 126 | return m.x(t); 127 | } 128 | 129 | // 130 | // glOrtho 131 | // 132 | function makeOrtho(left, right, 133 | bottom, top, 134 | znear, zfar) 135 | { 136 | var tx = -(right+left)/(right-left); 137 | var ty = -(top+bottom)/(top-bottom); 138 | var tz = -(zfar+znear)/(zfar-znear); 139 | 140 | return $M([[2/(right-left), 0, 0, tx], 141 | [0, 2/(top-bottom), 0, ty], 142 | [0, 0, -2/(zfar-znear), tz], 143 | [0, 0, 0, 1]]); 144 | } 145 | 146 | // 147 | // gluPerspective 148 | // 149 | function makePerspective(fovy, aspect, znear, zfar) 150 | { 151 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 152 | var ymin = -ymax; 153 | var xmin = ymin * aspect; 154 | var xmax = ymax * aspect; 155 | 156 | return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); 157 | } 158 | 159 | // 160 | // glFrustum 161 | // 162 | function makeFrustum(left, right, 163 | bottom, top, 164 | znear, zfar) 165 | { 166 | var X = 2*znear/(right-left); 167 | var Y = 2*znear/(top-bottom); 168 | var A = (right+left)/(right-left); 169 | var B = (top+bottom)/(top-bottom); 170 | var C = -(zfar+znear)/(zfar-znear); 171 | var D = -2*zfar*znear/(zfar-znear); 172 | 173 | return $M([[X, 0, A, 0], 174 | [0, Y, B, 0], 175 | [0, 0, C, D], 176 | [0, 0, -1, 0]]); 177 | } 178 | 179 | // 180 | // glOrtho 181 | // 182 | function makeOrtho(left, right, bottom, top, znear, zfar) 183 | { 184 | var tx = - (right + left) / (right - left); 185 | var ty = - (top + bottom) / (top - bottom); 186 | var tz = - (zfar + znear) / (zfar - znear); 187 | 188 | return $M([[2 / (right - left), 0, 0, tx], 189 | [0, 2 / (top - bottom), 0, ty], 190 | [0, 0, -2 / (zfar - znear), tz], 191 | [0, 0, 0, 1]]); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Raw WebGL/WebVR Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | Your browser doesn't appear to support the <canvas> element. 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 | 46 | 47 | 48 | 49 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/webvr-tests/bb5c886e2c877211562bb360630d15ab56336155/webvr/raw-webgl-example/metal003.png -------------------------------------------------------------------------------- /webvr/raw-webgl-example/sylvester.js: -------------------------------------------------------------------------------- 1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) -------------------------------------------------------------------------------- /webvr/raw-webgl-example/webgl-demo.js: -------------------------------------------------------------------------------- 1 | var canvas; // The canvas element 2 | var gl; // The WebGL context 3 | 4 | var cubeVerticesBuffer; 5 | var cubeVerticesTextureCoordBuffer; 6 | var cubeVerticesIndexBuffer; 7 | var cubeVerticesIndexBuffer; 8 | var cubeRotation = 0.0; 9 | var lastCubeUpdateTime = 0; 10 | 11 | var cubeImage; 12 | var cubeTexture; 13 | 14 | var mvMatrix; 15 | var shaderProgram; // The WebGLProgram we will create, which will render the cube 16 | var vertexPositionAttribute; 17 | var textureCoordAttribute; 18 | var perspectiveMatrix; 19 | 20 | // WebVR variables 21 | 22 | var frameData = new VRFrameData(); 23 | var vrDisplay; 24 | var btn = document.querySelector('.stop-start'); 25 | var normalSceneFrame; 26 | var vrSceneFrame; 27 | 28 | var poseStatsBtn = document.querySelector('.pose-stats'); 29 | var poseStatsSection = document.querySelector('section'); 30 | poseStatsSection.style.visibility = 'hidden'; // hide it initially 31 | 32 | var posStats = document.querySelector('.pos'); 33 | var orientStats = document.querySelector('.orient'); 34 | var linVelStats = document.querySelector('.lin-vel'); 35 | var linAccStats = document.querySelector('.lin-acc'); 36 | var angVelStats = document.querySelector('.ang-vel'); 37 | var angAccStats = document.querySelector('.ang-acc'); 38 | var poseStatsDisplayed = false; 39 | 40 | // 41 | // start 42 | // 43 | // Called when the body has loaded is created to get the ball rolling. 44 | 45 | document.body.onload = start; 46 | 47 | function start() { 48 | canvas = document.getElementById("glcanvas"); 49 | 50 | initWebGL(canvas); // Initialize the GL context 51 | 52 | // Only continue if WebGL is available and working 53 | 54 | if (gl) { 55 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque 56 | gl.clearDepth(1.0); // Clear everything 57 | gl.enable(gl.DEPTH_TEST); // Enable depth testing 58 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things 59 | 60 | // Initialize the shaders; this is where all the lighting for the 61 | // vertices and so forth is established. 62 | 63 | initShaders(); 64 | 65 | // Here's where we call the routine that builds all the objects 66 | // we'll be drawing. 67 | 68 | initBuffers(); 69 | 70 | // Next, load and set up the textures we'll be using. 71 | 72 | initTextures(); 73 | 74 | // draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser 75 | 76 | canvas.width = window.innerWidth; 77 | canvas.height = window.innerHeight; 78 | drawScene(); 79 | 80 | // WebVR: Check to see if WebVR is supported 81 | if(navigator.getVRDisplays) { 82 | console.log('WebVR 1.1 supported'); 83 | // Then get the displays attached to the computer 84 | navigator.getVRDisplays().then(function(displays) { 85 | // If a display is available, use it to present the scene 86 | if(displays.length > 0) { 87 | vrDisplay = displays[0]; 88 | console.log('Display found'); 89 | // Starting the presentation when the button is clicked: It can only be called in response to a user gesture 90 | btn.addEventListener('click', function() { 91 | if(btn.textContent === 'Start VR display') { 92 | vrDisplay.requestPresent([{ source: canvas }]).then(function() { 93 | console.log('Presenting to WebVR display'); 94 | 95 | // Set the canvas size to the size of the vrDisplay viewport 96 | 97 | var leftEye = vrDisplay.getEyeParameters('left'); 98 | var rightEye = vrDisplay.getEyeParameters('right'); 99 | 100 | canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2; 101 | canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight); 102 | 103 | // stop the normal presentation, and start the vr presentation 104 | window.cancelAnimationFrame(normalSceneFrame); 105 | drawVRScene(); 106 | 107 | btn.textContent = 'Exit VR display'; 108 | }); 109 | } else { 110 | vrDisplay.exitPresent(); 111 | console.log('Stopped presenting to WebVR display'); 112 | 113 | btn.textContent = 'Start VR display'; 114 | 115 | // Stop the VR presentation, and start the normal presentation 116 | vrDisplay.cancelAnimationFrame(vrSceneFrame); 117 | drawScene(); 118 | } 119 | }); 120 | } 121 | }); 122 | } else { 123 | console.log('WebVR API not supported by this browser.'); 124 | } 125 | } 126 | } 127 | 128 | // 129 | // initWebGL 130 | // 131 | // Initialize WebGL, returning the GL context or null if 132 | // WebGL isn't available or could not be initialized. 133 | // 134 | function initWebGL() { 135 | gl = null; 136 | 137 | try { 138 | gl = canvas.getContext("experimental-webgl"); 139 | } 140 | catch(e) { 141 | } 142 | 143 | // If we don't have a GL context, give up now 144 | 145 | if (!gl) { 146 | alert("Unable to initialize WebGL. Your browser may not support it."); 147 | } 148 | } 149 | 150 | // 151 | // initBuffers 152 | // 153 | // Initialize the buffers we'll need. For this demo, we just have 154 | // one object -- a simple two-dimensional cube. 155 | // 156 | function initBuffers() { 157 | 158 | // Create a buffer for the cube's vertices. 159 | 160 | cubeVerticesBuffer = gl.createBuffer(); 161 | 162 | // Select the cubeVerticesBuffer as the one to apply vertex 163 | // operations to from here out. 164 | 165 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 166 | 167 | // Now create an array of vertices for the cube. 168 | 169 | var vertices = [ 170 | // Front face 171 | -1.0, -1.0, 1.0, 172 | 1.0, -1.0, 1.0, 173 | 1.0, 1.0, 1.0, 174 | -1.0, 1.0, 1.0, 175 | 176 | // Back face 177 | -1.0, -1.0, -1.0, 178 | -1.0, 1.0, -1.0, 179 | 1.0, 1.0, -1.0, 180 | 1.0, -1.0, -1.0, 181 | 182 | // Top face 183 | -1.0, 1.0, -1.0, 184 | -1.0, 1.0, 1.0, 185 | 1.0, 1.0, 1.0, 186 | 1.0, 1.0, -1.0, 187 | 188 | // Bottom face 189 | -1.0, -1.0, -1.0, 190 | 1.0, -1.0, -1.0, 191 | 1.0, -1.0, 1.0, 192 | -1.0, -1.0, 1.0, 193 | 194 | // Right face 195 | 1.0, -1.0, -1.0, 196 | 1.0, 1.0, -1.0, 197 | 1.0, 1.0, 1.0, 198 | 1.0, -1.0, 1.0, 199 | 200 | // Left face 201 | -1.0, -1.0, -1.0, 202 | -1.0, -1.0, 1.0, 203 | -1.0, 1.0, 1.0, 204 | -1.0, 1.0, -1.0 205 | ]; 206 | 207 | // Now pass the list of vertices into WebGL to build the shape. We 208 | // do this by creating a Float32Array from the JavaScript array, 209 | // then use it to fill the current vertex buffer. 210 | 211 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 212 | 213 | // Map the texture onto the cube's faces. 214 | 215 | cubeVerticesTextureCoordBuffer = gl.createBuffer(); 216 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 217 | 218 | var textureCoordinates = [ 219 | // Front 220 | 0.0, 0.0, 221 | 1.0, 0.0, 222 | 1.0, 1.0, 223 | 0.0, 1.0, 224 | // Back 225 | 0.0, 0.0, 226 | 1.0, 0.0, 227 | 1.0, 1.0, 228 | 0.0, 1.0, 229 | // Top 230 | 0.0, 0.0, 231 | 1.0, 0.0, 232 | 1.0, 1.0, 233 | 0.0, 1.0, 234 | // Bottom 235 | 0.0, 0.0, 236 | 1.0, 0.0, 237 | 1.0, 1.0, 238 | 0.0, 1.0, 239 | // Right 240 | 0.0, 0.0, 241 | 1.0, 0.0, 242 | 1.0, 1.0, 243 | 0.0, 1.0, 244 | // Left 245 | 0.0, 0.0, 246 | 1.0, 0.0, 247 | 1.0, 1.0, 248 | 0.0, 1.0 249 | ]; 250 | 251 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), 252 | gl.STATIC_DRAW); 253 | 254 | // Build the element array buffer; this specifies the indices 255 | // into the vertex array for each face's vertices. 256 | 257 | cubeVerticesIndexBuffer = gl.createBuffer(); 258 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 259 | 260 | // This array defines each face as two triangles, using the 261 | // indices into the vertex array to specify each triangle's 262 | // position. 263 | 264 | var cubeVertexIndices = [ 265 | 0, 1, 2, 0, 2, 3, // front 266 | 4, 5, 6, 4, 6, 7, // back 267 | 8, 9, 10, 8, 10, 11, // top 268 | 12, 13, 14, 12, 14, 15, // bottom 269 | 16, 17, 18, 16, 18, 19, // right 270 | 20, 21, 22, 20, 22, 23 // left 271 | ]; 272 | 273 | // Now send the element array to GL 274 | 275 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 276 | new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 277 | } 278 | 279 | // 280 | // initTextures 281 | // 282 | // Initialize the textures we'll be using, then initiate a load of 283 | // the texture images. The handleTextureLoaded() callback will finish 284 | // the job; it gets called each time a texture finishes loading. 285 | // 286 | function initTextures() { 287 | cubeTexture = gl.createTexture(); 288 | cubeImage = new Image(); 289 | cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }; 290 | cubeImage.src = "metal003.png"; 291 | } 292 | 293 | function handleTextureLoaded(image, texture) { 294 | console.log("handleTextureLoaded, image = " + image); 295 | gl.bindTexture(gl.TEXTURE_2D, texture); 296 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, 297 | gl.UNSIGNED_BYTE, image); 298 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 299 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 300 | gl.generateMipmap(gl.TEXTURE_2D); 301 | gl.bindTexture(gl.TEXTURE_2D, null); 302 | } 303 | 304 | // 305 | // drawScene 306 | 307 | 308 | function drawScene() { 309 | // Request the next frame of the animation 310 | normalSceneFrame = window.requestAnimationFrame(drawScene); 311 | 312 | // Clear the canvas before we start drawing on it. 313 | 314 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 315 | 316 | gl.viewport(0, 0, canvas.width, canvas.height); 317 | 318 | // Establish the perspective with which we want to view the 319 | // scene. Our field of view is 45 degrees, with a width/height 320 | // ratio of 640:480, and we only want to see objects between 0.1 units 321 | // and 100 units away from the camera. 322 | 323 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 324 | 325 | // Set the drawing position to the "identity" point, which is 326 | // the center of the scene. 327 | 328 | loadIdentity(); 329 | 330 | // Now move the drawing position a bit to where we want to start 331 | // drawing the cube. 332 | 333 | mvTranslate([-0.0, 0.0, -9.0]); 334 | 335 | // Save the current matrix, then rotate before we draw. 336 | 337 | mvPushMatrix(); 338 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 339 | 340 | // Draw the cube by binding the array buffer to the cube's vertices 341 | // array, setting attributes, and pushing it to GL. 342 | 343 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 344 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 345 | 346 | // Set the texture coordinates attribute for the vertices. 347 | 348 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 349 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 350 | 351 | // Specify the texture to map onto the faces. 352 | 353 | gl.activeTexture(gl.TEXTURE0); 354 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 355 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 356 | 357 | // Draw the cube. 358 | 359 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 360 | setMatrixUniforms(); 361 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 362 | 363 | // Restore the original matrix 364 | 365 | mvPopMatrix(); 366 | 367 | // Update the rotation for the next draw, if it's time to do so. 368 | 369 | var currentTime = (new Date).getTime(); 370 | if (lastCubeUpdateTime) { 371 | var delta = currentTime - lastCubeUpdateTime; 372 | 373 | cubeRotation += (30 * delta) / 1000.0; 374 | } 375 | 376 | lastCubeUpdateTime = currentTime; 377 | } 378 | 379 | 380 | // 381 | // WebVR: Draw the scene for the WebVR display. 382 | // 383 | function drawVRScene() { 384 | // WebVR: Request the next frame of the animation 385 | vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene); 386 | 387 | // Populate frameData with the data of the next frame to display 388 | vrDisplay.getFrameData(frameData); 389 | 390 | // You can get the position, orientation, etc. of the display from the current frame's pose 391 | 392 | var curFramePose = frameData.pose; 393 | var curPos = curFramePose.position; 394 | var curOrient = curFramePose.orientation; 395 | if(poseStatsDisplayed) { 396 | displayPoseStats(curFramePose); 397 | } 398 | 399 | // Clear the canvas before we start drawing on it. 400 | 401 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 402 | 403 | // WebVR: Create the required projection and view matrix locations needed 404 | // for passing into the uniformMatrix4fv methods below 405 | 406 | var projectionMatrixLocation = gl.getUniformLocation(shaderProgram, "projMatrix"); 407 | var viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix"); 408 | 409 | // WebVR: Render the left eye’s view to the left half of the canvas 410 | gl.viewport(0, 0, canvas.width * 0.5, canvas.height); 411 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.leftProjectionMatrix); 412 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix); 413 | drawGeometry(); 414 | 415 | // WebVR: Render the right eye’s view to the right half of the canvas 416 | gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); 417 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.rightProjectionMatrix); 418 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix); 419 | drawGeometry(); 420 | 421 | function drawGeometry() { 422 | // Establish the perspective with which we want to view the 423 | // scene. Our field of view is 45 degrees, with a width/height 424 | // ratio of 640:480, and we only want to see objects between 0.1 units 425 | // and 100 units away from the camera. 426 | 427 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 428 | 429 | // Set the drawing position to the "identity" point, which is 430 | // the center of the scene. 431 | 432 | loadIdentity(); 433 | 434 | // Now move the drawing position a bit to where we want to start 435 | // drawing the cube. 436 | 437 | mvTranslate([ 438 | 0.0 - (curPos[0] * 25) + (curOrient[1] * 25), 439 | 5.0 - (curPos[1] * 25) - (curOrient[0] * 25), 440 | -15.0 - (curPos[2] * 25) 441 | ]); 442 | 443 | // Save the current matrix, then rotate before we draw. 444 | 445 | mvPushMatrix(); 446 | mvRotate(cubeRotation, [0.25, 0, 0.25 - curOrient[2] * 0.5]); 447 | 448 | // Draw the cube by binding the array buffer to the cube's vertices 449 | // array, setting attributes, and pushing it to GL. 450 | 451 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 452 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 453 | 454 | // Set the texture coordinates attribute for the vertices. 455 | 456 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 457 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 458 | 459 | // Specify the texture to map onto the faces. 460 | 461 | gl.activeTexture(gl.TEXTURE0); 462 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 463 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 464 | 465 | // Draw the cube. 466 | 467 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 468 | setMatrixUniforms(); 469 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 470 | 471 | // Restore the original matrix 472 | 473 | mvPopMatrix(); 474 | } 475 | 476 | // Update the rotation for the next draw, if it's time to do so. 477 | 478 | var currentTime = (new Date).getTime(); 479 | if (lastCubeUpdateTime) { 480 | var delta = currentTime - lastCubeUpdateTime; 481 | 482 | cubeRotation += (30 * delta) / 1000.0; 483 | } 484 | 485 | lastCubeUpdateTime = currentTime; 486 | 487 | // WebVR: Indicate that we are ready to present the rendered frame to the VR display 488 | vrDisplay.submitFrame(); 489 | } 490 | 491 | // 492 | // initShaders 493 | // 494 | // Initialize the shaders, so WebGL knows how to light our scene. 495 | // 496 | function initShaders() { 497 | var fragmentShader = getShader(gl, "shader-fs"); 498 | var vertexShader = getShader(gl, "shader-vs"); 499 | 500 | // Create the shader program 501 | 502 | shaderProgram = gl.createProgram(); // Create our program, set it to be the value of shaderProgram 503 | gl.attachShader(shaderProgram, vertexShader); 504 | gl.attachShader(shaderProgram, fragmentShader); 505 | gl.linkProgram(shaderProgram); 506 | 507 | // If creating the shader program failed, alert 508 | 509 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 510 | alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shader)); 511 | } 512 | 513 | gl.useProgram(shaderProgram); // Specify the WebGL program we want to use for the rendering 514 | 515 | vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 516 | gl.enableVertexAttribArray(vertexPositionAttribute); 517 | 518 | textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 519 | gl.enableVertexAttribArray(textureCoordAttribute); 520 | } 521 | 522 | // 523 | // getShader 524 | // 525 | // Loads a shader program by scouring the current document, 526 | // looking for a script with the specified ID. 527 | // 528 | function getShader(gl, id) { 529 | var shaderScript = document.getElementById(id); 530 | 531 | // Didn't find an element with the specified ID; abort. 532 | 533 | if (!shaderScript) { 534 | return null; 535 | } 536 | 537 | // Walk through the source element's children, building the 538 | // shader source string. 539 | 540 | var theSource = ""; 541 | var currentChild = shaderScript.firstChild; 542 | 543 | while(currentChild) { 544 | if (currentChild.nodeType == 3) { 545 | theSource += currentChild.textContent; 546 | } 547 | 548 | currentChild = currentChild.nextSibling; 549 | } 550 | 551 | // Now figure out what type of shader script we have, 552 | // based on its MIME type. 553 | 554 | var shader; 555 | 556 | if (shaderScript.type == "x-shader/x-fragment") { 557 | shader = gl.createShader(gl.FRAGMENT_SHADER); 558 | } else if (shaderScript.type == "x-shader/x-vertex") { 559 | shader = gl.createShader(gl.VERTEX_SHADER); 560 | } else { 561 | return null; // Unknown shader type 562 | } 563 | 564 | // Send the source to the shader object 565 | 566 | gl.shaderSource(shader, theSource); 567 | 568 | // Compile the shader program 569 | 570 | gl.compileShader(shader); 571 | 572 | // See if it compiled successfully 573 | 574 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 575 | alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); 576 | return null; 577 | } 578 | 579 | return shader; 580 | } 581 | 582 | // 583 | // Matrix utility functions 584 | // 585 | 586 | function loadIdentity() { 587 | mvMatrix = Matrix.I(4); 588 | } 589 | 590 | function multMatrix(m) { 591 | mvMatrix = mvMatrix.x(m); 592 | } 593 | 594 | function mvTranslate(v) { 595 | multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4()); 596 | } 597 | 598 | function setMatrixUniforms() { 599 | var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 600 | gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten())); 601 | 602 | var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); 603 | gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten())); 604 | } 605 | 606 | var mvMatrixStack = []; 607 | 608 | function mvPushMatrix(m) { 609 | if (m) { 610 | mvMatrixStack.push(m.dup()); 611 | mvMatrix = m.dup(); 612 | } else { 613 | mvMatrixStack.push(mvMatrix.dup()); 614 | } 615 | } 616 | 617 | function mvPopMatrix() { 618 | if (!mvMatrixStack.length) { 619 | throw("Can't pop from an empty matrix stack."); 620 | } 621 | 622 | mvMatrix = mvMatrixStack.pop(); 623 | return mvMatrix; 624 | } 625 | 626 | function mvRotate(angle, v) { 627 | var inRadians = angle * Math.PI / 180.0; 628 | var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); 629 | multMatrix(m); 630 | } 631 | 632 | // WebVR: Sample event handler 633 | 634 | window.addEventListener('vrdisplaypresentchange', function(e) { 635 | console.log('Display ' + e.display.displayId + ' presentation has changed. Reason given: ' + e.reason + '.'); 636 | }); 637 | 638 | // WebVR: Controls readout of pose stats panel 639 | 640 | poseStatsBtn.addEventListener('click', function() { 641 | if(!poseStatsDisplayed) { 642 | poseStatsDisplayed = true; 643 | poseStatsSection.style.visibility = 'visible'; 644 | poseStatsBtn.textContent = 'Hide pose stats'; 645 | } else { 646 | poseStatsDisplayed = false; 647 | poseStatsSection.style.visibility = 'hidden'; 648 | poseStatsBtn.textContent = 'Show pose stats'; 649 | } 650 | }); 651 | 652 | function displayPoseStats(pose) { 653 | var pos = pose.position; 654 | var orient = pose.orientation; 655 | var linVel = pose.linearVelocity; 656 | var linAcc = pose.linearAcceleration; 657 | var angVel = pose.angularVelocity; 658 | var angAcc = pose.angularAcceleration; 659 | 660 | posStats.textContent = 'Position: x ' + pos[0].toFixed(3) + ', y ' + pos[1].toFixed(3) + ', z ' + pos[2].toFixed(3); 661 | orientStats.textContent = 'Orientation: x ' + orient[0].toFixed(3) + ', y ' + orient[1].toFixed(3) + ', z ' + orient[2].toFixed(3); 662 | linVelStats.textContent = 'Linear velocity: x ' + linVel[0].toFixed(3) + ', y ' + linVel[1].toFixed(3) + ', z ' + linVel[2].toFixed(3); 663 | angVelStats.textContent = 'Angular velocity: x ' + angVel[0].toFixed(3) + ', y ' + angVel[1].toFixed(3) + ', z ' + angVel[2].toFixed(3); 664 | 665 | if(linAcc) { 666 | linAccStats.textContent = 'Linear acceleration: x ' + linAcc[0].toFixed(3) + ', y ' + linAcc[1].toFixed(3) + ', z ' + linAcc[2].toFixed(3); 667 | } else { 668 | linAccStats.textContent = 'Linear acceleration not reported'; 669 | } 670 | 671 | if(angAcc) { 672 | angAccStats.textContent = 'Angular acceleration: x ' + angAcc[0].toFixed(3) + ', y ' + angAcc[1].toFixed(3) + ', z ' + angAcc[2].toFixed(3); 673 | } else { 674 | angAccStats.textContent = 'Angular acceleration not reported'; 675 | } 676 | } 677 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/webgl.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | font-family: sans-serif; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | height: inherit; 9 | overflow: hidden; 10 | } 11 | 12 | canvas { 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | button { 18 | position: absolute; 19 | top: 3px; 20 | } 21 | 22 | .stop-start { 23 | right: 3px; 24 | } 25 | 26 | .pose-stats { 27 | right: 120px; 28 | } 29 | 30 | section { 31 | position: absolute; 32 | background-color: rgb(255,255,255,0.5); 33 | color: black; 34 | bottom: 3px; 35 | right: 3px; 36 | display: flex; 37 | } 38 | 39 | section p { 40 | padding: 5px 10px; 41 | margin: 0; 42 | font-size: 11px; 43 | width: 230px; 44 | text-align: center; 45 | } -------------------------------------------------------------------------------- /webvr/stage-parameters-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRStageParameters basic test 9 | 10 | 11 | 12 | 13 |

VRStageParameters basic test

14 | 15 |

16 | 17 | 44 | 45 | -------------------------------------------------------------------------------- /webvr/vr-controller-basic-info/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VR Gamepads basic test 9 | 10 | 11 | 12 | 13 |

VR Gamepads basic test

14 | 15 |

16 | 17 |
    18 |
19 | 20 | 102 | 103 | 104 | --------------------------------------------------------------------------------