├── .gitignore
├── examples
├── scene
│ ├── assets
│ │ ├── peach-gradient-1.jpg
│ │ ├── tex
│ │ │ └── shadow-circle.png
│ │ ├── 321103__nsstudios__blip1.wav
│ │ ├── tree1.dae
│ │ └── tree2.dae
│ └── index.html
├── basic
│ └── index.html
└── index.html
├── lib
├── GamepadButtonEvent.js
└── GamepadButton.js
├── tests
├── .jshintrc
├── karma.conf.js
├── __init.test.js
├── helpers.js
└── gamepad-controls.test.js
├── browser.js
├── .jshintrc
├── LICENSE
├── package.json
├── dist
├── aframe-gamepad-controls.min.js
└── aframe-gamepad-controls.js
├── README.md
└── gamepad-controls.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .DS_Store
3 | .gh-pages
4 |
--------------------------------------------------------------------------------
/examples/scene/assets/peach-gradient-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donmccurdy/aframe-gamepad-controls/master/examples/scene/assets/peach-gradient-1.jpg
--------------------------------------------------------------------------------
/examples/scene/assets/tex/shadow-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donmccurdy/aframe-gamepad-controls/master/examples/scene/assets/tex/shadow-circle.png
--------------------------------------------------------------------------------
/examples/scene/assets/321103__nsstudios__blip1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donmccurdy/aframe-gamepad-controls/master/examples/scene/assets/321103__nsstudios__blip1.wav
--------------------------------------------------------------------------------
/lib/GamepadButtonEvent.js:
--------------------------------------------------------------------------------
1 | function GamepadButtonEvent (type, index, details) {
2 | this.type = type;
3 | this.index = index;
4 | this.pressed = details.pressed;
5 | this.value = details.value;
6 | }
7 |
8 | module.exports = GamepadButtonEvent;
9 |
--------------------------------------------------------------------------------
/tests/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../.jshintrc",
3 | "globals" : {
4 | "it" : false,
5 | "describe" : false,
6 | "expect" : false,
7 | "beforeEach" : false,
8 | "afterEach" : false,
9 | "assert" : false,
10 | "spyOn" : false
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/browser.js:
--------------------------------------------------------------------------------
1 |
2 | // Browser distrubution of the A-Frame component.
3 | (function (AFRAME) {
4 | if (!AFRAME) {
5 | console.error('Component attempted to register before AFRAME was available.');
6 | return;
7 | }
8 |
9 | (AFRAME.aframeCore || AFRAME).registerComponent('gamepad-controls', require('./gamepad-controls'));
10 |
11 | }(window.AFRAME));
12 |
--------------------------------------------------------------------------------
/lib/GamepadButton.js:
--------------------------------------------------------------------------------
1 | module.exports = Object.assign(function GamepadButton () {}, {
2 | FACE_1: 0,
3 | FACE_2: 1,
4 | FACE_3: 2,
5 | FACE_4: 3,
6 |
7 | L_SHOULDER_1: 4,
8 | R_SHOULDER_1: 5,
9 | L_SHOULDER_2: 6,
10 | R_SHOULDER_2: 7,
11 |
12 | SELECT: 8,
13 | START: 9,
14 |
15 | DPAD_UP: 12,
16 | DPAD_DOWN: 13,
17 | DPAD_LEFT: 14,
18 | DPAD_RIGHT: 15,
19 |
20 | VENDOR: 16,
21 | });
22 |
--------------------------------------------------------------------------------
/examples/basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "THREE": false,
4 | "window": false,
5 | "document": false,
6 | "require": false,
7 | "console": false,
8 | "module": false
9 | },
10 | "bitwise": false,
11 | "browser": true,
12 | "eqeqeq": true,
13 | "esnext": true,
14 | "expr": true,
15 | "forin": true,
16 | "immed": true,
17 | "latedef": "nofunc",
18 | "laxbreak": true,
19 | "maxlen": 100,
20 | "newcap": true,
21 | "noarg": true,
22 | "noempty": true,
23 | "noyield": true,
24 | "quotmark": "single",
25 | "smarttabs": false,
26 | "trailing": true,
27 | "undef": true,
28 | "unused": true,
29 | "white": false
30 | }
31 |
--------------------------------------------------------------------------------
/tests/karma.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = function (config) {
3 | config.set({
4 | basePath: '../',
5 | browserify: {
6 | paths: ['./']
7 | },
8 | browsers: ['firefox_latest'],
9 | customLaunchers: {
10 | firefox_latest: {
11 | base: 'FirefoxNightly',
12 | prefs: { /* empty */ }
13 | }
14 | },
15 | client: {
16 | captureConsole: true,
17 | mocha: {ui: 'bdd'}
18 | },
19 | envPreprocessor: [
20 | 'TEST_ENV'
21 | ],
22 | files: [
23 | 'tests/**/*.test.js',
24 | ],
25 | frameworks: ['mocha', 'sinon-chai', 'chai-shallow-deep-equal', 'browserify'],
26 | preprocessors: {
27 | 'tests/**/*.js': ['browserify']
28 | },
29 | reporters: ['mocha']
30 | });
31 | };
32 |
--------------------------------------------------------------------------------
/tests/__init.test.js:
--------------------------------------------------------------------------------
1 | /* global sinon, setup, teardown */
2 |
3 | /**
4 | * __init.test.js is run before every test case.
5 | */
6 | window.debug = true;
7 |
8 | var AScene = require('aframe').AScene;
9 |
10 | beforeEach(function () {
11 | this.sinon = sinon.sandbox.create();
12 | // Stub to not create a WebGL context since Travis CI runs headless.
13 | this.sinon.stub(AScene.prototype, 'attachedCallback');
14 | });
15 |
16 | afterEach(function () {
17 | // Clean up any attached elements.
18 | ['canvas', 'a-assets', 'a-scene'].forEach(function (tagName) {
19 | var els = document.querySelectorAll(tagName);
20 | for (var i = 0; i < els.length; i++) {
21 | els[i].parentNode.removeChild(els[i]);
22 | }
23 | });
24 | AScene.scene = null;
25 |
26 | this.sinon.restore();
27 | });
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Don McCurdy
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A-Frame Gamepad Controls • Examples
6 |
7 |
24 |
25 |
26 | A-Frame Gamepad Controls
27 | Examples
28 |
29 | Basic
30 | Scene
31 |
32 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/helpers.js:
--------------------------------------------------------------------------------
1 | /* global suite */
2 |
3 | /**
4 | * Helper method to create a scene, create an entity, add entity to scene,
5 | * add scene to document.
6 | *
7 | * @returns {object} An `` element.
8 | */
9 | module.exports.entityFactory = function () {
10 | var scene = document.createElement('a-scene');
11 | var entity = document.createElement('a-entity');
12 | scene.appendChild(entity);
13 | document.body.appendChild(scene);
14 | return entity;
15 | };
16 |
17 | /**
18 | * Creates and attaches a mixin element (and an `` element if necessary).
19 | *
20 | * @param {string} id - ID of mixin.
21 | * @param {object} obj - Map of component names to attribute values.
22 | * @returns {object} An attached `` element.
23 | */
24 | module.exports.mixinFactory = function (id, obj) {
25 | var mixinEl = document.createElement('a-mixin');
26 | mixinEl.setAttribute('id', id);
27 | Object.keys(obj).forEach(function (componentName) {
28 | mixinEl.setAttribute(componentName, obj[componentName]);
29 | });
30 |
31 | var assetsEl = document.querySelector('a-assets');
32 | if (!assetsEl) {
33 | assetsEl = document.createElement('a-assets');
34 | document.body.appendChild(assetsEl);
35 | }
36 | assetsEl.appendChild(mixinEl);
37 |
38 | return mixinEl;
39 | };
40 |
41 | /**
42 | * Test that is only run locally and is skipped on CI.
43 | */
44 | module.exports.getSkipCISuite = function () {
45 | if (window.__env__.TEST_ENV === 'ci') {
46 | return suite.skip;
47 | } else {
48 | return suite;
49 | }
50 | };
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-gamepad-controls",
3 | "version": "0.6.0",
4 | "description": "Gamepad controls for A-Frame.",
5 | "main": "gamepad-controls.js",
6 | "config": {
7 | "demo_port": 8000
8 | },
9 | "scripts": {
10 | "dev": "budo browser.js:bundle.js --dir examples --port $npm_package_config_demo_port --live",
11 | "dist": "webpack browser.js dist/aframe-gamepad-controls.js && webpack -p browser.js dist/aframe-gamepad-controls.min.js",
12 | "postpublish": "npm run dist",
13 | "test": "karma start ./tests/karma.conf.js",
14 | "preversion": "karma start ./tests/karma.conf.js --single-run",
15 | "version": "npm run dist && git add -A dist",
16 | "postversion": "git push && git push --tags && npm publish"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/donmccurdy/aframe-gamepad-controls.git"
21 | },
22 | "keywords": [
23 | "aframe",
24 | "aframe-component",
25 | "layout",
26 | "aframe-vr",
27 | "vr",
28 | "aframe-layout",
29 | "mozvr",
30 | "webvr",
31 | "gamepad",
32 | "controller",
33 | "joystick"
34 | ],
35 | "author": "Don McCurdy ",
36 | "license": "MIT",
37 | "bugs": {
38 | "url": "https://github.com/donmccurdy/aframe-gamepad-controls/issues"
39 | },
40 | "homepage": "https://github.com/donmccurdy/aframe-gamepad-controls#readme",
41 | "dependencies": {},
42 | "peerDependencies": {
43 | "aframe": ">=0.5.0"
44 | },
45 | "devDependencies": {
46 | "aframe": ">=0.5.0",
47 | "browserify": "^12.0.1",
48 | "browserify-css": "^0.8.3",
49 | "budo": "^7.1.0",
50 | "chai": "^3.4.1",
51 | "chai-shallow-deep-equal": "^1.3.0",
52 | "karma": "^0.13.15",
53 | "karma-browserify": "^4.4.2",
54 | "karma-chai-shallow-deep-equal": "0.0.4",
55 | "karma-firefox-launcher": "^0.1.7",
56 | "karma-mocha": "^0.2.1",
57 | "karma-mocha-reporter": "^1.1.3",
58 | "karma-sinon-chai": "^1.1.0",
59 | "mocha": "^2.3.4",
60 | "webpack": "^1.12.9"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/examples/scene/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/tests/gamepad-controls.test.js:
--------------------------------------------------------------------------------
1 | var AFRAME = require('aframe');
2 | var component = require('../gamepad-controls');
3 | var entityFactory = require('./helpers').entityFactory;
4 |
5 | AFRAME.registerComponent('gamepad-controls', component);
6 |
7 | describe('Gamepad Controls', function () {
8 |
9 | /*******************************************************************
10 | * Setup
11 | */
12 |
13 | var GamepadButton = component.GamepadButton,
14 | EPS = 1e-6;
15 |
16 | var gamepad, ctrl;
17 |
18 | beforeEach(function () {
19 | // Mock gamepad
20 | gamepad = {
21 | axes: [0, 0, 0, 0],
22 | buttons: '.................'.split('.').map(function () {
23 | return { pressed: 0, value: 0 };
24 | }),
25 | connected: true,
26 | id: 'test-gamepad'
27 | };
28 | this.sinon.stub(navigator, 'getGamepads').returns([gamepad]);
29 | });
30 |
31 | beforeEach(function (done) {
32 | this.el = entityFactory();
33 | this.el.setAttribute('gamepad-controls', '');
34 | this.el.addEventListener('loaded', function () {
35 | ctrl = this.el.components['gamepad-controls'];
36 | done();
37 | }.bind(this));
38 | });
39 |
40 | /*******************************************************************
41 | * Tests
42 | */
43 |
44 | describe('Accessors', function () {
45 | it('detects a gamepad', function () {
46 | expect(ctrl.getGamepad()).to.equal(gamepad);
47 | expect(ctrl.isConnected()).to.be.true;
48 | });
49 |
50 | it('returns gamepad ID', function () {
51 | expect(ctrl.getID()).to.equal('test-gamepad');
52 | });
53 |
54 | it('returns joystick state', function () {
55 | var joystick0 = ctrl.getJoystick(0);
56 | expect(joystick0.x).to.equal(0);
57 | expect(joystick0.y).to.equal(0);
58 | });
59 |
60 | it('returns dpad state', function () {
61 | var dpad = ctrl.getDpad();
62 | expect(dpad.x).to.equal(0);
63 | expect(dpad.y).to.equal(0);
64 | });
65 | });
66 |
67 | describe('Movement', function () {
68 | it('moves object up/down/right/left with stick0', function () {
69 | gamepad.axes = [0, 1, 0, 0];
70 | ctrl.updatePosition(100);
71 | expect(this.el.object3D.position.z).to.equal(0.65);
72 |
73 | gamepad.axes = [1, 0, 0, 0];
74 | ctrl.updatePosition(1);
75 | expect(Math.abs(this.el.object3D.position.x - 0.000065)).to.be.below(EPS);
76 | expect(Math.abs(this.el.object3D.position.z - 0.65637)).to.be.below(EPS);
77 | });
78 |
79 | it('moves object up/down/right/left with dpad', function () {
80 | gamepad.buttons[GamepadButton.DPAD_DOWN] = {pressed: true, value: 1};
81 | ctrl.updatePosition(100);
82 | expect(this.el.object3D.position.z).to.equal(0.65);
83 |
84 | gamepad.buttons[GamepadButton.DPAD_DOWN] = {pressed: false, value: 0};
85 | gamepad.buttons[GamepadButton.DPAD_RIGHT] = {pressed: true, value: 1};
86 | ctrl.updatePosition(1);
87 | expect(Math.abs(this.el.object3D.position.x - 0.000065)).to.be.below(EPS);
88 | expect(Math.abs(this.el.object3D.position.z - 0.65637)).to.be.below(EPS);
89 | });
90 | });
91 |
92 | describe.skip('Rotation', function () {
93 | it('supports lookEnabled:auto (default)', function () {
94 | // Look controls should be enabled only when VR mode is active AND
95 | // there is a 'look-controls' instance on the element.
96 | this.el.setAttribute('gamepad-controls', '');
97 | expect(ctrl.isLookEnabled()).to.be.true;
98 | this.el.components['look-controls'] = true;
99 | expect(ctrl.isLookEnabled()).to.be.true;
100 | document.fullscreen = true;
101 | expect(ctrl.isLookEnabled()).to.be.false;
102 | delete this.el.components['look-controls'];
103 | expect(ctrl.isLookEnabled()).to.be.true;
104 | });
105 |
106 | it('supports lookEnabled:true', function () {
107 | this.el.setAttribute('gamepad-controls', 'lookEnabled: true');
108 | expect(ctrl.isLookEnabled()).to.be.true;
109 | this.el.components['look-controls'] = true;
110 | document.fullscreen = true;
111 | expect(ctrl.isLookEnabled()).to.be.true;
112 | delete this.el.components['look-controls'];
113 | });
114 |
115 | it('supports lookEnabled:false', function () {
116 | this.el.setAttribute('gamepad-controls', 'lookEnabled: false');
117 | expect(ctrl.isLookEnabled()).to.be.false;
118 | });
119 | });
120 |
121 | describe('Movement + Rotation', function () {
122 | it('moves relative to post-rotation heading', function () {
123 | this.el.setAttribute('rotation', {x: 0, y: 90, z: 0});
124 | gamepad.buttons[GamepadButton.DPAD_DOWN] = {pressed: true, value: 1};
125 | ctrl.updatePosition(100);
126 | expect(this.el.object3D.position.z).to.be.within(-EPS, +EPS);
127 | expect(Math.abs(this.el.object3D.position.x - 0.65)).to.be.below(EPS);
128 | });
129 | });
130 |
131 | });
132 |
--------------------------------------------------------------------------------
/dist/aframe-gamepad-controls.min.js:
--------------------------------------------------------------------------------
1 | !function(t){function e(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){!function(t){return t?void(t.aframeCore||t).registerComponent("gamepad-controls",i(1)):void console.error("Component attempted to register before AFRAME was available.")}(window.AFRAME)},function(t,e,i){var n=i(2),o=i(3),a=200,s=Math.PI/2,r=.2;t.exports={GamepadButton:n,schema:{controller:{"default":0,oneOf:[0,1,2,3]},enabled:{"default":!0},movementEnabled:{"default":!0},lookEnabled:{"default":!0},flyEnabled:{"default":!1},invertAxisY:{"default":!1},easing:{"default":20},acceleration:{"default":65},sensitivity:{"default":.04},pitchAxis:{"default":"x",oneOf:["x","y","z"]},yawAxis:{"default":"y",oneOf:["x","y","z"]},rollAxis:{"default":"z",oneOf:["x","y","z"]},debug:{"default":!1}},init:function(){this.velocity=new THREE.Vector3(0,0,0),this.direction=new THREE.Vector3(0,0,0),this.pitch=new THREE.Object3D,this.yaw=new THREE.Object3D,this.yaw.position.y=10,this.yaw.add(this.pitch),this.buttons={},this.getGamepad()||console.warn("Gamepad #%d not found. Connect controller and press any button to continue.",this.data.controller)},tick:function(t,e){this.updateRotation(e),this.updatePosition(e),this.updateButtonState()},updatePosition:function(t){var e=this.data,i=e.acceleration,n=e.easing,o=this.velocity,s=e.rollAxis,d=e.pitchAxis,u=this.el,c=this.getGamepad();if(t>a)return o[s]=0,void(o[d]=0);o[s]-=o[s]*n*t/1e3,o[d]-=o[d]*n*t/1e3;var h=u.getAttribute("position");if(e.enabled&&e.movementEnabled&&c){var l=this.getDpad(),p=l.x||this.getJoystick(0).x,E=l.y||this.getJoystick(0).y;Math.abs(p)>r&&(o[d]+=p*i*t/1e3),Math.abs(E)>r&&(o[s]+=E*i*t/1e3)}var f=this.getMovementVector(t);u.object3D.translateX(f.x),u.object3D.translateY(f.y),u.object3D.translateZ(f.z),u.setAttribute("position",{x:h.x+f.x,y:h.y+f.y,z:h.z+f.z})},getMovementVector:function(t){if(this._getMovementVector)return this._getMovementVector(t);var e=new THREE.Euler(0,0,0,"YXZ"),i=new THREE.Vector3;return this._getMovementVector=function(t){return i.copy(this.el.getAttribute("rotation")),this.direction.copy(this.velocity),this.direction.multiplyScalar(t/1e3),i?(this.data.flyEnabled||(i.x=0),e.set(THREE.Math.degToRad(i.x),THREE.Math.degToRad(i.y),0),this.direction.applyEuler(e),this.direction):this.direction},this._getMovementVector(t)},updateRotation:function(){if(this._updateRotation)return this._updateRotation();var t,e=new THREE.Vector3,i=new THREE.Vector3,n=new THREE.Vector3,o=0,a=0,d=1e-4,u=500;return this._updateRotation=function(){if(this.data.lookEnabled&&this.getGamepad()){if(t=Date.now(),e.copy(this.el.getAttribute("rotation")||e),e.distanceToSquared(i)>d&&e.distanceToSquared(n)>d)return i.copy(e),void(a=t);if(i.copy(e),!(u>t-a)){var c=this.getJoystick(1);Math.abs(c.x)<=r&&(c.x=0),Math.abs(c.y)<=r&&(c.y=0),this.data.invertAxisY&&(c.y=-c.y),a>o&&!c.lengthSq()||(c.multiplyScalar(this.data.sensitivity),this.yaw.rotation.y-=c.x,this.pitch.rotation.x-=c.y,this.pitch.rotation.x=Math.max(-s,Math.min(s,this.pitch.rotation.x)),this.el.setAttribute("rotation",{x:THREE.Math.radToDeg(this.pitch.rotation.x),y:THREE.Math.radToDeg(this.yaw.rotation.y),z:0}),n.copy(this.el.getAttribute("rotation")),o=t)}}},this._updateRotation()},updateButtonState:function(){var t=this.getGamepad();if(this.data.enabled&&t)for(var e=0;e **NOTICE**: This project is no longer maintained. I recommend using `movement-controls` from [A-Frame Extras](https://github.com/donmccurdy/aframe-extras) instead.
4 |
5 | Gamepad controls for A-Frame.
6 |
7 | Demo: https://donmccurdy.github.io/aframe-gamepad-controls/
8 |
9 | ## Overview
10 |
11 | Supports one or more gamepads, attached to an A-Frame scene. When used on a mobile device, `gamepad-controls` can also receive input from a gamepad connected to a host machine, using [ProxyControls.js](https://proxy-controls.donmccurdy.com).
12 |
13 | This component uses the HTML5 [Gamepad API](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API). The underlying API supports Firefox, Chrome, Edge, and Opera ([as of 01/2016](http://caniuse.com/#search=gamepad)). Safari and Internet Explorer do not currently support gamepads.
14 |
15 | ## Usage (script)
16 |
17 | ```html
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ```
34 |
35 | ## Usage (NPM)
36 |
37 | Install NPM module.
38 |
39 | ```
40 | $ npm install aframe-gamepad-controls
41 | ```
42 |
43 | Register `gamepad-controls` component.
44 |
45 | ```javascript
46 | var AFRAME = require('aframe');
47 | var GamepadControls = require('aframe-gamepad-controls');
48 | AFRAME.registerComponent('gamepad-controls', GamepadControls);
49 | ```
50 |
51 | Add markup.
52 |
53 | ```html
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | ```
64 |
65 | ## Development
66 |
67 | To edit the component or play with examples, [download the project](https://github.com/donmccurdy/aframe-gamepad-controls/archive/master.zip) and run:
68 |
69 | ```shell
70 | npm install
71 | npm run dev
72 | ```
73 |
74 | The demo will run at [http://localhost:8000/](http://localhost:8000/).
75 |
76 | ## Mobile / Cardboard + Gamepad
77 |
78 | In Chrome on Android, USB gamepads can be connected with an OTG adapter. For a Nexus 5X, I use [this](http://www.amazon.com/gp/product/B00XHOGEZG). I'm not aware of a way to connect a gamepad in iOS, but definitely let me know if there's something I'm missing.
79 |
80 | The `gamepad-controls` component can also receive remote events with WebRTC, if a `proxy-controls` element is attached to the scene. [More details about ProxyControls.js](https://proxy-controls.donmccurdy.com).
81 |
82 | Example:
83 |
84 | ```html
85 |
86 |
88 |
89 |
90 | ```
91 |
92 | ## Gear VR
93 |
94 | A-Frame supports the Gear VR controller with `gear-vr-controller`, but for Gear VR's without a controller, this component can be used to handle it's trackpad events.
95 |
96 | For a cursor-based setup, `downEvents` must be set to `gamepadbuttondown`. For example:
97 |
98 | ```html
99 |
100 | ```
101 |
102 | ## Button Events
103 |
104 | When buttons are pressed on the gamepad, a [GamepadButtonEvent](https://github.com/donmccurdy/aframe-gamepad-controls/blob/master/lib/GamepadButtonEvent.js) is emitted on the element. Components and entities may listen for these events and modify behavior as needed. Example:
105 |
106 | ```javascript
107 | el.addEventListener('gamepadbuttondown', function (e) {
108 | console.log('Button "%d" has been pressed.', e.index);
109 | });
110 | ```
111 |
112 | **GamepadButtonEvent:**
113 |
114 | Property | Type | Description
115 | ---------|---------|--------------
116 | type | string | Either `gamepadbuttondown` or `gamepadbuttonup`.
117 | index | int | Index of the button affected, 0..N.
118 | pressed | boolean | Whether or not the button is currently pressed.
119 | value | float | Distance the button was pressed, if applicable. Value will be 0 or 1 in most cases, but may return a float on the interval [0..1] for trigger-like buttons.
120 |
121 | **Markup-only Binding:**
122 |
123 | For convenience, additional events are fired including the button index, providing a way to bind events to specific buttons using only markup. To play `pew-pew.wav` when `Button 7` is pressed (right trigger on an Xbox controller), you might do this:
124 |
125 | ```html
126 |
129 |
130 | ```
131 |
132 | Finally, your code may call the `gamepad-controls` component directly to request the state of a button, as a [GamepadButton](https://developer.mozilla.org/en-US/docs/Web/API/GamepadButton) instance:
133 |
134 | ```javascript
135 | el.components['gamepad-controls'].getButton(index);
136 | // Returns a GamepadButton instance.
137 | ```
138 |
139 | ## Options
140 |
141 | Property | Default | Description
142 | ------------------|---------|-------------
143 | controller | 0 | Which controller (0..3) the object should be attached to.
144 | enabled | true | Enables all events on this controller.
145 | movementEnabled | true | Enables movement via the left thumbstick.
146 | lookEnabled | true | `true`, or `false`. Enables view rotation via the right thumbstick.
147 | flyEnabled | false | Whether or not movement is restricted to the entity’s initial plane.
148 | invertAxisY | false | Invert Y axis of view rotation thumbstick.
149 | debug | false | When true, shows debugging info in the console.
150 |
--------------------------------------------------------------------------------
/gamepad-controls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Gamepad controls for A-Frame.
3 | *
4 | * For more information about the Gamepad API, see:
5 | * https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
6 | */
7 |
8 | var GamepadButton = require('./lib/GamepadButton'),
9 | GamepadButtonEvent = require('./lib/GamepadButtonEvent');
10 |
11 | var MAX_DELTA = 200, // ms
12 | PI_2 = Math.PI / 2;
13 |
14 | var JOYSTICK_EPS = 0.2;
15 |
16 | module.exports = {
17 |
18 | /*******************************************************************
19 | * Statics
20 | */
21 |
22 | GamepadButton: GamepadButton,
23 |
24 | /*******************************************************************
25 | * Schema
26 | */
27 |
28 | schema: {
29 | // Controller 0-3
30 | controller: { default: 0, oneOf: [0, 1, 2, 3] },
31 |
32 | // Enable/disable features
33 | enabled: { default: true },
34 | movementEnabled: { default: true },
35 | lookEnabled: { default: true },
36 | flyEnabled: { default: false },
37 | invertAxisY: { default: false },
38 |
39 | // Constants
40 | easing: { default: 20 },
41 | acceleration: { default: 65 },
42 | sensitivity: { default: 0.04 },
43 |
44 | // Control axes
45 | pitchAxis: { default: 'x', oneOf: [ 'x', 'y', 'z' ] },
46 | yawAxis: { default: 'y', oneOf: [ 'x', 'y', 'z' ] },
47 | rollAxis: { default: 'z', oneOf: [ 'x', 'y', 'z' ] },
48 |
49 | // Debugging
50 | debug: { default: false }
51 | },
52 |
53 | /*******************************************************************
54 | * Core
55 | */
56 |
57 | /**
58 | * Called once when component is attached. Generally for initial setup.
59 | */
60 | init: function () {
61 | // Movement
62 | this.velocity = new THREE.Vector3(0, 0, 0);
63 | this.direction = new THREE.Vector3(0, 0, 0);
64 |
65 | // Rotation
66 | this.pitch = new THREE.Object3D();
67 | this.yaw = new THREE.Object3D();
68 | this.yaw.position.y = 10;
69 | this.yaw.add(this.pitch);
70 |
71 | // Button state
72 | this.buttons = {};
73 |
74 | if (!this.getGamepad()) {
75 | console.warn(
76 | 'Gamepad #%d not found. Connect controller and press any button to continue.',
77 | this.data.controller
78 | );
79 | }
80 | },
81 |
82 | /**
83 | * Called on each iteration of main render loop.
84 | */
85 | tick: function (t, dt) {
86 | this.updateRotation(dt);
87 | this.updatePosition(dt);
88 | this.updateButtonState();
89 | },
90 |
91 | /*******************************************************************
92 | * Movement
93 | */
94 |
95 | updatePosition: function (dt) {
96 | var data = this.data;
97 | var acceleration = data.acceleration;
98 | var easing = data.easing;
99 | var velocity = this.velocity;
100 | var rollAxis = data.rollAxis;
101 | var pitchAxis = data.pitchAxis;
102 | var el = this.el;
103 | var gamepad = this.getGamepad();
104 |
105 | // If data has changed or FPS is too low
106 | // we reset the velocity
107 | if (dt > MAX_DELTA) {
108 | velocity[rollAxis] = 0;
109 | velocity[pitchAxis] = 0;
110 | return;
111 | }
112 |
113 | velocity[rollAxis] -= velocity[rollAxis] * easing * dt / 1000;
114 | velocity[pitchAxis] -= velocity[pitchAxis] * easing * dt / 1000;
115 |
116 | var position = el.getAttribute('position');
117 |
118 | if (data.enabled && data.movementEnabled && gamepad) {
119 | var dpad = this.getDpad(),
120 | inputX = dpad.x || this.getJoystick(0).x,
121 | inputY = dpad.y || this.getJoystick(0).y;
122 | if (Math.abs(inputX) > JOYSTICK_EPS) {
123 | velocity[pitchAxis] += inputX * acceleration * dt / 1000;
124 | }
125 | if (Math.abs(inputY) > JOYSTICK_EPS) {
126 | velocity[rollAxis] += inputY * acceleration * dt / 1000;
127 | }
128 | }
129 |
130 | var movementVector = this.getMovementVector(dt);
131 |
132 | el.object3D.translateX(movementVector.x);
133 | el.object3D.translateY(movementVector.y);
134 | el.object3D.translateZ(movementVector.z);
135 |
136 | el.setAttribute('position', {
137 | x: position.x + movementVector.x,
138 | y: position.y + movementVector.y,
139 | z: position.z + movementVector.z
140 | });
141 | },
142 |
143 | getMovementVector: function (dt) {
144 | if (this._getMovementVector) {
145 | return this._getMovementVector(dt);
146 | }
147 |
148 | var euler = new THREE.Euler(0, 0, 0, 'YXZ'),
149 | rotation = new THREE.Vector3();
150 |
151 | this._getMovementVector = function (dt) {
152 | rotation.copy(this.el.getAttribute('rotation'));
153 | this.direction.copy(this.velocity);
154 | this.direction.multiplyScalar(dt / 1000);
155 | if (!rotation) { return this.direction; }
156 | if (!this.data.flyEnabled) { rotation.x = 0; }
157 | euler.set(
158 | THREE.Math.degToRad(rotation.x),
159 | THREE.Math.degToRad(rotation.y),
160 | 0
161 | );
162 | this.direction.applyEuler(euler);
163 | return this.direction;
164 | };
165 |
166 | return this._getMovementVector(dt);
167 | },
168 |
169 | /*******************************************************************
170 | * Rotation
171 | */
172 |
173 | updateRotation: function () {
174 | if (this._updateRotation) {
175 | return this._updateRotation();
176 | }
177 |
178 | var initialRotation = new THREE.Vector3(),
179 | prevInitialRotation = new THREE.Vector3(),
180 | prevFinalRotation = new THREE.Vector3();
181 |
182 | var tCurrent,
183 | tLastLocalActivity = 0,
184 | tLastExternalActivity = 0;
185 |
186 | var ROTATION_EPS = 0.0001,
187 | DEBOUNCE = 500;
188 |
189 | this._updateRotation = function () {
190 | if (!this.data.lookEnabled || !this.getGamepad()) {
191 | return;
192 | }
193 |
194 | tCurrent = Date.now();
195 | initialRotation.copy(this.el.getAttribute('rotation') || initialRotation);
196 |
197 | // If initial rotation for this frame is different from last frame, and
198 | // doesn't match last gamepad state, assume an external component is
199 | // active on this element.
200 | if (initialRotation.distanceToSquared(prevInitialRotation) > ROTATION_EPS
201 | && initialRotation.distanceToSquared(prevFinalRotation) > ROTATION_EPS) {
202 | prevInitialRotation.copy(initialRotation);
203 | tLastExternalActivity = tCurrent;
204 | return;
205 | }
206 |
207 | prevInitialRotation.copy(initialRotation);
208 |
209 | // If external controls have been active in last 500ms, wait.
210 | if (tCurrent - tLastExternalActivity < DEBOUNCE) {
211 | return;
212 | }
213 |
214 | var lookVector = this.getJoystick(1);
215 | if (Math.abs(lookVector.x) <= JOYSTICK_EPS) lookVector.x = 0;
216 | if (Math.abs(lookVector.y) <= JOYSTICK_EPS) lookVector.y = 0;
217 | if (this.data.invertAxisY) lookVector.y = -lookVector.y;
218 |
219 | // If external controls have been active more recently than gamepad,
220 | // and gamepad hasn't moved, don't overwrite the existing rotation.
221 | if (tLastExternalActivity > tLastLocalActivity && !lookVector.lengthSq()) {
222 | return;
223 | }
224 |
225 | lookVector.multiplyScalar(this.data.sensitivity);
226 | this.yaw.rotation.y -= lookVector.x;
227 | this.pitch.rotation.x -= lookVector.y;
228 | this.pitch.rotation.x = Math.max(-PI_2, Math.min(PI_2, this.pitch.rotation.x));
229 |
230 | this.el.setAttribute('rotation', {
231 | x: THREE.Math.radToDeg(this.pitch.rotation.x),
232 | y: THREE.Math.radToDeg(this.yaw.rotation.y),
233 | z: 0
234 | });
235 | prevFinalRotation.copy(this.el.getAttribute('rotation'));
236 | tLastLocalActivity = tCurrent;
237 | };
238 |
239 | return this._updateRotation();
240 | },
241 |
242 | /*******************************************************************
243 | * Button events
244 | */
245 |
246 | updateButtonState: function () {
247 | var gamepad = this.getGamepad();
248 | if (this.data.enabled && gamepad) {
249 |
250 | // Fire DOM events for button state changes.
251 | for (var i = 0; i < gamepad.buttons.length; i++) {
252 | if (gamepad.buttons[i].pressed && !this.buttons[i]) {
253 | this.emit(new GamepadButtonEvent('gamepadbuttondown', i, gamepad.buttons[i]));
254 | } else if (!gamepad.buttons[i].pressed && this.buttons[i]) {
255 | this.emit(new GamepadButtonEvent('gamepadbuttonup', i, gamepad.buttons[i]));
256 | }
257 | this.buttons[i] = gamepad.buttons[i].pressed;
258 | }
259 |
260 | } else if (Object.keys(this.buttons)) {
261 | // Reset state if controls are disabled or controller is lost.
262 | this.buttons = {};
263 | }
264 | },
265 |
266 | emit: function (event) {
267 | // Emit original event.
268 | this.el.emit(event.type, event);
269 |
270 | // Emit convenience event, identifying button index.
271 | this.el.emit(
272 | event.type + ':' + event.index,
273 | new GamepadButtonEvent(event.type, event.index, event)
274 | );
275 | },
276 |
277 | /*******************************************************************
278 | * Gamepad state
279 | */
280 |
281 | /**
282 | * Returns the Gamepad instance attached to the component. If connected,
283 | * a proxy-controls component may provide access to Gamepad input from a
284 | * remote device.
285 | *
286 | * @return {Gamepad}
287 | */
288 | getGamepad: function () {
289 | var localGamepad = navigator.getGamepads
290 | && navigator.getGamepads()[this.data.controller],
291 | proxyControls = this.el.sceneEl.components['proxy-controls'],
292 | proxyGamepad = proxyControls && proxyControls.isConnected()
293 | && proxyControls.getGamepad(this.data.controller);
294 | return proxyGamepad || localGamepad;
295 | },
296 |
297 | /**
298 | * Returns the state of the given button.
299 | * @param {number} index The button (0-N) for which to find state.
300 | * @return {GamepadButton}
301 | */
302 | getButton: function (index) {
303 | return this.getGamepad().buttons[index];
304 | },
305 |
306 | /**
307 | * Returns state of the given axis. Axes are labelled 0-N, where 0-1 will
308 | * represent X/Y on the first joystick, and 2-3 X/Y on the second.
309 | * @param {number} index The axis (0-N) for which to find state.
310 | * @return {number} On the interval [-1,1].
311 | */
312 | getAxis: function (index) {
313 | return this.getGamepad().axes[index];
314 | },
315 |
316 | /**
317 | * Returns the state of the given joystick (0 or 1) as a THREE.Vector2.
318 | * @param {number} id The joystick (0, 1) for which to find state.
319 | * @return {THREE.Vector2}
320 | */
321 | getJoystick: function (index) {
322 | var gamepad = this.getGamepad();
323 | switch (index) {
324 | case 0: return new THREE.Vector2(gamepad.axes[0], gamepad.axes[1]);
325 | case 1: return new THREE.Vector2(gamepad.axes[2], gamepad.axes[3]);
326 | default: throw new Error('Unexpected joystick index "%d".', index);
327 | }
328 | },
329 |
330 | /**
331 | * Returns the state of the dpad as a THREE.Vector2.
332 | * @return {THREE.Vector2}
333 | */
334 | getDpad: function () {
335 | var gamepad = this.getGamepad();
336 | if (!gamepad.buttons[GamepadButton.DPAD_RIGHT]) {
337 | return new THREE.Vector2();
338 | }
339 | return new THREE.Vector2(
340 | (gamepad.buttons[GamepadButton.DPAD_RIGHT].pressed ? 1 : 0)
341 | + (gamepad.buttons[GamepadButton.DPAD_LEFT].pressed ? -1 : 0),
342 | (gamepad.buttons[GamepadButton.DPAD_UP].pressed ? -1 : 0)
343 | + (gamepad.buttons[GamepadButton.DPAD_DOWN].pressed ? 1 : 0)
344 | );
345 | },
346 |
347 | /**
348 | * Returns true if the gamepad is currently connected to the system.
349 | * @return {boolean}
350 | */
351 | isConnected: function () {
352 | var gamepad = this.getGamepad();
353 | return !!(gamepad && gamepad.connected);
354 | },
355 |
356 | /**
357 | * Returns a string containing some information about the controller. Result
358 | * may vary across browsers, for a given controller.
359 | * @return {string}
360 | */
361 | getID: function () {
362 | return this.getGamepad().id;
363 | }
364 | };
365 |
--------------------------------------------------------------------------------
/dist/aframe-gamepad-controls.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // The module cache
3 | /******/ var installedModules = {};
4 |
5 | /******/ // The require function
6 | /******/ function __webpack_require__(moduleId) {
7 |
8 | /******/ // Check if module is in cache
9 | /******/ if(installedModules[moduleId])
10 | /******/ return installedModules[moduleId].exports;
11 |
12 | /******/ // Create a new module (and put it into the cache)
13 | /******/ var module = installedModules[moduleId] = {
14 | /******/ exports: {},
15 | /******/ id: moduleId,
16 | /******/ loaded: false
17 | /******/ };
18 |
19 | /******/ // Execute the module function
20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 |
22 | /******/ // Flag the module as loaded
23 | /******/ module.loaded = true;
24 |
25 | /******/ // Return the exports of the module
26 | /******/ return module.exports;
27 | /******/ }
28 |
29 |
30 | /******/ // expose the modules object (__webpack_modules__)
31 | /******/ __webpack_require__.m = modules;
32 |
33 | /******/ // expose the module cache
34 | /******/ __webpack_require__.c = installedModules;
35 |
36 | /******/ // __webpack_public_path__
37 | /******/ __webpack_require__.p = "";
38 |
39 | /******/ // Load entry module and return exports
40 | /******/ return __webpack_require__(0);
41 | /******/ })
42 | /************************************************************************/
43 | /******/ ([
44 | /* 0 */
45 | /***/ function(module, exports, __webpack_require__) {
46 |
47 |
48 | // Browser distrubution of the A-Frame component.
49 | (function (AFRAME) {
50 | if (!AFRAME) {
51 | console.error('Component attempted to register before AFRAME was available.');
52 | return;
53 | }
54 |
55 | (AFRAME.aframeCore || AFRAME).registerComponent('gamepad-controls', __webpack_require__(1));
56 |
57 | }(window.AFRAME));
58 |
59 |
60 | /***/ },
61 | /* 1 */
62 | /***/ function(module, exports, __webpack_require__) {
63 |
64 | /**
65 | * Gamepad controls for A-Frame.
66 | *
67 | * For more information about the Gamepad API, see:
68 | * https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
69 | */
70 |
71 | var GamepadButton = __webpack_require__(2),
72 | GamepadButtonEvent = __webpack_require__(3);
73 |
74 | var MAX_DELTA = 200, // ms
75 | PI_2 = Math.PI / 2;
76 |
77 | var JOYSTICK_EPS = 0.2;
78 |
79 | module.exports = {
80 |
81 | /*******************************************************************
82 | * Statics
83 | */
84 |
85 | GamepadButton: GamepadButton,
86 |
87 | /*******************************************************************
88 | * Schema
89 | */
90 |
91 | schema: {
92 | // Controller 0-3
93 | controller: { default: 0, oneOf: [0, 1, 2, 3] },
94 |
95 | // Enable/disable features
96 | enabled: { default: true },
97 | movementEnabled: { default: true },
98 | lookEnabled: { default: true },
99 | flyEnabled: { default: false },
100 | invertAxisY: { default: false },
101 |
102 | // Constants
103 | easing: { default: 20 },
104 | acceleration: { default: 65 },
105 | sensitivity: { default: 0.04 },
106 |
107 | // Control axes
108 | pitchAxis: { default: 'x', oneOf: [ 'x', 'y', 'z' ] },
109 | yawAxis: { default: 'y', oneOf: [ 'x', 'y', 'z' ] },
110 | rollAxis: { default: 'z', oneOf: [ 'x', 'y', 'z' ] },
111 |
112 | // Debugging
113 | debug: { default: false }
114 | },
115 |
116 | /*******************************************************************
117 | * Core
118 | */
119 |
120 | /**
121 | * Called once when component is attached. Generally for initial setup.
122 | */
123 | init: function () {
124 | // Movement
125 | this.velocity = new THREE.Vector3(0, 0, 0);
126 | this.direction = new THREE.Vector3(0, 0, 0);
127 |
128 | // Rotation
129 | this.pitch = new THREE.Object3D();
130 | this.yaw = new THREE.Object3D();
131 | this.yaw.position.y = 10;
132 | this.yaw.add(this.pitch);
133 |
134 | // Button state
135 | this.buttons = {};
136 |
137 | if (!this.getGamepad()) {
138 | console.warn(
139 | 'Gamepad #%d not found. Connect controller and press any button to continue.',
140 | this.data.controller
141 | );
142 | }
143 | },
144 |
145 | /**
146 | * Called on each iteration of main render loop.
147 | */
148 | tick: function (t, dt) {
149 | this.updateRotation(dt);
150 | this.updatePosition(dt);
151 | this.updateButtonState();
152 | },
153 |
154 | /*******************************************************************
155 | * Movement
156 | */
157 |
158 | updatePosition: function (dt) {
159 | var data = this.data;
160 | var acceleration = data.acceleration;
161 | var easing = data.easing;
162 | var velocity = this.velocity;
163 | var rollAxis = data.rollAxis;
164 | var pitchAxis = data.pitchAxis;
165 | var el = this.el;
166 | var gamepad = this.getGamepad();
167 |
168 | // If data has changed or FPS is too low
169 | // we reset the velocity
170 | if (dt > MAX_DELTA) {
171 | velocity[rollAxis] = 0;
172 | velocity[pitchAxis] = 0;
173 | return;
174 | }
175 |
176 | velocity[rollAxis] -= velocity[rollAxis] * easing * dt / 1000;
177 | velocity[pitchAxis] -= velocity[pitchAxis] * easing * dt / 1000;
178 |
179 | var position = el.getAttribute('position');
180 |
181 | if (data.enabled && data.movementEnabled && gamepad) {
182 | var dpad = this.getDpad(),
183 | inputX = dpad.x || this.getJoystick(0).x,
184 | inputY = dpad.y || this.getJoystick(0).y;
185 | if (Math.abs(inputX) > JOYSTICK_EPS) {
186 | velocity[pitchAxis] += inputX * acceleration * dt / 1000;
187 | }
188 | if (Math.abs(inputY) > JOYSTICK_EPS) {
189 | velocity[rollAxis] += inputY * acceleration * dt / 1000;
190 | }
191 | }
192 |
193 | var movementVector = this.getMovementVector(dt);
194 |
195 | el.object3D.translateX(movementVector.x);
196 | el.object3D.translateY(movementVector.y);
197 | el.object3D.translateZ(movementVector.z);
198 |
199 | el.setAttribute('position', {
200 | x: position.x + movementVector.x,
201 | y: position.y + movementVector.y,
202 | z: position.z + movementVector.z
203 | });
204 | },
205 |
206 | getMovementVector: function (dt) {
207 | if (this._getMovementVector) {
208 | return this._getMovementVector(dt);
209 | }
210 |
211 | var euler = new THREE.Euler(0, 0, 0, 'YXZ'),
212 | rotation = new THREE.Vector3();
213 |
214 | this._getMovementVector = function (dt) {
215 | rotation.copy(this.el.getAttribute('rotation'));
216 | this.direction.copy(this.velocity);
217 | this.direction.multiplyScalar(dt / 1000);
218 | if (!rotation) { return this.direction; }
219 | if (!this.data.flyEnabled) { rotation.x = 0; }
220 | euler.set(
221 | THREE.Math.degToRad(rotation.x),
222 | THREE.Math.degToRad(rotation.y),
223 | 0
224 | );
225 | this.direction.applyEuler(euler);
226 | return this.direction;
227 | };
228 |
229 | return this._getMovementVector(dt);
230 | },
231 |
232 | /*******************************************************************
233 | * Rotation
234 | */
235 |
236 | updateRotation: function () {
237 | if (this._updateRotation) {
238 | return this._updateRotation();
239 | }
240 |
241 | var initialRotation = new THREE.Vector3(),
242 | prevInitialRotation = new THREE.Vector3(),
243 | prevFinalRotation = new THREE.Vector3();
244 |
245 | var tCurrent,
246 | tLastLocalActivity = 0,
247 | tLastExternalActivity = 0;
248 |
249 | var ROTATION_EPS = 0.0001,
250 | DEBOUNCE = 500;
251 |
252 | this._updateRotation = function () {
253 | if (!this.data.lookEnabled || !this.getGamepad()) {
254 | return;
255 | }
256 |
257 | tCurrent = Date.now();
258 | initialRotation.copy(this.el.getAttribute('rotation') || initialRotation);
259 |
260 | // If initial rotation for this frame is different from last frame, and
261 | // doesn't match last gamepad state, assume an external component is
262 | // active on this element.
263 | if (initialRotation.distanceToSquared(prevInitialRotation) > ROTATION_EPS
264 | && initialRotation.distanceToSquared(prevFinalRotation) > ROTATION_EPS) {
265 | prevInitialRotation.copy(initialRotation);
266 | tLastExternalActivity = tCurrent;
267 | return;
268 | }
269 |
270 | prevInitialRotation.copy(initialRotation);
271 |
272 | // If external controls have been active in last 500ms, wait.
273 | if (tCurrent - tLastExternalActivity < DEBOUNCE) {
274 | return;
275 | }
276 |
277 | var lookVector = this.getJoystick(1);
278 | if (Math.abs(lookVector.x) <= JOYSTICK_EPS) lookVector.x = 0;
279 | if (Math.abs(lookVector.y) <= JOYSTICK_EPS) lookVector.y = 0;
280 | if (this.data.invertAxisY) lookVector.y = -lookVector.y;
281 |
282 | // If external controls have been active more recently than gamepad,
283 | // and gamepad hasn't moved, don't overwrite the existing rotation.
284 | if (tLastExternalActivity > tLastLocalActivity && !lookVector.lengthSq()) {
285 | return;
286 | }
287 |
288 | lookVector.multiplyScalar(this.data.sensitivity);
289 | this.yaw.rotation.y -= lookVector.x;
290 | this.pitch.rotation.x -= lookVector.y;
291 | this.pitch.rotation.x = Math.max(-PI_2, Math.min(PI_2, this.pitch.rotation.x));
292 |
293 | this.el.setAttribute('rotation', {
294 | x: THREE.Math.radToDeg(this.pitch.rotation.x),
295 | y: THREE.Math.radToDeg(this.yaw.rotation.y),
296 | z: 0
297 | });
298 | prevFinalRotation.copy(this.el.getAttribute('rotation'));
299 | tLastLocalActivity = tCurrent;
300 | };
301 |
302 | return this._updateRotation();
303 | },
304 |
305 | /*******************************************************************
306 | * Button events
307 | */
308 |
309 | updateButtonState: function () {
310 | var gamepad = this.getGamepad();
311 | if (this.data.enabled && gamepad) {
312 |
313 | // Fire DOM events for button state changes.
314 | for (var i = 0; i < gamepad.buttons.length; i++) {
315 | if (gamepad.buttons[i].pressed && !this.buttons[i]) {
316 | this.emit(new GamepadButtonEvent('gamepadbuttondown', i, gamepad.buttons[i]));
317 | } else if (!gamepad.buttons[i].pressed && this.buttons[i]) {
318 | this.emit(new GamepadButtonEvent('gamepadbuttonup', i, gamepad.buttons[i]));
319 | }
320 | this.buttons[i] = gamepad.buttons[i].pressed;
321 | }
322 |
323 | } else if (Object.keys(this.buttons)) {
324 | // Reset state if controls are disabled or controller is lost.
325 | this.buttons = {};
326 | }
327 | },
328 |
329 | emit: function (event) {
330 | // Emit original event.
331 | this.el.emit(event.type, event);
332 |
333 | // Emit convenience event, identifying button index.
334 | this.el.emit(
335 | event.type + ':' + event.index,
336 | new GamepadButtonEvent(event.type, event.index, event)
337 | );
338 | },
339 |
340 | /*******************************************************************
341 | * Gamepad state
342 | */
343 |
344 | /**
345 | * Returns the Gamepad instance attached to the component. If connected,
346 | * a proxy-controls component may provide access to Gamepad input from a
347 | * remote device.
348 | *
349 | * @return {Gamepad}
350 | */
351 | getGamepad: function () {
352 | var localGamepad = navigator.getGamepads
353 | && navigator.getGamepads()[this.data.controller],
354 | proxyControls = this.el.sceneEl.components['proxy-controls'],
355 | proxyGamepad = proxyControls && proxyControls.isConnected()
356 | && proxyControls.getGamepad(this.data.controller);
357 | return proxyGamepad || localGamepad;
358 | },
359 |
360 | /**
361 | * Returns the state of the given button.
362 | * @param {number} index The button (0-N) for which to find state.
363 | * @return {GamepadButton}
364 | */
365 | getButton: function (index) {
366 | return this.getGamepad().buttons[index];
367 | },
368 |
369 | /**
370 | * Returns state of the given axis. Axes are labelled 0-N, where 0-1 will
371 | * represent X/Y on the first joystick, and 2-3 X/Y on the second.
372 | * @param {number} index The axis (0-N) for which to find state.
373 | * @return {number} On the interval [-1,1].
374 | */
375 | getAxis: function (index) {
376 | return this.getGamepad().axes[index];
377 | },
378 |
379 | /**
380 | * Returns the state of the given joystick (0 or 1) as a THREE.Vector2.
381 | * @param {number} id The joystick (0, 1) for which to find state.
382 | * @return {THREE.Vector2}
383 | */
384 | getJoystick: function (index) {
385 | var gamepad = this.getGamepad();
386 | switch (index) {
387 | case 0: return new THREE.Vector2(gamepad.axes[0], gamepad.axes[1]);
388 | case 1: return new THREE.Vector2(gamepad.axes[2], gamepad.axes[3]);
389 | default: throw new Error('Unexpected joystick index "%d".', index);
390 | }
391 | },
392 |
393 | /**
394 | * Returns the state of the dpad as a THREE.Vector2.
395 | * @return {THREE.Vector2}
396 | */
397 | getDpad: function () {
398 | var gamepad = this.getGamepad();
399 | if (!gamepad.buttons[GamepadButton.DPAD_RIGHT]) {
400 | return new THREE.Vector2();
401 | }
402 | return new THREE.Vector2(
403 | (gamepad.buttons[GamepadButton.DPAD_RIGHT].pressed ? 1 : 0)
404 | + (gamepad.buttons[GamepadButton.DPAD_LEFT].pressed ? -1 : 0),
405 | (gamepad.buttons[GamepadButton.DPAD_UP].pressed ? -1 : 0)
406 | + (gamepad.buttons[GamepadButton.DPAD_DOWN].pressed ? 1 : 0)
407 | );
408 | },
409 |
410 | /**
411 | * Returns true if the gamepad is currently connected to the system.
412 | * @return {boolean}
413 | */
414 | isConnected: function () {
415 | var gamepad = this.getGamepad();
416 | return !!(gamepad && gamepad.connected);
417 | },
418 |
419 | /**
420 | * Returns a string containing some information about the controller. Result
421 | * may vary across browsers, for a given controller.
422 | * @return {string}
423 | */
424 | getID: function () {
425 | return this.getGamepad().id;
426 | }
427 | };
428 |
429 |
430 | /***/ },
431 | /* 2 */
432 | /***/ function(module, exports) {
433 |
434 | module.exports = Object.assign(function GamepadButton () {}, {
435 | FACE_1: 0,
436 | FACE_2: 1,
437 | FACE_3: 2,
438 | FACE_4: 3,
439 |
440 | L_SHOULDER_1: 4,
441 | R_SHOULDER_1: 5,
442 | L_SHOULDER_2: 6,
443 | R_SHOULDER_2: 7,
444 |
445 | SELECT: 8,
446 | START: 9,
447 |
448 | DPAD_UP: 12,
449 | DPAD_DOWN: 13,
450 | DPAD_LEFT: 14,
451 | DPAD_RIGHT: 15,
452 |
453 | VENDOR: 16,
454 | });
455 |
456 |
457 | /***/ },
458 | /* 3 */
459 | /***/ function(module, exports) {
460 |
461 | function GamepadButtonEvent (type, index, details) {
462 | this.type = type;
463 | this.index = index;
464 | this.pressed = details.pressed;
465 | this.value = details.value;
466 | }
467 |
468 | module.exports = GamepadButtonEvent;
469 |
470 |
471 | /***/ }
472 | /******/ ]);
--------------------------------------------------------------------------------
/examples/scene/assets/tree1.dae:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CINEMA4D 15.064 COLLADA Exporter
6 |
7 | 2015-08-28T05:40:04Z
8 | 2015-08-28T05:40:04Z
9 |
10 | Y_UP
11 |
12 |
13 |
14 | tex/shadow-circle.png
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 0.8 0.8 0.8 1
24 |
25 |
26 | 0.2 0.2 0.2 1
27 |
28 |
29 | 0.5
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 0.0627451 0.396078 0.513725 1
41 |
42 |
43 | 0.2 0.2 0.2 1
44 |
45 |
46 | 0.5
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 0.0235294 0.564706 0.607843 1
58 |
59 |
60 | 0.2 0.2 0.2 1
61 |
62 |
63 | 0.5
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 0.164706 0.72549 0.701961 1
75 |
76 |
77 | 0.2 0.2 0.2 1
78 |
79 |
80 | 0.5
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 0.654902 0.47451 0.415686 1
92 |
93 |
94 | 0.2 0.2 0.2 1
95 |
96 |
97 | 0.5
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | ID13
108 |
109 |
110 |
111 |
112 | ID14
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 1 1 1 1
122 |
123 |
124 | 0.88
125 |
126 |
127 | 1
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | -40 -80.5 40 40 -80.5 40 40 -80.5 -40 -40 -80.5 -40 -40 -77.5711 47.0711 40 -77.5711 47.0711 45 -77.5711 45 47.0711 -77.5711 40 47.0711 -77.5711 -40 45 -77.5711 -45 40 -77.5711 -47.0711 -40 -77.5711 -47.0711 -45 -77.5711 -45 -47.0711 -77.5711 -40 -47.0711 -77.5711 40 -45 -77.5711 45 -40 -70.5 50 40 -70.5 50 47.0711 -70.5 47.0711 50 -70.5 40 50 -70.5 -40 47.0711 -70.5 -47.0711 40 -70.5 -50 -40 -70.5 -50 -47.0711 -70.5 -47.0711 -50 -70.5 -40 -50 -70.5 40 -47.0711 -70.5 47.0711 -40 70.5 50 40 70.5 50 47.0711 70.5 47.0711 50 70.5 40 50 70.5 -40 47.0711 70.5 -47.0711 40 70.5 -50 -40 70.5 -50 -47.0711 70.5 -47.0711 -50 70.5 -40 -50 70.5 40 -47.0711 70.5 47.0711 -40 77.5711 47.0711 40 77.5711 47.0711 45 77.5711 45 47.0711 77.5711 40 47.0711 77.5711 -40 45 77.5711 -45 40 77.5711 -47.0711 -40 77.5711 -47.0711 -45 77.5711 -45 -47.0711 77.5711 -40 -47.0711 77.5711 40 -45 77.5711 45 -40 80.5 40 40 80.5 40 40 80.5 -40 -40 80.5 -40
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | -0.0785214 -0.921027 0.381502 0.0785214 -0.921027 0.381502 0 -0.382683 0.92388 0 0 1 0 0.382683 0.92388 -0.0785214 0.921027 0.381502 0.0785214 0.921027 0.381502 0.156558 -0.912487 0.377964 0.357407 -0.357407 0.862856 0.382683 0 0.92388 0.357407 0.357407 0.862856 0.156558 0.912487 0.377964 0.381502 -0.921027 0.0785214 0.377964 -0.912487 0.156558 0.862856 -0.357407 0.357407 0.92388 0 0.382683 0.862856 0.357407 0.357407 0.377964 0.912487 0.156558 0.381502 0.921027 0.0785214 0.381502 -0.921027 -0.0785214 0.92388 -0.382683 -0 1 0 -0 0.92388 0.382683 -0 0.381502 0.921027 -0.0785214 0.377964 -0.912487 -0.156558 0.862856 -0.357407 -0.357407 0.92388 0 -0.382683 0.862856 0.357407 -0.357407 0.377964 0.912487 -0.156558 0.0785214 -0.921027 -0.381502 0.156558 -0.912487 -0.377964 0.357407 -0.357407 -0.862856 0.382683 0 -0.92388 0.357407 0.357407 -0.862856 0.156558 0.912487 -0.377964 0.0785214 0.921027 -0.381502 -0.0785214 -0.921027 -0.381502 0 -0.382683 -0.92388 0 0 -1 0 0.382683 -0.92388 -0.0785214 0.921027 -0.381502 -0.156558 -0.912487 -0.377964 -0.357407 -0.357407 -0.862856 -0.382683 0 -0.92388 -0.357407 0.357407 -0.862856 -0.156558 0.912487 -0.377964 -0.381502 -0.921027 -0.0785214 -0.377964 -0.912487 -0.156558 -0.862856 -0.357407 -0.357407 -0.92388 0 -0.382683 -0.862856 0.357407 -0.357407 -0.377964 0.912487 -0.156558 -0.381502 0.921027 -0.0785214 -0.381502 -0.921027 0.0785214 -0.92388 -0.382683 -0 -1 0 -0 -0.92388 0.382683 -0 -0.381502 0.921027 0.0785214 -0.377964 -0.912487 0.156558 -0.862856 -0.357407 0.357407 -0.92388 0 0.382683 -0.862856 0.357407 0.357407 -0.377964 0.912487 0.156558 -0.156558 -0.912487 0.377964 -0.357407 -0.357407 0.862856 -0.382683 0 0.92388 -0.357407 0.357407 0.862856 -0.156558 0.912487 0.377964 0 1 -0 0 -1 -0
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | 0 0 0 0.0455526 0.835876 0.0455526 0.835876 0 0 0.0911051 0.835876 0.0911051 0 0.908895 0.835876 0.908895 0 0.954447 0.835876 0.954447 0 1 0.835876 1 0.876907 0 0.917938 0.0455526 0.917938 0.0911051 0.917938 0.908895 0.917938 0.954447 0.876907 1 0.958969 0 1 0.0455526 1 0.0911051 1 0.908895 1 0.954447 0.958969 1 1 1 1 0
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4
194 | 1 1 3 5 1 2 4 0 1 0 0 0 5 2 2 17 2 5 16 2 4 4 2 1 17 3 5 29 3 7 28 3 6 16 3 4 29 4 7 41 4 9 40 4 8 28 4 6 41 6 9 53 6 11 52 5 10 40 5 8 6 7 13 5 1 2 1 1 12 6 8 13 18 8 14 17 8 5 5 8 2 18 9 14 30 9 15 29 9 7 17 9 5 30 10 15 42 10 16 41 10 9 29 10 7 42 11 16 53 6 17 41 6 9 7 12 19 6 13 13 1 12 18 7 14 19 19 14 20 18 14 14 6 14 13 19 15 20 31 15 21 30 15 15 18 15 14 31 16 21 43 16 22 42 16 16 30 16 15 43 18 22 53 18 23 42 17 16 2 19 3 8 19 2 7 12 1 1 12 0 8 20 2 20 20 5 19 20 4 7 20 1 20 21 5 32 21 7 31 21 6 19 21 4 32 22 7 44 22 9 43 22 8 31 22 6 44 23 9 54 23 11 53 18 10 43 18 8 9 24 13 8 19 2 2 19 12 9 25 13 21 25 14 20 25 5 8 25 2 21 26 14 33 26 15 32 26 7 20 26 5 33 27 15 45 27 16 44 27 9 32 27 7 45 28 16 54 23 17 44 23 9 10 29 19 9 30 13 2 29 18 10 31 19 22 31 20 21 31 14 9 31 13 22 32 20 34 32 21 33 32 15 21 32 14 34 33 21 46 33 22 45 33 16 33 33 15 46 35 22 54 35 23 45 34 16 3 36 3 11 36 2 10 29 1 2 29 0 11 37 2 23 37 5 22 37 4 10 37 1 23 38 5 35 38 7 34 38 6 22 38 4 35 39 7 47 39 9 46 39 8 34 39 6 47 40 9 55 40 11 54 35 10 46 35 8 12 41 13 11 36 2 3 36 12 12 42 13 24 42 14 23 42 5 11 42 2 24 43 14 36 43 15 35 43 7 23 43 5 36 44 15 48 44 16 47 44 9 35 44 7 48 45 16 55 40 17 47 40 9 13 46 19 12 47 13 3 46 18 13 48 19 25 48 20 24 48 14 12 48 13 25 49 20 37 49 21 36 49 15 24 49 14 37 50 21 49 50 22 48 50 16 36 50 15 49 52 22 55 52 23 48 51 16 0 53 3 14 53 2 13 46 1 3 46 0 14 54 2 26 54 5 25 54 4 13 54 1 26 55 5 38 55 7 37 55 6 25 55 4 38 56 7 50 56 9 49 56 8 37 56 6 50 57 9 52 57 11 55 52 10 49 52 8 15 58 13 14 53 2 0 53 12 15 59 13 27 59 14 26 59 5 14 59 2 27 60 14 39 60 15 38 60 7 26 60 5 39 61 15 51 61 16 50 61 9 38 61 7 51 62 16 52 57 17 50 57 9 4 0 19 15 63 13 0 0 18 4 64 19 16 64 20 27 64 14 15 64 13 16 65 20 28 65 21 39 65 15 27 65 14 28 66 21 40 66 22 51 66 16 39 66 15 40 5 22 52 5 23 51 67 16 53 68 25 54 68 24 55 68 10 52 68 0 3 69 0 2 69 25 1 69 24 0 69 10
195 |
196 |
197 |
198 |
199 |
200 |
201 | 0 -50 0 0 50 0 10 -50 -0 10 -50 -0 10 50 -0 10 50 -0 8.66025 -50 -5 8.66025 -50 -5 8.66025 50 -5 8.66025 50 -5 5 -50 -8.66025 5 -50 -8.66025 5 50 -8.66025 5 50 -8.66025 6.12323e-16 -50 -10 6.12323e-16 -50 -10 6.12323e-16 50 -10 6.12323e-16 50 -10 -5 -50 -8.66025 -5 -50 -8.66025 -5 50 -8.66025 -5 50 -8.66025 -8.66025 -50 -5 -8.66025 -50 -5 -8.66025 50 -5 -8.66025 50 -5 -10 -50 -1.22465e-15 -10 -50 -1.22465e-15 -10 50 -1.22465e-15 -10 50 -1.22465e-15 -8.66025 -50 5 -8.66025 -50 5 -8.66025 50 5 -8.66025 50 5 -5 -50 8.66025 -5 -50 8.66025 -5 50 8.66025 -5 50 8.66025 -1.83697e-15 -50 10 -1.83697e-15 -50 10 -1.83697e-15 50 10 -1.83697e-15 50 10 5 -50 8.66025 5 -50 8.66025 5 50 8.66025 5 50 8.66025 8.66025 -50 5 8.66025 -50 5 8.66025 50 5 8.66025 50 5
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | 0 -1 -0 1 0 -0 0.866026 0 -0.5 0 1 -0 0.5 0 -0.866026 0 0 -1 -0.5 0 -0.866026 -0.866026 0 -0.5 -1 0 -0 -0.866026 0 0.5 -0.5 0 0.866026 0 0 1 0.5 0 0.866026 0.866026 0 0.5
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | 0.5 0.5 0 0.5 0.0669873 0.75 0 0 0 1 0.0833333 1 0.0833333 0 1 0.5 0.933013 0.75 0.25 0.933013 0.166667 1 0.166667 0 0.75 0.933013 0.5 1 0.25 1 0.25 0 0.333333 1 0.333333 0 0.416667 1 0.416667 0 0.5 0 0.933013 0.25 0.583333 1 0.583333 0 0.0669873 0.25 0.75 0.0669873 0.666667 1 0.666667 0 0.25 0.0669873 0.75 1 0.75 0 0.833333 1 0.833333 0 0.916667 1 0.916667 0 1 1 1 0
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 | 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3
237 | 6 0 2 2 0 1 0 0 0 7 2 6 8 2 5 4 1 4 3 1 3 9 3 8 1 3 0 5 3 7 10 0 9 6 0 2 0 0 0 11 4 11 12 4 10 8 2 5 7 2 6 13 3 12 1 3 0 9 3 8 14 0 13 10 0 9 0 0 0 15 5 15 16 5 14 12 4 10 11 4 11 17 3 13 1 3 0 13 3 12 18 0 12 14 0 13 0 0 0 19 6 17 20 6 16 16 5 14 15 5 15 21 3 9 1 3 0 17 3 13 22 0 8 18 0 12 0 0 0 23 7 19 24 7 18 20 6 16 19 6 17 25 3 2 1 3 0 21 3 9 26 0 7 22 0 8 0 0 0 27 8 20 28 8 13 24 7 18 23 7 19 29 3 1 1 3 0 25 3 2 30 0 21 26 0 7 0 0 0 31 9 23 32 9 22 28 8 13 27 8 20 33 3 24 1 3 0 29 3 1 34 0 25 30 0 21 0 0 0 35 10 27 36 10 26 32 9 22 31 9 23 37 3 28 1 3 0 33 3 24 38 0 20 34 0 25 0 0 0 39 11 30 40 11 29 36 10 26 35 10 27 41 3 20 1 3 0 37 3 28 42 0 28 38 0 20 0 0 0 43 12 32 44 12 31 40 11 29 39 11 30 45 3 25 1 3 0 41 3 20 46 0 24 42 0 28 0 0 0 47 13 34 48 13 33 44 12 31 43 12 32 49 3 21 1 3 0 45 3 25 2 0 1 46 0 24 0 0 0 3 1 36 4 1 35 48 13 33 47 13 34 5 3 7 1 3 0 49 3 21
238 |
239 |
240 |
241 |
242 |
243 |
244 | -50 0 50 50 0 50 -50 0 -50 50 0 -50
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 | 0 1 -0
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 | 0 0 0 1 1 1 1 0
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 | 4
280 | 1 0 3 3 0 2 2 0 1 0 0 0
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 | 0 0 -0
289 | 0 1 0 -0
290 | 1 0 0 0
291 | 0 0 1 -0
292 | 1 1 1
293 |
294 | 0 180 -0
295 | 0 1 0 -0
296 | 1 0 0 0
297 | 0 0 1 -0
298 | 1 1 1
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 | 0 50 -0
311 | 0 1 0 -0
312 | 1 0 0 0
313 | 0 0 1 -0
314 | 1 1 1
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 | 0 0 -0
327 | 0 1 0 -0
328 | 1 0 0 0
329 | 0 0 1 -0
330 | 1 1 1
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
--------------------------------------------------------------------------------
/examples/scene/assets/tree2.dae:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CINEMA4D 15.064 COLLADA Exporter
6 |
7 | 2015-08-28T05:43:48Z
8 | 2015-08-28T05:43:48Z
9 |
10 | Y_UP
11 |
12 |
13 |
14 | tex/shadow-circle.png
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 0.8 0.8 0.8 1
24 |
25 |
26 | 0.2 0.2 0.2 1
27 |
28 |
29 | 0.5
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 0.0627451 0.396078 0.513725 1
41 |
42 |
43 | 0.2 0.2 0.2 1
44 |
45 |
46 | 0.5
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 0.0235294 0.564706 0.607843 1
58 |
59 |
60 | 0.2 0.2 0.2 1
61 |
62 |
63 | 0.5
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 0.164706 0.72549 0.701961 1
75 |
76 |
77 | 0.2 0.2 0.2 1
78 |
79 |
80 | 0.5
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 0.654902 0.47451 0.415686 1
92 |
93 |
94 | 0.2 0.2 0.2 1
95 |
96 |
97 | 0.5
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | ID13
108 |
109 |
110 |
111 |
112 | ID14
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 1 1 1 1
122 |
123 |
124 | 0.88
125 |
126 |
127 | 1
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | -32.0367 -60 32.0367 32.0367 -60 32.0367 32.0367 -60 -32.0367 -32.0367 -60 -32.0367 -32.0367 -57.6676 37.6676 32.0367 -57.6676 37.6676 36.0183 -57.6676 36.0183 37.6676 -57.6676 32.0367 37.6676 -57.6676 -32.0367 36.0183 -57.6676 -36.0183 32.0367 -57.6676 -37.6676 -32.0367 -57.6676 -37.6676 -36.0183 -57.6676 -36.0183 -37.6676 -57.6676 -32.0367 -37.6676 -57.6676 32.0367 -36.0183 -57.6676 36.0183 -32.0367 -52.0367 40 32.0367 -52.0367 40 37.6676 -52.0367 37.6676 40 -52.0367 32.0367 40 -52.0367 -32.0367 37.6676 -52.0367 -37.6676 32.0367 -52.0367 -40 -32.0367 -52.0367 -40 -37.6676 -52.0367 -37.6676 -40 -52.0367 -32.0367 -40 -52.0367 32.0367 -37.6676 -52.0367 37.6676 -32.0367 52.0367 40 32.0367 52.0367 40 37.6676 52.0367 37.6676 40 52.0367 32.0367 40 52.0367 -32.0367 37.6676 52.0367 -37.6676 32.0367 52.0367 -40 -32.0367 52.0367 -40 -37.6676 52.0367 -37.6676 -40 52.0367 -32.0367 -40 52.0367 32.0367 -37.6676 52.0367 37.6676 -32.0367 57.6676 37.6676 32.0367 57.6676 37.6676 36.0183 57.6676 36.0183 37.6676 57.6676 32.0367 37.6676 57.6676 -32.0367 36.0183 57.6676 -36.0183 32.0367 57.6676 -37.6676 -32.0367 57.6676 -37.6676 -36.0183 57.6676 -36.0183 -37.6676 57.6676 -32.0367 -37.6676 57.6676 32.0367 -36.0183 57.6676 36.0183 -32.0367 60 32.0367 32.0367 60 32.0367 32.0367 60 -32.0367 -32.0367 60 -32.0367
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | -0.0785213 -0.921027 0.381502 0.0785213 -0.921027 0.381502 0 -0.382683 0.92388 0 0 1 0 0.382683 0.92388 -0.0785213 0.921027 0.381502 0.0785213 0.921027 0.381502 0.156558 -0.912487 0.377964 0.357407 -0.357407 0.862856 0.382683 0 0.92388 0.357406 0.357407 0.862856 0.156558 0.912487 0.377964 0.381502 -0.921027 0.0785213 0.377964 -0.912487 0.156558 0.862856 -0.357407 0.357407 0.92388 0 0.382683 0.862856 0.357407 0.357407 0.377964 0.912487 0.156558 0.381502 0.921027 0.0785213 0.381502 -0.921027 -0.0785213 0.92388 -0.382683 -0 1 0 -0 0.92388 0.382683 -0 0.381502 0.921027 -0.0785213 0.377964 -0.912487 -0.156558 0.862856 -0.357407 -0.357407 0.92388 0 -0.382683 0.862856 0.357407 -0.357407 0.377964 0.912487 -0.156558 0.0785213 -0.921027 -0.381502 0.156558 -0.912487 -0.377964 0.357406 -0.357407 -0.862856 0.382683 0 -0.92388 0.357407 0.357407 -0.862856 0.156558 0.912487 -0.377964 0.0785213 0.921027 -0.381502 -0.0785213 -0.921027 -0.381502 0 -0.382683 -0.92388 0 0 -1 0 0.382683 -0.92388 -0.0785213 0.921027 -0.381502 -0.156558 -0.912487 -0.377964 -0.357407 -0.357407 -0.862856 -0.382683 0 -0.92388 -0.357406 0.357407 -0.862856 -0.156558 0.912487 -0.377964 -0.381502 -0.921027 -0.0785213 -0.377964 -0.912487 -0.156558 -0.862856 -0.357407 -0.357407 -0.92388 0 -0.382683 -0.862856 0.357407 -0.357407 -0.377964 0.912487 -0.156558 -0.381502 0.921027 -0.0785213 -0.381502 -0.921027 0.0785213 -0.92388 -0.382683 -0 -1 0 -0 -0.92388 0.382683 -0 -0.381502 0.921027 0.0785213 -0.377964 -0.912487 0.156558 -0.862856 -0.357407 0.357407 -0.92388 0 0.382683 -0.862856 0.357407 0.357407 -0.377964 0.912487 0.156558 -0.156558 -0.912487 0.377964 -0.357406 -0.357407 0.862856 -0.382683 0 0.92388 -0.357407 0.357407 0.862856 -0.156558 0.912487 0.377964 0 1 -0 0 -1 -0
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | 0 0 0 0.0484494 0.836663 0.0484494 0.836663 0 0 0.0968987 0.836663 0.0968987 0 0.903101 0.836663 0.903101 0 0.951551 0.836663 0.951551 0 1 0.836663 1 0.877497 0 0.918331 0.0484494 0.918331 0.0968987 0.918331 0.903101 0.918331 0.951551 0.877497 1 0.959166 0 1 0.0484494 1 0.0968987 1 0.903101 1 0.951551 0.959166 1 1 1 1 0
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4
194 | 1 1 3 5 1 2 4 0 1 0 0 0 5 2 2 17 2 5 16 2 4 4 2 1 17 3 5 29 3 7 28 3 6 16 3 4 29 4 7 41 4 9 40 4 8 28 4 6 41 6 9 53 6 11 52 5 10 40 5 8 6 7 13 5 1 2 1 1 12 6 8 13 18 8 14 17 8 5 5 8 2 18 9 14 30 9 15 29 9 7 17 9 5 30 10 15 42 10 16 41 10 9 29 10 7 42 11 16 53 6 17 41 6 9 7 12 19 6 13 13 1 12 18 7 14 19 19 14 20 18 14 14 6 14 13 19 15 20 31 15 21 30 15 15 18 15 14 31 16 21 43 16 22 42 16 16 30 16 15 43 18 22 53 18 23 42 17 16 2 19 3 8 19 2 7 12 1 1 12 0 8 20 2 20 20 5 19 20 4 7 20 1 20 21 5 32 21 7 31 21 6 19 21 4 32 22 7 44 22 9 43 22 8 31 22 6 44 23 9 54 23 11 53 18 10 43 18 8 9 24 13 8 19 2 2 19 12 9 25 13 21 25 14 20 25 5 8 25 2 21 26 14 33 26 15 32 26 7 20 26 5 33 27 15 45 27 16 44 27 9 32 27 7 45 28 16 54 23 17 44 23 9 10 29 19 9 30 13 2 29 18 10 31 19 22 31 20 21 31 14 9 31 13 22 32 20 34 32 21 33 32 15 21 32 14 34 33 21 46 33 22 45 33 16 33 33 15 46 35 22 54 35 23 45 34 16 3 36 3 11 36 2 10 29 1 2 29 0 11 37 2 23 37 5 22 37 4 10 37 1 23 38 5 35 38 7 34 38 6 22 38 4 35 39 7 47 39 9 46 39 8 34 39 6 47 40 9 55 40 11 54 35 10 46 35 8 12 41 13 11 36 2 3 36 12 12 42 13 24 42 14 23 42 5 11 42 2 24 43 14 36 43 15 35 43 7 23 43 5 36 44 15 48 44 16 47 44 9 35 44 7 48 45 16 55 40 17 47 40 9 13 46 19 12 47 13 3 46 18 13 48 19 25 48 20 24 48 14 12 48 13 25 49 20 37 49 21 36 49 15 24 49 14 37 50 21 49 50 22 48 50 16 36 50 15 49 52 22 55 52 23 48 51 16 0 53 3 14 53 2 13 46 1 3 46 0 14 54 2 26 54 5 25 54 4 13 54 1 26 55 5 38 55 7 37 55 6 25 55 4 38 56 7 50 56 9 49 56 8 37 56 6 50 57 9 52 57 11 55 52 10 49 52 8 15 58 13 14 53 2 0 53 12 15 59 13 27 59 14 26 59 5 14 59 2 27 60 14 39 60 15 38 60 7 26 60 5 39 61 15 51 61 16 50 61 9 38 61 7 51 62 16 52 57 17 50 57 9 4 0 19 15 63 13 0 0 18 4 64 19 16 64 20 27 64 14 15 64 13 16 65 20 28 65 21 39 65 15 27 65 14 28 66 21 40 66 22 51 66 16 39 66 15 40 5 22 52 5 23 51 67 16 53 68 25 54 68 24 55 68 10 52 68 0 3 69 0 2 69 25 1 69 24 0 69 10
195 |
196 |
197 |
198 |
199 |
200 |
201 | -18.4211 -34.5 62.1092 18.4211 -34.5 62.1092 18.4211 -34.5 -62.1092 -18.4211 -34.5 -62.1092 -18.4211 -33.1589 65.3469 18.4211 -33.1589 65.3469 20.7105 -33.1589 64.3986 21.6589 -33.1589 62.1092 21.6589 -33.1589 -62.1092 20.7105 -33.1589 -64.3986 18.4211 -33.1589 -65.3469 -18.4211 -33.1589 -65.3469 -20.7105 -33.1589 -64.3986 -21.6589 -33.1589 -62.1092 -21.6589 -33.1589 62.1092 -20.7105 -33.1589 64.3986 -18.4211 -29.9211 66.6881 18.4211 -29.9211 66.6881 21.6589 -29.9211 65.3469 23 -29.9211 62.1092 23 -29.9211 -62.1092 21.6589 -29.9211 -65.3469 18.4211 -29.9211 -66.6881 -18.4211 -29.9211 -66.6881 -21.6589 -29.9211 -65.3469 -23 -29.9211 -62.1092 -23 -29.9211 62.1092 -21.6589 -29.9211 65.3469 -18.4211 29.9211 66.6881 18.4211 29.9211 66.6881 21.6589 29.9211 65.3469 23 29.9211 62.1092 23 29.9211 -62.1092 21.6589 29.9211 -65.3469 18.4211 29.9211 -66.6881 -18.4211 29.9211 -66.6881 -21.6589 29.9211 -65.3469 -23 29.9211 -62.1092 -23 29.9211 62.1092 -21.6589 29.9211 65.3469 -18.4211 33.1589 65.3469 18.4211 33.1589 65.3469 20.7105 33.1589 64.3986 21.6589 33.1589 62.1092 21.6589 33.1589 -62.1092 20.7105 33.1589 -64.3986 18.4211 33.1589 -65.3469 -18.4211 33.1589 -65.3469 -20.7105 33.1589 -64.3986 -21.6589 33.1589 -62.1092 -21.6589 33.1589 62.1092 -20.7105 33.1589 64.3986 -18.4211 34.5 62.1092 18.4211 34.5 62.1092 18.4211 34.5 -62.1092 -18.4211 34.5 -62.1092
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | -0.0785212 -0.921027 0.381502 0.0785212 -0.921027 0.381502 0 -0.382683 0.92388 0 0 1 0 0.382683 0.92388 -0.0785212 0.921027 0.381502 0.0785212 0.921027 0.381502 0.156558 -0.912487 0.377965 0.357406 -0.357406 0.862857 0.382683 0 0.92388 0.357406 0.357406 0.862857 0.156558 0.912487 0.377965 0.381502 -0.921027 0.0785213 0.377965 -0.912487 0.156558 0.862856 -0.357407 0.357407 0.923879 0 0.382684 0.862856 0.357406 0.357407 0.377965 0.912487 0.156558 0.381502 0.921027 0.0785213 0.381502 -0.921027 -0.0785213 0.92388 -0.382683 -0 1 0 -0 0.92388 0.382683 -0 0.381502 0.921027 -0.0785213 0.377965 -0.912487 -0.156558 0.862856 -0.357406 -0.357407 0.923879 0 -0.382684 0.862856 0.357407 -0.357407 0.377965 0.912487 -0.156558 0.0785212 -0.921027 -0.381502 0.156558 -0.912487 -0.377965 0.357406 -0.357406 -0.862857 0.382683 0 -0.92388 0.357406 0.357406 -0.862857 0.156558 0.912487 -0.377965 0.0785212 0.921027 -0.381502 -0.0785212 -0.921027 -0.381502 0 -0.382683 -0.92388 0 0 -1 0 0.382683 -0.92388 -0.0785212 0.921027 -0.381502 -0.156558 -0.912487 -0.377965 -0.357406 -0.357406 -0.862857 -0.382683 0 -0.92388 -0.357406 0.357406 -0.862857 -0.156558 0.912487 -0.377965 -0.381502 -0.921027 -0.0785213 -0.377965 -0.912487 -0.156558 -0.862856 -0.357407 -0.357407 -0.923879 0 -0.382684 -0.862856 0.357406 -0.357407 -0.377965 0.912487 -0.156558 -0.381502 0.921027 -0.0785213 -0.381502 -0.921027 0.0785213 -0.92388 -0.382683 -0 -1 0 -0 -0.92388 0.382683 -0 -0.381502 0.921027 0.0785213 -0.377965 -0.912487 0.156558 -0.862856 -0.357406 0.357407 -0.923879 0 0.382684 -0.862856 0.357407 0.357407 -0.377965 0.912487 0.156558 -0.156558 -0.912487 0.377965 -0.357406 -0.357406 0.862857 -0.382683 0 0.92388 -0.357406 0.357406 0.862857 -0.156558 0.912487 0.377965 0 1 -0 0 -1 -0
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | 0 0 0 0.0484494 0.836663 0.0484494 0.836663 0 0 0.0968987 0.836663 0.0968987 0 0.903101 0.836663 0.903101 0 0.951551 0.836663 0.951551 0 1 0.836663 1 0.877497 0 0.918331 0.0484494 0.918331 0.0968987 0.918331 0.903101 0.918331 0.951551 0.877497 1 0.959166 0 1 0.0484494 1 0.0968987 1 0.903101 1 0.951551 0.959166 1 0.945267 0.0484494 0.945267 0 0.945267 0.0968987 0.945267 0.903101 0.945267 0.951551 0.945267 1 0.95895 0 0.972633 0.0484494 0.972633 0.0968987 0.972633 0.903101 0.972633 0.951551 0.95895 1 0.986317 0 0.986317 1 1 1 1 0
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 | 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4
237 | 1 1 3 5 1 2 4 0 1 0 0 0 5 2 2 17 2 5 16 2 4 4 2 1 17 3 5 29 3 7 28 3 6 16 3 4 29 4 7 41 4 9 40 4 8 28 4 6 41 6 9 53 6 11 52 5 10 40 5 8 6 7 13 5 1 2 1 1 12 6 8 13 18 8 14 17 8 5 5 8 2 18 9 14 30 9 15 29 9 7 17 9 5 30 10 15 42 10 16 41 10 9 29 10 7 42 11 16 53 6 17 41 6 9 7 12 19 6 13 13 1 12 18 7 14 19 19 14 20 18 14 14 6 14 13 19 15 20 31 15 21 30 15 15 18 15 14 31 16 21 43 16 22 42 16 16 30 16 15 43 18 22 53 18 23 42 17 16 2 19 25 8 19 24 7 12 1 1 12 0 8 20 24 20 20 26 19 20 4 7 20 1 20 21 26 32 21 27 31 21 6 19 21 4 32 22 27 44 22 28 43 22 8 31 22 6 44 23 28 54 23 29 53 18 10 43 18 8 9 24 31 8 19 24 2 19 30 9 25 31 21 25 32 20 25 26 8 25 24 21 26 32 33 26 33 32 26 27 20 26 26 33 27 33 45 27 34 44 27 28 32 27 27 45 28 34 54 23 35 44 23 28 10 29 19 9 30 31 2 29 36 10 31 19 22 31 20 21 31 32 9 31 31 22 32 20 34 32 21 33 32 33 21 32 32 34 33 21 46 33 22 45 33 34 33 33 33 46 35 22 54 35 37 45 34 34 3 36 3 11 36 2 10 29 1 2 29 0 11 37 2 23 37 5 22 37 4 10 37 1 23 38 5 35 38 7 34 38 6 22 38 4 35 39 7 47 39 9 46 39 8 34 39 6 47 40 9 55 40 11 54 35 10 46 35 8 12 41 13 11 36 2 3 36 12 12 42 13 24 42 14 23 42 5 11 42 2 24 43 14 36 43 15 35 43 7 23 43 5 36 44 15 48 44 16 47 44 9 35 44 7 48 45 16 55 40 17 47 40 9 13 46 19 12 47 13 3 46 18 13 48 19 25 48 20 24 48 14 12 48 13 25 49 20 37 49 21 36 49 15 24 49 14 37 50 21 49 50 22 48 50 16 36 50 15 49 52 22 55 52 23 48 51 16 0 53 25 14 53 24 13 46 1 3 46 0 14 54 24 26 54 26 25 54 4 13 54 1 26 55 26 38 55 27 37 55 6 25 55 4 38 56 27 50 56 28 49 56 8 37 56 6 50 57 28 52 57 29 55 52 10 49 52 8 15 58 31 14 53 24 0 53 30 15 59 31 27 59 32 26 59 26 14 59 24 27 60 32 39 60 33 38 60 27 26 60 26 39 61 33 51 61 34 50 61 28 38 61 27 51 62 34 52 57 35 50 57 28 4 0 19 15 63 31 0 0 36 4 64 19 16 64 20 27 64 32 15 64 31 16 65 20 28 65 21 39 65 33 27 65 32 28 66 21 40 66 22 51 66 34 39 66 33 40 5 22 52 5 37 51 67 34 53 68 39 54 68 38 55 68 10 52 68 0 3 69 0 2 69 39 1 69 38 0 69 10
238 |
239 |
240 |
241 |
242 |
243 |
244 | -40 -80.5 40 40 -80.5 40 40 -80.5 -40 -40 -80.5 -40 -40 -77.5711 47.0711 40 -77.5711 47.0711 45 -77.5711 45 47.0711 -77.5711 40 47.0711 -77.5711 -40 45 -77.5711 -45 40 -77.5711 -47.0711 -40 -77.5711 -47.0711 -45 -77.5711 -45 -47.0711 -77.5711 -40 -47.0711 -77.5711 40 -45 -77.5711 45 -40 -70.5 50 40 -70.5 50 47.0711 -70.5 47.0711 50 -70.5 40 50 -70.5 -40 47.0711 -70.5 -47.0711 40 -70.5 -50 -40 -70.5 -50 -47.0711 -70.5 -47.0711 -50 -70.5 -40 -50 -70.5 40 -47.0711 -70.5 47.0711 -40 70.5 50 40 70.5 50 47.0711 70.5 47.0711 50 70.5 40 50 70.5 -40 47.0711 70.5 -47.0711 40 70.5 -50 -40 70.5 -50 -47.0711 70.5 -47.0711 -50 70.5 -40 -50 70.5 40 -47.0711 70.5 47.0711 -40 77.5711 47.0711 40 77.5711 47.0711 45 77.5711 45 47.0711 77.5711 40 47.0711 77.5711 -40 45 77.5711 -45 40 77.5711 -47.0711 -40 77.5711 -47.0711 -45 77.5711 -45 -47.0711 77.5711 -40 -47.0711 77.5711 40 -45 77.5711 45 -40 80.5 40 40 80.5 40 40 80.5 -40 -40 80.5 -40
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 | -0.0785214 -0.921027 0.381502 0.0785214 -0.921027 0.381502 0 -0.382683 0.92388 0 0 1 0 0.382683 0.92388 -0.0785214 0.921027 0.381502 0.0785214 0.921027 0.381502 0.156558 -0.912487 0.377964 0.357407 -0.357407 0.862856 0.382683 0 0.92388 0.357407 0.357407 0.862856 0.156558 0.912487 0.377964 0.381502 -0.921027 0.0785214 0.377964 -0.912487 0.156558 0.862856 -0.357407 0.357407 0.92388 0 0.382683 0.862856 0.357407 0.357407 0.377964 0.912487 0.156558 0.381502 0.921027 0.0785214 0.381502 -0.921027 -0.0785214 0.92388 -0.382683 -0 1 0 -0 0.92388 0.382683 -0 0.381502 0.921027 -0.0785214 0.377964 -0.912487 -0.156558 0.862856 -0.357407 -0.357407 0.92388 0 -0.382683 0.862856 0.357407 -0.357407 0.377964 0.912487 -0.156558 0.0785214 -0.921027 -0.381502 0.156558 -0.912487 -0.377964 0.357407 -0.357407 -0.862856 0.382683 0 -0.92388 0.357407 0.357407 -0.862856 0.156558 0.912487 -0.377964 0.0785214 0.921027 -0.381502 -0.0785214 -0.921027 -0.381502 0 -0.382683 -0.92388 0 0 -1 0 0.382683 -0.92388 -0.0785214 0.921027 -0.381502 -0.156558 -0.912487 -0.377964 -0.357407 -0.357407 -0.862856 -0.382683 0 -0.92388 -0.357407 0.357407 -0.862856 -0.156558 0.912487 -0.377964 -0.381502 -0.921027 -0.0785214 -0.377964 -0.912487 -0.156558 -0.862856 -0.357407 -0.357407 -0.92388 0 -0.382683 -0.862856 0.357407 -0.357407 -0.377964 0.912487 -0.156558 -0.381502 0.921027 -0.0785214 -0.381502 -0.921027 0.0785214 -0.92388 -0.382683 -0 -1 0 -0 -0.92388 0.382683 -0 -0.381502 0.921027 0.0785214 -0.377964 -0.912487 0.156558 -0.862856 -0.357407 0.357407 -0.92388 0 0.382683 -0.862856 0.357407 0.357407 -0.377964 0.912487 0.156558 -0.156558 -0.912487 0.377964 -0.357407 -0.357407 0.862856 -0.382683 0 0.92388 -0.357407 0.357407 0.862856 -0.156558 0.912487 0.377964 0 1 -0 0 -1 -0
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 | 0 0 0 0.0455526 0.835876 0.0455526 0.835876 0 0 0.0911051 0.835876 0.0911051 0 0.908895 0.835876 0.908895 0 0.954447 0.835876 0.954447 0 1 0.835876 1 0.876907 0 0.917938 0.0455526 0.917938 0.0911051 0.917938 0.908895 0.917938 0.954447 0.876907 1 0.958969 0 1 0.0455526 1 0.0911051 1 0.908895 1 0.954447 0.958969 1 1 1 1 0
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 | 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4
280 | 1 1 3 5 1 2 4 0 1 0 0 0 5 2 2 17 2 5 16 2 4 4 2 1 17 3 5 29 3 7 28 3 6 16 3 4 29 4 7 41 4 9 40 4 8 28 4 6 41 6 9 53 6 11 52 5 10 40 5 8 6 7 13 5 1 2 1 1 12 6 8 13 18 8 14 17 8 5 5 8 2 18 9 14 30 9 15 29 9 7 17 9 5 30 10 15 42 10 16 41 10 9 29 10 7 42 11 16 53 6 17 41 6 9 7 12 19 6 13 13 1 12 18 7 14 19 19 14 20 18 14 14 6 14 13 19 15 20 31 15 21 30 15 15 18 15 14 31 16 21 43 16 22 42 16 16 30 16 15 43 18 22 53 18 23 42 17 16 2 19 3 8 19 2 7 12 1 1 12 0 8 20 2 20 20 5 19 20 4 7 20 1 20 21 5 32 21 7 31 21 6 19 21 4 32 22 7 44 22 9 43 22 8 31 22 6 44 23 9 54 23 11 53 18 10 43 18 8 9 24 13 8 19 2 2 19 12 9 25 13 21 25 14 20 25 5 8 25 2 21 26 14 33 26 15 32 26 7 20 26 5 33 27 15 45 27 16 44 27 9 32 27 7 45 28 16 54 23 17 44 23 9 10 29 19 9 30 13 2 29 18 10 31 19 22 31 20 21 31 14 9 31 13 22 32 20 34 32 21 33 32 15 21 32 14 34 33 21 46 33 22 45 33 16 33 33 15 46 35 22 54 35 23 45 34 16 3 36 3 11 36 2 10 29 1 2 29 0 11 37 2 23 37 5 22 37 4 10 37 1 23 38 5 35 38 7 34 38 6 22 38 4 35 39 7 47 39 9 46 39 8 34 39 6 47 40 9 55 40 11 54 35 10 46 35 8 12 41 13 11 36 2 3 36 12 12 42 13 24 42 14 23 42 5 11 42 2 24 43 14 36 43 15 35 43 7 23 43 5 36 44 15 48 44 16 47 44 9 35 44 7 48 45 16 55 40 17 47 40 9 13 46 19 12 47 13 3 46 18 13 48 19 25 48 20 24 48 14 12 48 13 25 49 20 37 49 21 36 49 15 24 49 14 37 50 21 49 50 22 48 50 16 36 50 15 49 52 22 55 52 23 48 51 16 0 53 3 14 53 2 13 46 1 3 46 0 14 54 2 26 54 5 25 54 4 13 54 1 26 55 5 38 55 7 37 55 6 25 55 4 38 56 7 50 56 9 49 56 8 37 56 6 50 57 9 52 57 11 55 52 10 49 52 8 15 58 13 14 53 2 0 53 12 15 59 13 27 59 14 26 59 5 14 59 2 27 60 14 39 60 15 38 60 7 26 60 5 39 61 15 51 61 16 50 61 9 38 61 7 51 62 16 52 57 17 50 57 9 4 0 19 15 63 13 0 0 18 4 64 19 16 64 20 27 64 14 15 64 13 16 65 20 28 65 21 39 65 15 27 65 14 28 66 21 40 66 22 51 66 16 39 66 15 40 5 22 52 5 23 51 67 16 53 68 25 54 68 24 55 68 10 52 68 0 3 69 0 2 69 25 1 69 24 0 69 10
281 |
282 |
283 |
284 |
285 |
286 |
287 | 0 -50 0 0 50 0 10 -50 -0 10 -50 -0 10 50 -0 10 50 -0 7.07107 -50 -7.07107 7.07107 -50 -7.07107 7.07107 50 -7.07107 7.07107 50 -7.07107 6.12323e-16 -50 -10 6.12323e-16 -50 -10 6.12323e-16 50 -10 6.12323e-16 50 -10 -7.07107 -50 -7.07107 -7.07107 -50 -7.07107 -7.07107 50 -7.07107 -7.07107 50 -7.07107 -10 -50 -1.22465e-15 -10 -50 -1.22465e-15 -10 50 -1.22465e-15 -10 50 -1.22465e-15 -7.07107 -50 7.07107 -7.07107 -50 7.07107 -7.07107 50 7.07107 -7.07107 50 7.07107 -1.83697e-15 -50 10 -1.83697e-15 -50 10 -1.83697e-15 50 10 -1.83697e-15 50 10 7.07107 -50 7.07107 7.07107 -50 7.07107 7.07107 50 7.07107 7.07107 50 7.07107
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 | 0 -1 -0 1 0 -0 0.707107 0 -0.707107 0 1 -0 0 0 -1 -0.707107 0 -0.707107 -1 0 -0 -0.707107 0 0.707107 0 0 1 0.707107 0 0.707107
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 | 0.5 0.5 0 0.5 0.146447 0.853553 0 0 0 1 0.125 1 0.125 0 1 0.5 0.853553 0.853553 0.5 1 0.25 1 0.25 0 0.375 1 0.375 0 0.5 0 0.853553 0.146447 0.625 1 0.625 0 0.146447 0.146447 0.75 1 0.75 0 0.875 1 0.875 0 1 1 1 0
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 | 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3
323 | 6 0 2 2 0 1 0 0 0 7 2 6 8 2 5 4 1 4 3 1 3 9 3 8 1 3 0 5 3 7 10 0 9 6 0 2 0 0 0 11 4 11 12 4 10 8 2 5 7 2 6 13 3 9 1 3 0 9 3 8 14 0 8 10 0 9 0 0 0 15 5 13 16 5 12 12 4 10 11 4 11 17 3 2 1 3 0 13 3 9 18 0 7 14 0 8 0 0 0 19 6 14 20 6 9 16 5 12 15 5 13 21 3 1 1 3 0 17 3 2 22 0 15 18 0 7 0 0 0 23 7 17 24 7 16 20 6 9 19 6 14 25 3 18 1 3 0 21 3 1 26 0 14 22 0 15 0 0 0 27 8 20 28 8 19 24 7 16 23 7 17 29 3 14 1 3 0 25 3 18 30 0 18 26 0 14 0 0 0 31 9 22 32 9 21 28 8 19 27 8 20 33 3 15 1 3 0 29 3 14 2 0 1 30 0 18 0 0 0 3 1 24 4 1 23 32 9 21 31 9 22 5 3 7 1 3 0 33 3 15
324 |
325 |
326 |
327 |
328 |
329 |
330 | -50 0 50 50 0 50 -50 0 -50 50 0 -50
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 | 0 1 -0
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 | 0 0 0 1 1 1 1 0
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 | 4
366 | 1 0 3 3 0 2 2 0 1 0 0 0
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 | -23.7123 210.709 24.9106
375 | 0 1 0 -0
376 | 1 0 0 0
377 | 0 0 1 -0
378 | 1 1 1
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 | 3.20043 174.503 2.82738
391 | 0 1 0 -0
392 | 1 0 0 0
393 | 0 0 1 -0
394 | 1 1 1
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 | 0 180 -0
407 | 0 1 0 -0
408 | 1 0 0 0
409 | 0 0 1 -0
410 | 1 1 1
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 | 0 50 -0
423 | 0 1 0 -0
424 | 1 0 0 0
425 | 0 0 1 -0
426 | 1 1 1
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 | 0 0 -0
439 | 0 1 0 -0
440 | 1 0 0 0
441 | 0 0 1 -0
442 | 1 1 1
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
--------------------------------------------------------------------------------