Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions editor/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@

const signals = editor.signals;

signals.cameraResetted.add( saveState );
signals.geometryChanged.add( saveState );
signals.objectAdded.add( saveState );
signals.objectChanged.add( saveState );
Expand Down
6 changes: 5 additions & 1 deletion editor/js/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function Config() {
'project/editable': false,
'project/vr': false,

'project/camera': 'perspective',

'project/renderer/type': 'WebGLRenderer',
'project/renderer/antialias': true,
'project/renderer/shadows': true,
Expand All @@ -28,7 +30,9 @@ function Config() {
'settings/shortcuts/rotate': 'e',
'settings/shortcuts/scale': 'r',
'settings/shortcuts/undo': 'z',
'settings/shortcuts/focus': 'f'
'settings/shortcuts/focus': 'f',
'settings/shortcuts/perspective': 'p',
'settings/shortcuts/orthographic': 'o'
};

if ( window.localStorage[ name ] === undefined ) {
Expand Down
66 changes: 66 additions & 0 deletions editor/js/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var _DEFAULT_CAMERA = new THREE.PerspectiveCamera( 50, 1, 0.001, 1e10 );
_DEFAULT_CAMERA.name = 'Camera';
_DEFAULT_CAMERA.position.set( 0, 5, 10 );
_DEFAULT_CAMERA.lookAt( new THREE.Vector3() );
const _ORTHOGRAPHIC_FRUSTUM_SIZE = 100;

function Editor() {

Expand Down Expand Up @@ -551,6 +552,68 @@ Editor.prototype = {

},

setCameraType: function ( type ) {

const oldCamera = this.camera;

const isOrthographic = oldCamera.isOrthographicCamera === true;

if ( ( type === 'orthographic' && isOrthographic ) || ( type === 'perspective' && ! isOrthographic ) ) return;

// the orbit point the framing should be preserved around

const center = this.controls ? this.controls.center : new THREE.Vector3();
const distance = oldCamera.position.distanceTo( center );

let newCamera;

if ( type === 'orthographic' ) {

const halfSize = _ORTHOGRAPHIC_FRUSTUM_SIZE / 2;
newCamera = new THREE.OrthographicCamera( - halfSize, halfSize, halfSize, - halfSize, 0, 10000 );
newCamera.position.copy( oldCamera.position );
newCamera.quaternion.copy( oldCamera.quaternion );

// derive the zoom so the orthographic framing matches the perspective view at the orbit center

const halfFOV = THREE.MathUtils.DEG2RAD * oldCamera.fov / 2;
newCamera.zoom = ( newCamera.top - newCamera.bottom ) / ( 2 * Math.max( distance, 0.0001 ) * Math.tan( halfFOV ) );

} else {

newCamera = new THREE.PerspectiveCamera( 50, 1, 0.001, 1e10 );
newCamera.quaternion.copy( oldCamera.quaternion );

// reposition along the view direction so the perspective framing matches the orthographic view

const halfFOV = THREE.MathUtils.DEG2RAD * newCamera.fov / 2;
const targetDistance = ( oldCamera.top - oldCamera.bottom ) / ( 2 * oldCamera.zoom * Math.tan( halfFOV ) );

const offset = new THREE.Vector3().subVectors( oldCamera.position, center );
if ( offset.lengthSq() === 0 ) offset.set( 0, 0, 1 ).applyQuaternion( oldCamera.quaternion );
offset.normalize().multiplyScalar( targetDistance );

newCamera.position.copy( center ).add( offset );

}

newCamera.name = oldCamera.name;
newCamera.uuid = oldCamera.uuid;
newCamera.updateProjectionMatrix();

this.camera = newCamera;
this.cameras[ newCamera.uuid ] = newCamera;

if ( this.viewportCamera === oldCamera ) this.viewportCamera = newCamera;

this.signals.cameraResetted.dispatch();

// keep the selection (and thus the sidebar) in sync with the new camera instance

if ( this.selected === oldCamera ) this.select( newCamera );

},

setViewportCamera: function ( uuid ) {

this.viewportCamera = this.cameras[ uuid ] || this.camera;
Expand Down Expand Up @@ -629,6 +692,7 @@ Editor.prototype = {
this.history.clear();
this.storage.clear();

this.setCameraType( 'perspective' );
this.camera.copy( _DEFAULT_CAMERA );
this.signals.cameraResetted.dispatch();

Expand Down Expand Up @@ -676,6 +740,8 @@ Editor.prototype = {
var loader = new THREE.ObjectLoader();
var camera = await loader.parseAsync( json.camera );

this.setCameraType( camera.isOrthographicCamera ? 'orthographic' : 'perspective' );

const existingUuid = this.camera.uuid;
const incomingUuid = camera.uuid;

Expand Down
36 changes: 30 additions & 6 deletions editor/js/EditorControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ class EditorControls extends THREE.EventDispatcher {

var changeEvent = { type: 'change' };

this.setCamera = function ( camera ) {

object = camera;

};

this.focus = function ( target ) {

var distance;
Expand All @@ -66,13 +72,22 @@ class EditorControls extends THREE.EventDispatcher {

object.position.copy( center ).add( delta );

if ( object.isOrthographicCamera ) {

object.zoom = ( object.top - object.bottom ) / ( distance * 2 );
object.updateProjectionMatrix();

}

scope.dispatchEvent( changeEvent );

};

this.pan = function ( delta ) {

var distance = object.position.distanceTo( center );
var distance = object.isOrthographicCamera
? ( object.top - object.bottom ) / object.zoom
: object.position.distanceTo( center );

delta.multiplyScalar( distance * scope.panSpeed );
delta.applyMatrix3( normalMatrix.getNormalMatrix( object.matrix ) );
Expand All @@ -86,15 +101,24 @@ class EditorControls extends THREE.EventDispatcher {

this.zoom = function ( delta ) {

var distance = object.position.distanceTo( center );
if ( object.isOrthographicCamera ) {

delta.multiplyScalar( distance * scope.zoomSpeed );
object.zoom = Math.max( 0.0001, object.zoom * Math.pow( 0.95, delta.z ) );
object.updateProjectionMatrix();

if ( delta.length() > distance ) return;
} else {

delta.applyMatrix3( normalMatrix.getNormalMatrix( object.matrix ) );
var distance = object.position.distanceTo( center );

object.position.add( delta );
delta.multiplyScalar( distance * scope.zoomSpeed );

if ( delta.length() > distance ) return;

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

object.position.add( delta );

}

scope.dispatchEvent( changeEvent );

Expand Down
4 changes: 3 additions & 1 deletion editor/js/Menubar.Add.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,9 @@ function MenubarAdd( editor ) {
option.setTextContent( strings.getKey( 'menubar/add/camera/orthographic' ) );
option.onClick( function () {

const aspect = editor.camera.aspect;
const aspect = editor.camera.isPerspectiveCamera
? editor.camera.aspect
: ( editor.camera.right - editor.camera.left ) / ( editor.camera.top - editor.camera.bottom );
const camera = new THREE.OrthographicCamera( - aspect, aspect );
camera.name = 'OrthographicCamera';

Expand Down
19 changes: 17 additions & 2 deletions editor/js/Menubar.Render.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,28 @@ class RenderImageDialog {
const loader = new THREE.ObjectLoader();

const camera = await loader.parseAsync( json.camera );
camera.aspect = imageWidth.getValue() / imageHeight.getValue();

const aspect = imageWidth.getValue() / imageHeight.getValue();

if ( camera.isPerspectiveCamera ) {

camera.aspect = aspect;

} else {

const frustumHeight = camera.top - camera.bottom;

camera.left = - frustumHeight * aspect / 2;
camera.right = frustumHeight * aspect / 2;

}

camera.updateProjectionMatrix();
camera.updateMatrixWorld();

const scene = await loader.parseAsync( json.scene );

const renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true } );
const renderer = new THREE.WebGLRenderer( { antialias: true, reversedDepthBuffer: true } );
renderer.setSize( imageWidth.getValue(), imageHeight.getValue() );
renderer.setClearColor( editor.viewportColor );

Expand Down
37 changes: 35 additions & 2 deletions editor/js/Sidebar.Project.Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ function SidebarProjectRenderer( editor ) {
const container = new UIPanel();
container.setBorderTop( '0px' );

// Camera

const cameraRow = new UIRow();
container.add( cameraRow );

cameraRow.add( new UIText( strings.getKey( 'sidebar/project/camera' ) ).setClass( 'Label' ) );

const cameraTypeSelect = new UISelect().setOptions( {
'perspective': 'Perspective',
'orthographic': 'Orthographic'
} ).setWidth( '150px' ).onChange( function () {

editor.setCameraType( this.getValue() );

} );
cameraTypeSelect.setValue( config.getKey( 'project/camera' ) );
cameraRow.add( cameraTypeSelect );

if ( config.getKey( 'project/camera' ) === 'orthographic' ) {

editor.setCameraType( 'orthographic' );

}

// Renderer

const rendererRow = new UIRow();
Expand Down Expand Up @@ -111,12 +135,12 @@ function SidebarProjectRenderer( editor ) {

if ( rendererType === 'WebGPURenderer' ) {

currentRenderer = new WebGPURenderer( { antialias: antialias, logarithmicDepthBuffer: true } );
currentRenderer = new WebGPURenderer( { antialias: antialias, reversedDepthBuffer: true } );
await currentRenderer.init();

} else {

currentRenderer = new THREE.WebGLRenderer( { antialias: antialias, logarithmicDepthBuffer: true } );
currentRenderer = new THREE.WebGLRenderer( { antialias: antialias, reversedDepthBuffer: true } );

}

Expand All @@ -135,6 +159,15 @@ function SidebarProjectRenderer( editor ) {

// Signals

signals.cameraResetted.add( function () {

const type = editor.camera.isOrthographicCamera ? 'orthographic' : 'perspective';

cameraTypeSelect.setValue( type );
config.setKey( 'project/camera', type );

} );

signals.editorCleared.add( function () {

currentRenderer.shadowMap.enabled = true;
Expand Down
2 changes: 2 additions & 0 deletions editor/js/Sidebar.Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ function SidebarScene( editor ) {

signals.sceneGraphChanged.add( refreshUI );

signals.cameraResetted.add( refreshUI );

signals.objectChanged.add( function ( object ) {

const options = outliner.options;
Expand Down
14 changes: 13 additions & 1 deletion editor/js/Sidebar.Settings.Shortcuts.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function SidebarSettingsShortcuts( editor ) {
headerRow.add( new UIText( strings.getKey( 'sidebar/settings/shortcuts' ).toUpperCase() ) );
container.add( headerRow );

const shortcuts = [ 'translate', 'rotate', 'scale', 'undo', 'focus' ];
const shortcuts = [ 'translate', 'rotate', 'scale', 'undo', 'focus', 'perspective', 'orthographic' ];

function createShortcutInput( name ) {

Expand Down Expand Up @@ -175,6 +175,18 @@ function SidebarSettingsShortcuts( editor ) {

break;

case config.getKey( 'settings/shortcuts/perspective' ):

editor.setCameraType( 'perspective' );

break;

case config.getKey( 'settings/shortcuts/orthographic' ):

editor.setCameraType( 'orthographic' );

break;

}

} );
Expand Down
3 changes: 3 additions & 0 deletions editor/js/Strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ function Strings( config ) {
'sidebar/script/remove': 'Remove',

'sidebar/project': 'Project',
'sidebar/project/camera': 'Camera',
'sidebar/project/renderer': 'Renderer',
'sidebar/project/antialias': 'Antialias',
'sidebar/project/shadows': 'Shadows',
Expand Down Expand Up @@ -849,6 +850,8 @@ function Strings( config ) {
'sidebar/settings/shortcuts/scale': 'Scale',
'sidebar/settings/shortcuts/undo': 'Undo',
'sidebar/settings/shortcuts/focus': 'Focus',
'sidebar/settings/shortcuts/perspective': 'Perspective',
'sidebar/settings/shortcuts/orthographic': 'Orthographic',

'sidebar/history': 'History',
'sidebar/history/clear': 'Clear',
Expand Down
13 changes: 12 additions & 1 deletion editor/js/Viewport.XR.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@ class XR {

const onSessionStarted = async ( session ) => {

camera.copy( editor.camera );
if ( editor.camera.isPerspectiveCamera ) {

camera.copy( editor.camera );

} else {

// an orthographic default camera can't be mirrored into a perspective XR camera

camera.position.copy( editor.camera.position );
camera.quaternion.copy( editor.camera.quaternion );

}

const sidebar = document.getElementById( 'sidebar' );
sidebar.style.width = '350px';
Expand Down
Loading