add on-the-fly camera perspective switching
This commit is contained in:
parent
5d2f76e238
commit
8335d2d8e9
2 changed files with 121 additions and 4 deletions
|
|
@ -135,7 +135,7 @@ api.event.on("set.threaded", bool => setThreaded(bool));
|
|||
|
||||
function booleanSave() {
|
||||
let control = settings().controller;
|
||||
let doAlert = ui.ortho.checked !== control.ortho;
|
||||
let setProjection = ui.ortho.checked !== control.ortho;
|
||||
if (control.assembly != ui.assembly.checked) {
|
||||
client.wasm(ui.assembly.checked);
|
||||
}
|
||||
|
|
@ -171,8 +171,8 @@ function booleanSave() {
|
|||
updateStats();
|
||||
updateDrawer();
|
||||
api.event.emit('boolean.update');
|
||||
if (doAlert) {
|
||||
api.show.alert("change requires page refresh");
|
||||
if (setProjection) {
|
||||
space.view.setProjection(control.ortho ? 'orthographic' : 'perspective');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,9 +112,11 @@ let WIN = self.window || {},
|
|||
platformBelt = false,
|
||||
volume,
|
||||
camera,
|
||||
cameraType,
|
||||
renderer,
|
||||
container,
|
||||
raycaster,
|
||||
sliderCallback,
|
||||
freezeTo,
|
||||
freeze,
|
||||
isRound = false,
|
||||
|
|
@ -1282,6 +1284,12 @@ let Space = {
|
|||
},
|
||||
get ctrl() {
|
||||
return viewControl;
|
||||
},
|
||||
setProjection(type) {
|
||||
Space.setProjection(type);
|
||||
},
|
||||
getProjection() {
|
||||
return cameraType;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1355,12 +1363,120 @@ let Space = {
|
|||
return ncv;
|
||||
},
|
||||
|
||||
internals: () => {
|
||||
internals() {
|
||||
return { renderer, camera, platform };
|
||||
},
|
||||
|
||||
isOrtho() {
|
||||
return type === 'orthographic';
|
||||
},
|
||||
|
||||
isPerspective() {
|
||||
return type === 'perspective';
|
||||
},
|
||||
|
||||
setProjection: (type) => {
|
||||
if (!camera || !viewControl || !initialized) {
|
||||
console.warn('Space not initialized');
|
||||
return;
|
||||
}
|
||||
if (type === cameraType) {
|
||||
return; // already set
|
||||
}
|
||||
if (type !== 'orthographic' && type !== 'perspective') {
|
||||
console.warn('Invalid camera type:', type);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save current view state
|
||||
const position = viewControl.getPosition();
|
||||
const target = viewControl.getTarget().clone();
|
||||
const distance = camera.position.distanceTo(target);
|
||||
|
||||
// Create new camera
|
||||
let newCamera;
|
||||
if (type === 'orthographic') {
|
||||
const asp = aspect();
|
||||
// Calculate ortho size based on perspective distance and FOV
|
||||
const size = distance * Math.tan(perspective * Math.PI / 180 / 2);
|
||||
newCamera = new THREE.OrthographicCamera(
|
||||
-size * asp, size * asp, size, -size, 0.1, 100000
|
||||
);
|
||||
} else {
|
||||
newCamera = new THREE.PerspectiveCamera(
|
||||
perspective, aspect(), 0.1, 100000
|
||||
);
|
||||
}
|
||||
|
||||
// Copy camera position
|
||||
newCamera.position.copy(camera.position);
|
||||
newCamera.up.copy(camera.up);
|
||||
newCamera.lookAt(target);
|
||||
|
||||
// Store old control properties
|
||||
const maxDistance = viewControl.maxDistance;
|
||||
const noKeys = viewControl.noKeys;
|
||||
const enabled = viewControl.enabled;
|
||||
|
||||
// Swap camera
|
||||
const oldCamera = camera;
|
||||
camera = newCamera;
|
||||
cameraType = type;
|
||||
|
||||
// Recreate viewControl with new camera and proper callbacks
|
||||
viewControl = new Orbit(camera, container, (position, moved) => {
|
||||
if (platform) {
|
||||
platform.visible = hidePlatformBelow ?
|
||||
initialized && position.y >= 0 && showPlatform : showPlatform;
|
||||
volume.visible = showVolume && platform.visible;
|
||||
}
|
||||
if (grid.view) {
|
||||
grid.view.visible = hideGridBelow ? platform.visible : showGrid;
|
||||
}
|
||||
if (cameraLight) {
|
||||
cameraLight.position.copy(camera.position);
|
||||
}
|
||||
if (moved && platformOnMove) {
|
||||
clearTimeout(platformMoveTimer);
|
||||
platformMoveTimer = setTimeout(platformOnMove, 500);
|
||||
Space.scene.updateFog();
|
||||
}
|
||||
updateLastAction();
|
||||
updateFocus();
|
||||
}, (val) => {
|
||||
if (camera && grid?.origin?.scale) {
|
||||
grid.origin.scale();
|
||||
}
|
||||
if (camera && viewControl) {
|
||||
// increase intersect line precision on zoom
|
||||
const dist = camera.position.distanceTo(viewControl.target);
|
||||
raycaster.params.Line.threshold = Math.min(1, dist / 100);
|
||||
}
|
||||
updateLastAction();
|
||||
if (sliderCallback) sliderCallback(val);
|
||||
});
|
||||
viewControl.noKeys = noKeys;
|
||||
viewControl.maxDistance = maxDistance;
|
||||
viewControl.enabled = enabled;
|
||||
viewControl.setPosition(position);
|
||||
|
||||
// Dispose old camera
|
||||
THREE.dispose(oldCamera);
|
||||
|
||||
// Update camera-dependent systems
|
||||
if (cameraLight) {
|
||||
cameraLight.position.copy(camera.position);
|
||||
}
|
||||
if (grid?.origin?.scale) {
|
||||
grid.origin.scale();
|
||||
}
|
||||
|
||||
requestRefresh();
|
||||
},
|
||||
|
||||
init: (domelement, slider, ortho) => {
|
||||
container = domelement;
|
||||
sliderCallback = slider;
|
||||
|
||||
WORLD.rotation.x = -PI2;
|
||||
SCENE.add(WORLD);
|
||||
|
|
@ -1378,6 +1494,7 @@ let Space = {
|
|||
// renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
|
||||
|
||||
renderer.localClippingEnabled = true;
|
||||
cameraType = ortho ? 'orthographic' : 'perspective';
|
||||
camera = ortho ?
|
||||
new THREE.OrthographicCamera(-100 * aspect(), 100 * aspect(), 100, -100, 0.1, 100000) :
|
||||
new THREE.PerspectiveCamera(perspective, aspect(), 0.1, 100000);
|
||||
|
|
|
|||
Loading…
Reference in a new issue