diff --git a/packages/frontend-2/components/tour/Segmentation.vue b/packages/frontend-2/components/tour/Segmentation.vue index e1b226b35..70fbb4f47 100644 --- a/packages/frontend-2/components/tour/Segmentation.vue +++ b/packages/frontend-2/components/tour/Segmentation.vue @@ -64,7 +64,7 @@ diff --git a/packages/frontend-2/lib/tour/slideshowItems.ts b/packages/frontend-2/lib/tour/slideshowItems.ts index b677686ae..3d8523427 100644 --- a/packages/frontend-2/lib/tour/slideshowItems.ts +++ b/packages/frontend-2/lib/tour/slideshowItems.ts @@ -11,7 +11,7 @@ export type SlideshowItem = { export const items = [ { - camPos: [-31.86138, 15.93344, -41.14196, -22.0765, 15.93344, -35.10095, 0, 1], + camPos: [-31.86138, 41.14196, 15.93344, -22.0765, 35.10095, 15.93344, 0, 1], style: {} as Partial, viewed: false, showControls: true, @@ -24,7 +24,7 @@ export const items = [ } }, { - camPos: [-3.3795, 23.25852, -40.78977, -20.65056, 21.78906, -40.72203, 0, 1], + camPos: [-3.3795, 40.78977, 23.25852, -20.65056, 40.72203, 21.78906, 0, 1], style: {} as Partial, viewed: false, showControls: true, @@ -36,7 +36,7 @@ export const items = [ } }, { - camPos: [-39.91711, 42.83686, -46.26069, -18.44162, 34.91624, -29.75982, 0, 1], + camPos: [-39.91711, 46.26069, 42.83686, -18.44162, 29.75982, 34.91624, 0, 1], style: {} as Partial, viewed: false, showControls: false, diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index 91e764351..fff2800f6 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -105,7 +105,7 @@ const getStream = () => { // prettier-ignore // 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D' // Revit sample house (good for bim-like stuff with many display meshes) - // 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8' + 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8' // 'https://latest.speckle.dev/streams/c1faab5c62/commits/ab1a1ab2b6' // 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8' // 'https://latest.speckle.dev/streams/58b5648c4d/commits/60371ecb2d' @@ -387,7 +387,7 @@ const getStream = () => { // Sum fucking pipes // 'https://app.speckle.systems/projects/122448a81e/models/f21aff1f4a' // Thin plane - 'https://app.speckle.systems/projects/20f72acc58/models/2cf8a736f8' + // 'https://app.speckle.systems/projects/20f72acc58/models/2cf8a736f8' ) } diff --git a/packages/viewer/src/modules/extensions/CameraController.ts b/packages/viewer/src/modules/extensions/CameraController.ts index dfb0bda0a..4e09e96cc 100644 --- a/packages/viewer/src/modules/extensions/CameraController.ts +++ b/packages/viewer/src/modules/extensions/CameraController.ts @@ -22,8 +22,8 @@ import { FlyControls, FlyControlsOptions } from './controls/FlyControls' import { SpeckleControls } from './controls/SpeckleControls' import { GeometryType } from '../batching/Batch' -const UP: Vector3 = new Vector3(0, 1, 0) -const quatBuff = new Quaternion() +// const UP: Vector3 = new Vector3(0, 1, 0) +// const quatBuff = new Quaternion() export enum NearPlaneCalculation { EMPIRIC, @@ -405,8 +405,7 @@ export class CameraController extends Extension implements SpeckleCamera { const renderer = this.viewer.getRenderer() if (!renderer.renderingCamera) return - const camera = renderer.renderingCamera as PerspectiveCamera - const minDist = this.getClosestGeometryDistance(camera) + const minDist = this.getClosestGeometryDistance() if (minDist === Number.POSITIVE_INFINITY) { this.updateNearCameraPlaneEmpiric(targetVolume, offsetScale) return @@ -456,12 +455,9 @@ export class CameraController extends Extension implements SpeckleCamera { renderer.renderingCamera.updateProjectionMatrix() } - protected getClosestGeometryDistance(camera: PerspectiveCamera): number { - const cameraPosition = camera.position + protected getClosestGeometryDistance(): number { + const cameraPosition = this._renderingCamera.position const cameraTarget = this.getTarget() - cameraTarget.applyQuaternion( - quatBuff.setFromUnitVectors(UP, this._activeControls.up) - ) const cameraDir = new Vector3().subVectors(cameraTarget, cameraPosition).normalize() const batches = this.viewer @@ -583,13 +579,9 @@ export class CameraController extends Extension implements SpeckleCamera { } protected setViewSpeckle(view: SpeckleView, transition = true) { - /** SpeckleViews assume Z up, so we pre-transform to Z forward */ - const quat = new Quaternion() - .setFromUnitVectors(new Vector3(0, 1, 0), new Vector3(0, 0, 1)) - .invert() this._activeControls.fromPositionAndTarget( - new Vector3(view.origin.x, view.origin.y, view.origin.z).applyQuaternion(quat), - new Vector3(view.target.x, view.target.y, view.target.z).applyQuaternion(quat) + new Vector3(view.origin.x, view.origin.y, view.origin.z), + new Vector3(view.target.x, view.target.y, view.target.z) ) if (!transition) this._activeControls.jumpToGoal() @@ -608,19 +600,23 @@ export class CameraController extends Extension implements SpeckleCamera { this.viewer.World.worldBox.getBoundingSphere(targetSphere) const distance = this.fitToRadius(targetSphere.radius) - const canonicalPosition = new Vector3() - .copy(this.viewer.World.worldBox.getCenter(new Vector3())) - .applyQuaternion( - new Quaternion() - .setFromUnitVectors(new Vector3(0, 1, 0), new Vector3(0, 0, 1)) - .invert() - ) - const canonicalTarget = new Vector3().copy(canonicalPosition) + const canonicalPosition = new Vector3().copy( + this.viewer.World.worldBox.getCenter(new Vector3()) + ) + const canonicalTarget = new Vector3().copy(canonicalPosition) + const controlerBasis = new Quaternion().setFromUnitVectors( + new Vector3(0, 1, 0), + this._activeControls.up + ) switch (side) { case 'front': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(0, 0, 1).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(0, 0, 1) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() @@ -628,7 +624,11 @@ export class CameraController extends Extension implements SpeckleCamera { case 'back': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(0, 0, -1).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(0, 0, -1) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() @@ -637,7 +637,11 @@ export class CameraController extends Extension implements SpeckleCamera { case 'up': case 'top': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(0, 1, 0).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(0, 1, 0) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() @@ -646,7 +650,11 @@ export class CameraController extends Extension implements SpeckleCamera { case 'down': case 'bottom': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(0, -1, 0).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(0, -1, 0) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() @@ -654,7 +662,11 @@ export class CameraController extends Extension implements SpeckleCamera { case 'right': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(1, 0, 0).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(1, 0, 0) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() @@ -662,7 +674,11 @@ export class CameraController extends Extension implements SpeckleCamera { case 'left': this._activeControls.fromPositionAndTarget( - canonicalPosition.add(new Vector3(-1, 0, 0).multiplyScalar(distance)), + canonicalPosition.add( + new Vector3(-1, 0, 0) + .applyQuaternion(controlerBasis) + .multiplyScalar(distance) + ), canonicalTarget ) if (this._renderingCamera === this.orthographicCamera) this.disableRotations() diff --git a/packages/viewer/src/modules/extensions/controls/SmoothOrbitControls.ts b/packages/viewer/src/modules/extensions/controls/SmoothOrbitControls.ts index b9c6ac7f3..923135e0a 100644 --- a/packages/viewer/src/modules/extensions/controls/SmoothOrbitControls.ts +++ b/packages/viewer/src/modules/extensions/controls/SmoothOrbitControls.ts @@ -237,10 +237,13 @@ export class SmoothOrbitControls extends SpeckleControls { const v0 = new Vector3().copy(position) const v1 = new Vector3().copy(target) - v0.sub(v1) + /** Three.js Spherical assumes (0, 1, 0) as up... */ + v0.sub(v1).applyMatrix4(this._basisTransformInv) const spherical = new Spherical() spherical.setFromCartesianCoords(v0.x, v0.y, v0.z) this.setOrbit(spherical.theta, spherical.phi, spherical.radius) + /** Three.js Spherical assumes (0, 1, 0) as up... */ + v1.applyMatrix4(this._basisTransformInv) this.setTarget(v1.x, v1.y, v1.z) } @@ -263,21 +266,17 @@ export class SmoothOrbitControls extends SpeckleControls { } /** - * Gets the current goal position. Needs to be in a basis with (0,1,0) as up + * Gets the current goal position */ public getPosition(): Vector3 { - return this.positionFromSpherical(this.goalSpherical, this.origin).applyMatrix4( - this._basisTransformInv - ) + return this.positionFromSpherical(this.goalSpherical, this.goalOrigin) } /** * Gets the point in model coordinates the model should orbit/pivot around. - * Needs to be in a basis with (0,1,0) as up - * We keep goalOrigin untransformed, so there is no need to transform back from the controller's defined basis */ public getTarget(): Vector3 { - return this.goalOrigin.clone() + return this.goalOrigin.clone().applyMatrix4(this._basisTransform) } public isStationary(): boolean { @@ -304,6 +303,19 @@ export class SmoothOrbitControls extends SpeckleControls { this.setFieldOfView(Math.exp(this.goalLogFov)) } + /** Computes min/max radius values based on the current world size */ + protected computeMinMaxRadius() { + if (this.world) { + const maxDistance = this.world.getRelativeOffset(10) + const minDistance = this.world.getRelativeOffset(0.01) + if (!isNaN(maxDistance) && !isNaN(minDistance)) + Object.assign(this._options, { + maximumRadius: maxDistance, + minimumRadius: minDistance + }) + } + } + /** * Set the absolute orbital goal of the camera. The change will be * applied over a number of frames depending on configured acceleration and @@ -326,6 +338,10 @@ export class SmoothOrbitControls extends SpeckleControls { maximumRadius } = this._options + if (isNaN(minimumRadius) || isNaN(maximumRadius)) { + this.computeMinMaxRadius() + } + const { theta, phi, radius } = this.goalSpherical const nextTheta = clamp(goalTheta, minimumAzimuthalAngle, maximumAzimuthalAngle) @@ -512,15 +528,7 @@ export class SmoothOrbitControls extends SpeckleControls { return false } - if (this.world) { - const maxDistance = this.world.getRelativeOffset(10) - const minDistance = this.world.getRelativeOffset(0.01) - this.applyOptions({ - maximumRadius: maxDistance, - minimumRadius: minDistance - }) - // radiusNormalisationRange = this.world.worldBox.getSize(new Vector3()).length() - } + this.computeMinMaxRadius() const { maximumPolarAngle } = this._options @@ -644,6 +652,7 @@ export class SmoothOrbitControls extends SpeckleControls { return height / (Math.tan(MathUtils.DEG2RAD * Math.exp(this.logFov) * 0.5) * 2) }*/ + /** Three.js Spherical assumes (0, 1, 0) as up... */ protected positionFromSpherical(spherical: Spherical, origin?: Vector3) { const position: Vector3 = new Vector3() position.setFromSpherical(spherical) @@ -655,6 +664,7 @@ export class SmoothOrbitControls extends SpeckleControls { return position } + /** Three.js Spherical assumes (0, 1, 0) as up... */ protected quaternionFromSpherical(spherical: Spherical) { const quaternion: Quaternion = new Quaternion() quaternion.setFromEuler( @@ -823,7 +833,8 @@ export class SmoothOrbitControls extends SpeckleControls { this.panPerPixel dxy.multiplyScalar(metersPerPixel) - const target = this.getTarget() + /** This panProjection assumes (0, 1, 0) as up... */ + const target = this.getTarget().applyMatrix4(this._basisTransformInv) target.add(dxy.applyMatrix3(this.panProjection)) this.setTarget(target.x, target.y, target.z) } diff --git a/packages/viewer/src/modules/extensions/controls/SpeckleControls.ts b/packages/viewer/src/modules/extensions/controls/SpeckleControls.ts index d5d94407d..21d7cce86 100644 --- a/packages/viewer/src/modules/extensions/controls/SpeckleControls.ts +++ b/packages/viewer/src/modules/extensions/controls/SpeckleControls.ts @@ -23,10 +23,7 @@ export abstract class SpeckleControls extends EventEmitter { abstract fitToSphere(sphere: Sphere): void abstract dispose(): void - /** The input position and target vectors will always be in basis where (0,1,0) is up */ abstract fromPositionAndTarget(position: Vector3, target: Vector3): void - /** Always in basis where (0,1,0) is up */ abstract getTarget(): Vector3 - /** Always in basis where (0,1,0) is up */ abstract getPosition(): Vector3 }