-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New feature: Enhanced zoomOnBoundingsInfo with Bounding Box Option, Orthographic Camera Support, and Offset #17292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
c031b9b
eff6c9a
2dbea65
57311f6
1da4608
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -304,7 +304,7 @@ | |
| this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd); | ||
| } | ||
|
|
||
| /** | ||
|
Check failure on line 307 in packages/dev/core/src/Behaviors/Cameras/framingBehavior.ts
|
||
| * Targets the bounding box info defined by its extends and updates zoom level accordingly. | ||
| * @param minimumWorld Determines the smaller position of the bounding box extend | ||
| * @param maximumWorld Determines the bigger position of the bounding box extend | ||
|
|
@@ -312,7 +312,14 @@ | |
| * @param onAnimationEnd Callback triggered at the end of the framing animation | ||
| * @returns true if the zoom was done | ||
| */ | ||
| public zoomOnBoundingInfo(minimumWorld: Vector3, maximumWorld: Vector3, focusOnOriginXZ: boolean = false, onAnimationEnd: Nullable<() => void> = null): boolean { | ||
| public zoomOnBoundingInfo( | ||
| minimumWorld: Vector3, | ||
| maximumWorld: Vector3, | ||
| focusOnOriginXZ: boolean = false, | ||
| onAnimationEnd: Nullable<() => void> = null, | ||
| mode: string = "sphere", | ||
| radiusScaling: number = 1 | ||
| ): boolean { | ||
| let zoomTarget: Vector3; | ||
|
|
||
| if (!this._attachedCamera) { | ||
|
|
@@ -350,13 +357,13 @@ | |
| // Small delta ensures camera is not always at lower zoom limit. | ||
| let radius = 0; | ||
| if (this._mode === FramingBehavior.FitFrustumSidesMode) { | ||
| const position = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld); | ||
| const position = this._calculateLowerRadiusFromModelBoundingInfo(minimumWorld, maximumWorld, mode, radiusScaling); | ||
| if (this.autoCorrectCameraLimitsAndSensibility) { | ||
| this._attachedCamera.lowerRadiusLimit = radiusWorld.length() + this._attachedCamera.minZ; | ||
| } | ||
| radius = position; | ||
| } else if (this._mode === FramingBehavior.IgnoreBoundsSizeMode) { | ||
| radius = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld); | ||
| radius = this._calculateLowerRadiusFromModelBoundingInfo(minimumWorld, maximumWorld, mode, radiusScaling); | ||
| if (this.autoCorrectCameraLimitsAndSensibility && this._attachedCamera.lowerRadiusLimit === null) { | ||
| this._attachedCamera.lowerRadiusLimit = this._attachedCamera.minZ; | ||
| } | ||
|
|
@@ -392,21 +399,21 @@ | |
| return true; | ||
| } | ||
|
|
||
| /** | ||
|
Check failure on line 402 in packages/dev/core/src/Behaviors/Cameras/framingBehavior.ts
|
||
| * Calculates the lowest radius for the camera based on the bounding box of the mesh. | ||
| * @param minimumWorld | ||
| * @param maximumWorld | ||
| * @returns The minimum distance from the primary mesh's center point at which the camera must be kept in order | ||
| * to fully enclose the mesh in the viewing frustum. | ||
| */ | ||
| protected _calculateLowerRadiusFromModelBoundingSphere(minimumWorld: Vector3, maximumWorld: Vector3): number { | ||
| protected _calculateLowerRadiusFromModelBoundingInfo(minimumWorld: Vector3, maximumWorld: Vector3, mode: string = "sphere", radiusScale: number = 1): number { | ||
|
||
| const camera = this._attachedCamera; | ||
|
|
||
| if (!camera) { | ||
| return 0; | ||
| } | ||
|
|
||
| let distance = camera._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld, this._radiusScale); | ||
| let distance = camera._calculateLowerRadiusFromModelBoundingInfo(minimumWorld, maximumWorld, mode, radiusScale); | ||
| if (camera.lowerRadiusLimit && this._mode === FramingBehavior.IgnoreBoundsSizeMode) { | ||
| // Don't exceed the requested limit | ||
| distance = distance < camera.lowerRadiusLimit ? camera.lowerRadiusLimit : distance; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1448,7 +1448,7 @@ | |
| meshes = meshes || this.getScene().meshes; | ||
|
|
||
| const minMaxVector = Mesh.MinMax(meshes); | ||
| let distance = this._calculateLowerRadiusFromModelBoundingSphere(minMaxVector.min, minMaxVector.max); | ||
| let distance = this._calculateLowerRadiusFromModelBoundingInfo(minMaxVector.min, minMaxVector.max); | ||
|
|
||
| // If there are defined limits, we need to take them into account | ||
| distance = Math.max(Math.min(distance, this.upperRadiusLimit || Number.MAX_VALUE), this.lowerRadiusLimit || 0); | ||
|
|
@@ -1561,24 +1561,55 @@ | |
| /** | ||
| * @internal | ||
| */ | ||
| public _calculateLowerRadiusFromModelBoundingSphere(minimumWorld: Vector3, maximumWorld: Vector3, radiusScale: number = 1): number { | ||
| const boxVectorGlobalDiagonal = Vector3.Distance(minimumWorld, maximumWorld); | ||
|
|
||
| // Get aspect ratio in order to calculate frustum slope | ||
| public _calculateLowerRadiusFromModelBoundingInfo(minimumWorld: Vector3, maximumWorld: Vector3, mode: string = "sphere", radiusScale: number = 1): number { | ||
|
||
| const engine = this.getScene().getEngine(); | ||
| const aspectRatio = engine.getAspectRatio(this); | ||
| const frustumSlopeY = Math.tan(this.fov / 2); | ||
| const frustumSlopeX = frustumSlopeY * aspectRatio; | ||
|
|
||
| // Formula for setting distance | ||
| // (Good explanation: http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene) | ||
| const radiusWithoutFraming = boxVectorGlobalDiagonal * 0.5; | ||
|
|
||
| // Horizon distance | ||
| const radius = radiusWithoutFraming * radiusScale; | ||
| const distanceForHorizontalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlopeX * frustumSlopeX)); | ||
| const distanceForVerticalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlopeY * frustumSlopeY)); | ||
| return Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum); | ||
| const oldRadius = this.radius; | ||
| let distance = oldRadius; | ||
| let distanceForHorizontalFrustum: number = 0; | ||
| let distanceForVerticalFrustum: number = 0; | ||
| const height = (maximumWorld.y - minimumWorld.y) * 0.5; | ||
| const widht = (maximumWorld.x - minimumWorld.x) * 0.5; | ||
|
||
| if (mode === "sphere") { | ||
| const boxVectorGlobalDiagonal = Vector3.Distance(minimumWorld, maximumWorld); | ||
| // Get aspect ratio in order to calculate frustum slope | ||
|
|
||
| // Formula for setting distance | ||
| // (Good explanation: http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene) | ||
| const radiusWithoutFraming = boxVectorGlobalDiagonal * 0.5; | ||
|
|
||
| // Horizon distance | ||
| const radius = radiusWithoutFraming * radiusScale; | ||
| distanceForHorizontalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlopeX * frustumSlopeX)); | ||
| distanceForVerticalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlopeY * frustumSlopeY)); | ||
| distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum); | ||
| } else if (mode === "bounding box") { | ||
| // Setting the distance according to the bounding box (centring the first face of the bounding box) | ||
| const depth = (maximumWorld.z - minimumWorld.z) * 0.5; | ||
| distanceForHorizontalFrustum = (radiusScale * widht) / frustumSlopeX + depth; | ||
| distanceForVerticalFrustum = (radiusScale * height) / frustumSlopeY + depth; | ||
| distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum); | ||
| } else { | ||
| return this.radius; | ||
|
||
| } | ||
| //Adding a check for orthographic Camera | ||
| if (this.mode === Camera.ORTHOGRAPHIC_CAMERA) { | ||
| if (aspectRatio < widht / height) { | ||
| this.orthoRight = widht * radiusScale; | ||
|
||
| this.orthoLeft = -this.orthoRight; | ||
| this.orthoTop = this.orthoRight / aspectRatio; | ||
| this.orthoBottom = this.orthoLeft / aspectRatio; | ||
| } else { | ||
| this.orthoRight = height * aspectRatio * radiusScale; | ||
| this.orthoLeft = -this.orthoRight * radiusScale; | ||
| this.orthoTop = height; | ||
| this.orthoBottom = -this.orthoTop; | ||
| } | ||
| console.log("ciao", this.orthoBottom, this.orthoTop, this.orthoLeft, this.orthoRight); | ||
|
Check failure on line 1610 in packages/dev/core/src/Cameras/arcRotateCamera.ts
|
||
|
||
| } | ||
| return distance; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if radiusscale is not sent, we are defaulting to 1, which then gets sent to camera below
let distance = camera._calculateLowerRadiusFromModelBoundingInfo(minimumWorld, maximumWorld, mode, radiusScale);however before this change, we would send this._radiusScale in the above code, so the behavior is slightly different
i would recommend making radiusScaling truly optional here, and if it is not passed we default to this._radiusScale still
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've noticed there are two _calculateLowerRadiusFromModelBoundingSphere methods—one as a method of FramingBehavior and the other as a method of ArcRotateCamera. One of them takes the radius scale as a parameter, and the other doesn't. I didn't fully understand this choice, but I'll try to figure it out and fix my implementation accordingly.