Skip to content

Commit 26eb77f

Browse files
authored
ortho cameras (#565)
* ortho cameras * ortho camera labels * camera change shortcut * fix regression * use select for ortho
1 parent bd05e29 commit 26eb77f

File tree

10 files changed

+223
-66
lines changed

10 files changed

+223
-66
lines changed

src/components/Main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ComponentsSidebar from './components/Sidebar';
77
import ModalTextures from './modals/ModalTextures';
88
import ModalHelp from './modals/ModalHelp';
99
import SceneGraph from './scenegraph/SceneGraph';
10+
import CameraToolbar from './viewport/CameraToolbar';
1011
import TransformToolBar from './viewport/TransformToolBar';
1112
import ViewportHUD from './viewport/ViewportHUD';
1213
import { injectCSS } from '../lib/utils';
@@ -170,7 +171,7 @@ export default class Main extends React.Component {
170171
/>
171172

172173
<div id="viewportBar">
173-
<div />
174+
<CameraToolbar />
174175
<ViewportHUD />
175176
<TransformToolBar />
176177
</div>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
var React = require('react');
2+
var Events = require('../../lib/Events.js');
3+
var classNames = require('classnames');
4+
import Select from 'react-select';
5+
6+
const options = [
7+
{ value: 'perspective', event: 'cameraperspectivetoggle', payload: null, label: 'Perspective' },
8+
{ value: 'ortholeft', event: 'cameraorthographictoggle', payload: 'left', label: 'Left View' },
9+
{ value: 'orthoright', event: 'cameraorthographictoggle', payload: 'right', label: 'Right View' },
10+
{ value: 'orthotop', event: 'cameraorthographictoggle', payload: 'top', label: 'Top View' },
11+
{ value: 'orthobottom', event: 'cameraorthographictoggle', payload: 'bottom', label: 'Bottom View' },
12+
{ value: 'orthoback', event: 'cameraorthographictoggle', payload: 'back', label: 'Back View' },
13+
{ value: 'orthofront', event: 'cameraorthographictoggle', payload: 'front', label: 'Front View' },
14+
];
15+
16+
function getOption (value) {
17+
return options.filter(opt => opt.value === value)[0];
18+
}
19+
20+
export default class CameraToolbar extends React.Component {
21+
constructor(props) {
22+
super(props);
23+
this.state = {
24+
selectedCamera: 'perspective'
25+
};
26+
this.justChangedCamera = false;
27+
}
28+
29+
componentDidMount() {
30+
Events.on('cameratoggle', data => {
31+
if (this.justChangedCamera) {
32+
// Prevent recursion.
33+
this.justChangedCamera = false;
34+
return;
35+
}
36+
this.setState({selectedCamera: data.value});
37+
});
38+
}
39+
40+
onChange(option) {
41+
console.log(option);
42+
this.justChangedCamera = true;
43+
this.setState({selectedCamera: option.value});
44+
Events.emit(option.event, option.payload);
45+
}
46+
47+
render() {
48+
return (
49+
<div id="cameraToolbar">
50+
<a href="#" className="button fa fa-camera" />
51+
<Select
52+
id="cameraSelect"
53+
classNamePrefix="select"
54+
options={options}
55+
simpleValue
56+
value={getOption(this.state.selectedCamera)}
57+
isSearchable={false}
58+
onChange={this.onChange.bind(this)} />
59+
</div>
60+
);
61+
}
62+
}

src/components/viewport/TransformToolbar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default class TransformToolbar extends React.Component {
6868

6969
render() {
7070
return (
71-
<div className="transformToolbar">
71+
<div id="transformToolbar" className="toolbarButtons">
7272
{this.renderTransformButtons()}
7373
<span className="local-transform">
7474
<input

src/index.js

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var Shortcuts = require('./lib/shortcuts');
99
import React from 'react';
1010
import ReactDOM from 'react-dom';
1111
import Main from './components/Main';
12+
import { initCameras } from './lib/cameras';
1213
import { injectCSS, injectJS } from './lib/utils';
1314
import { createEntity } from './lib/entity';
1415
import { GLTFExporter } from '../vendor/GLTFExporter'; // eslint-disable-line no-unused-vars
@@ -59,52 +60,13 @@ Inspector.prototype = {
5960
return;
6061
}
6162

62-
Shortcuts.init(this);
63-
6463
this.container = document.querySelector('.a-canvas');
65-
this.currentCameraEl = this.sceneEl.camera.el;
66-
this.currentCameraEl.setAttribute(
67-
'data-aframe-inspector-original-camera',
68-
''
69-
);
70-
71-
// If the current camera is the default, we should prevent AFRAME from
72-
// remove it once when we inject the editor's camera.
73-
if (this.currentCameraEl.hasAttribute('data-aframe-default-camera')) {
74-
this.currentCameraEl.removeAttribute('data-aframe-default-camera');
75-
this.currentCameraEl.setAttribute(
76-
'data-aframe-inspector',
77-
'default-camera'
78-
);
79-
}
80-
81-
this.currentCameraEl.setAttribute('camera', 'active', false);
82-
83-
// Create Inspector camera.
84-
const camera = (this.camera = new THREE.PerspectiveCamera());
85-
camera.far = 10000;
86-
camera.near = 0.01;
87-
camera.position.set(0, 1.6, 2);
88-
camera.lookAt(new THREE.Vector3(0, 1.6, -1));
89-
camera.updateMatrixWorld();
90-
this.sceneEl.object3D.add(camera);
91-
this.sceneEl.camera = camera;
92-
64+
initCameras(this);
9365
this.initUI();
9466
},
9567

96-
/**
97-
* Currently not used.
98-
*/
99-
initModules: function() {
100-
for (var moduleName in this.modules) {
101-
var module = this.modules[moduleName];
102-
console.log('Initializing module <%s>', moduleName);
103-
module.init(this.sceneEl);
104-
}
105-
},
106-
10768
initUI: function() {
69+
Shortcuts.init(this);
10870
this.initEvents();
10971

11072
this.selected = null;

src/lib/EditorControls.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ THREE.Box3.prototype.expandByObject = (function() {
5959
* @author WestLangley / http://github.com/WestLangley
6060
*/
6161

62-
THREE.EditorControls = function(object, domElement) {
62+
THREE.EditorControls = function(_object, domElement) {
6363
domElement = domElement !== undefined ? domElement : document;
6464

6565
// API
@@ -70,6 +70,8 @@ THREE.EditorControls = function(object, domElement) {
7070
this.zoomSpeed = 0.1;
7171
this.rotationSpeed = 0.005;
7272

73+
var object = _object;
74+
7375
// internals
7476

7577
var scope = this;
@@ -87,6 +89,20 @@ THREE.EditorControls = function(object, domElement) {
8789
var spherical = new THREE.Spherical();
8890
var sphere = new THREE.Sphere();
8991

92+
this.isOrthographic = false;
93+
this.rotationEnabled = true;
94+
this.setCamera = function (_object) {
95+
object = _object;
96+
if (object.type === 'OrthographicCamera') {
97+
this.rotationEnabled = false;
98+
this.isOrthographic = true;
99+
} else {
100+
this.rotationEnabled = true;
101+
this.isOrthographic = false;
102+
}
103+
};
104+
this.setCamera(_object);
105+
90106
// events
91107

92108
var changeEvent = { type: 'change' };
@@ -139,12 +155,29 @@ THREE.EditorControls = function(object, domElement) {
139155

140156
delta.applyMatrix3(normalMatrix.getNormalMatrix(object.matrix));
141157

142-
object.position.add(delta);
158+
if (this.isOrthographic) {
159+
// Change FOV for ortho.
160+
let factor = 1;
161+
if ((delta.x + delta.y + delta.z) < 0) {
162+
factor = -1;
163+
}
164+
delta = distance * scope.zoomSpeed * factor;
165+
object.left -= delta;
166+
object.bottom -= delta;
167+
object.right += delta;
168+
object.top += delta;
169+
if (object.left >= -0.0001) { return; }
170+
object.updateProjectionMatrix();
171+
} else {
172+
object.position.add(delta);
173+
}
143174

144175
scope.dispatchChange();
145176
};
146177

147178
this.rotate = function(delta) {
179+
if (!this.rotationEnabled) { return; }
180+
148181
vector.copy(object.position).sub(center);
149182

150183
spherical.setFromVector3(vector);

src/lib/TransformControls.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@
769769
);
770770
THREE.TransformGizmoScale.prototype.constructor = THREE.TransformGizmoScale;
771771

772-
THREE.TransformControls = function(camera, domElement) {
772+
THREE.TransformControls = function(_camera, domElement) {
773773
// TODO: Make non-uniform scale and rotate play nice in hierarchies
774774
// TODO: ADD RXYZ contol
775775

@@ -785,6 +785,7 @@
785785
this.size = 1;
786786
this.axis = null;
787787

788+
var camera = _camera;
788789
var scope = this;
789790

790791
var _mode = 'translate';
@@ -846,6 +847,10 @@
846847
var camPosition = new THREE.Vector3();
847848
var camRotation = new THREE.Euler();
848849

850+
this.setCamera = function (_camera) {
851+
camera = _camera;
852+
}
853+
849854
this.activate = function() {
850855
domElement.addEventListener('mousedown', onPointerDown, false);
851856
domElement.addEventListener('touchstart', onPointerDown, false);

src/lib/cameras.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import Events from './Events';
2+
3+
/**
4+
* Initialize various cameras, store original one.
5+
*/
6+
export function initCameras (inspector) {
7+
const originalCamera = inspector.currentCameraEl = inspector.sceneEl.camera.el;
8+
inspector.currentCameraEl.setAttribute(
9+
'data-aframe-inspector-original-camera',
10+
''
11+
);
12+
13+
// If the current camera is the default, we should prevent AFRAME from
14+
// remove it once when we inject the editor's camera.
15+
if (inspector.currentCameraEl.hasAttribute('data-aframe-default-camera')) {
16+
inspector.currentCameraEl.removeAttribute('data-aframe-default-camera');
17+
inspector.currentCameraEl.setAttribute(
18+
'data-aframe-inspector',
19+
'default-camera'
20+
);
21+
}
22+
23+
inspector.currentCameraEl.setAttribute('camera', 'active', false);
24+
25+
// Create Inspector camera.
26+
const perspectiveCamera = inspector.camera = new THREE.PerspectiveCamera();
27+
perspectiveCamera.far = 10000;
28+
perspectiveCamera.near = 0.01;
29+
perspectiveCamera.position.set(0, 1.6, 2);
30+
perspectiveCamera.lookAt(new THREE.Vector3(0, 1.6, -1));
31+
perspectiveCamera.updateMatrixWorld();
32+
inspector.sceneEl.object3D.add(perspectiveCamera);
33+
inspector.sceneEl.camera = perspectiveCamera;
34+
35+
const orthoCamera = new THREE.OrthographicCamera(-10, 10, 10, -10);
36+
inspector.sceneEl.object3D.add(orthoCamera);
37+
38+
const cameras = inspector.cameras = {
39+
perspective: perspectiveCamera,
40+
original: originalCamera,
41+
ortho: orthoCamera
42+
};
43+
44+
Events.on('cameraperspectivetoggle', () => {
45+
inspector.sceneEl.camera = inspector.camera = cameras.perspective;
46+
Events.emit('cameratoggle', {camera: inspector.camera, value: 'perspective'});
47+
});
48+
49+
Events.on('cameraorthographictoggle', dir => {
50+
inspector.sceneEl.camera = inspector.camera = cameras.ortho;
51+
if (dir === 'left') {
52+
cameras.ortho.position.set(-10, 0, 0);
53+
} else if (dir === 'right') {
54+
cameras.ortho.position.set(10, 0, 0);
55+
} else if (dir === 'top') {
56+
cameras.ortho.position.set(0, 10, 0);
57+
} else if (dir === 'bottom') {
58+
cameras.ortho.position.set(0, -10, 0);
59+
} else if (dir === 'back') {
60+
cameras.ortho.position.set(0, 0, -10);
61+
} else if (dir === 'front') {
62+
cameras.ortho.position.set(0, 0, 10);
63+
}
64+
cameras.ortho.lookAt(0, 0, 0);
65+
Events.emit('cameratoggle', {camera: inspector.camera, value: `ortho${dir}`});
66+
});
67+
68+
return inspector.cameras;
69+
};

src/lib/shortcuts.js

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ function shouldCaptureKeyEvent(event) {
1212
return false;
1313
}
1414
return (
15-
event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA'
15+
event.target.closest('#cameraToolbar') ||
16+
(event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA')
1617
);
1718
}
1819

@@ -94,6 +95,22 @@ var Shortcuts = {
9495
}
9596
}
9697

98+
if (keyCode === 49) {
99+
Events.emit('cameraperspectivetoggle');
100+
} else if (keyCode === 50) {
101+
Events.emit('cameraorthographictoggle', 'left');
102+
} else if (keyCode === 51) {
103+
Events.emit('cameraorthographictoggle', 'right');
104+
} else if (keyCode === 52) {
105+
Events.emit('cameraorthographictoggle', 'top');
106+
} else if (keyCode === 53) {
107+
Events.emit('cameraorthographictoggle', 'bottom');
108+
} else if (keyCode === 54) {
109+
Events.emit('cameraorthographictoggle', 'back');
110+
} else if (keyCode === 55) {
111+
Events.emit('cameraorthographictoggle', 'front');
112+
}
113+
97114
for (var moduleName in this.shortcuts.modules) {
98115
var shortcutsModule = this.shortcuts.modules[moduleName];
99116
if (
@@ -136,38 +153,28 @@ var Shortcuts = {
136153
}
137154
}
138155

139-
// f: focus filter input
140-
if (event.keyCode === 70) {
156+
// s: focus search input
157+
if (event.keyCode === 83) {
141158
event.preventDefault();
142159
event.stopPropagation();
143160
document.getElementById('filter').focus();
144161
}
145162
}
146163

147164
// º: toggle sidebars visibility
148-
if (event.keyCode === 192) {
165+
if (event.keyCode === 48) {
149166
Events.emit('togglesidebar', { which: 'all' });
150167
event.preventDefault();
151168
event.stopPropagation();
152169
}
153-
154-
// 1: toggle scenegraph visibility only
155-
if (event.keyCode === 49) {
156-
Events.emit('togglesidebar', { which: 'scenegraph' });
157-
}
158-
159-
// 2: toggle sidebar visibility only
160-
if (event.keyCode === 50) {
161-
Events.emit('togglesidebar', { which: 'attributes' });
162-
}
163170
},
164171
enable: function() {
165172
if (this.enabled) {
166173
this.disable();
167174
}
168175

169-
window.addEventListener('keydown', this.onKeyDown, false);
170-
window.addEventListener('keyup', this.onKeyUp, false);
176+
window.addEventListener('keydown', this.onKeyDown.bind(this), false);
177+
window.addEventListener('keyup', this.onKeyUp.bind(this), false);
171178
this.enabled = true;
172179
},
173180
disable: function() {

0 commit comments

Comments
 (0)