diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts index 702006bf2cd63b1e3d368e4dc2156d2dcb5d1f02..09914b2dd2625c78a6eba2769b2501129e479b2b 100644 --- a/src/mol-canvas3d/camera.ts +++ b/src/mol-canvas3d/camera.ts @@ -278,6 +278,7 @@ namespace Camera { fog: 50, clipFar: true, minNear: 5, + minFar: 0, }; } @@ -294,6 +295,7 @@ namespace Camera { fog: number clipFar: boolean minNear: number + minFar: number } export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) { @@ -311,6 +313,7 @@ namespace Camera { if (typeof source.fog !== 'undefined') out.fog = source.fog; if (typeof source.clipFar !== 'undefined') out.clipFar = source.clipFar; if (typeof source.minNear !== 'undefined') out.minNear = source.minNear; + if (typeof source.minFar !== 'undefined') out.minFar = source.minFar; return out; } @@ -323,6 +326,7 @@ namespace Camera { && a.fog === b.fog && a.clipFar === b.clipFar && a.minNear === b.minNear + && a.minFar === b.minFar && Vec3.exactEquals(a.position, b.position) && Vec3.exactEquals(a.up, b.up) && Vec3.exactEquals(a.target, b.target); @@ -390,18 +394,14 @@ function updatePers(camera: Camera) { } function updateClip(camera: Camera) { - let { radius, radiusMax, mode, fog, clipFar, minNear } = camera.state; + let { radius, radiusMax, mode, fog, clipFar, minNear, minFar } = camera.state; if (radius < 0.01) radius = 0.01; - const normalizedFar = clipFar ? radius : radiusMax; + const normalizedFar = Math.max(clipFar ? radius : radiusMax, minFar); const cameraDistance = Vec3.distance(camera.position, camera.target); let near = cameraDistance - radius; let far = cameraDistance + normalizedFar; - const fogNearFactor = -(50 - fog) / 50; - const fogNear = cameraDistance - (normalizedFar * fogNearFactor); - const fogFar = far; - if (mode === 'perspective') { // set at least to 5 to avoid slow sphere impostor rendering near = Math.max(Math.min(radiusMax, minNear), near); @@ -417,6 +417,10 @@ function updateClip(camera: Camera) { far = near + 0.01; } + const fogNearFactor = -(50 - fog) / 50; + const fogNear = cameraDistance - (normalizedFar * fogNearFactor); + const fogFar = far; + camera.near = near; camera.far = 2 * far; // avoid precision issues distingushing far objects from background camera.fogNear = fogNear; diff --git a/src/mol-canvas3d/controls/trackball.ts b/src/mol-canvas3d/controls/trackball.ts index 1a702684f6e6a58e122290d8749c8dd7a04caa3f..08647f650748495102273cf365518354ff0ea358 100644 --- a/src/mol-canvas3d/controls/trackball.ts +++ b/src/mol-canvas3d/controls/trackball.ts @@ -451,8 +451,8 @@ namespace TrackballControls { } if (p.flyMode || input.pointerLock) { - const ds = Vec3.distance(scene.boundingSphereVisible.center, camera.position); - camera.setState({ radius: Math.max(ds, camera.state.radius) }); + const cameraDistance = Vec3.distance(camera.position, scene.boundingSphereVisible.center); + camera.setState({ minFar: cameraDistance + scene.boundingSphereVisible.radius }); } } @@ -715,11 +715,30 @@ namespace TrackballControls { const minDistance = Math.max(camera.state.minNear, p.minDistance); Vec3.setMagnitude(moveEye, moveEye, minDistance); Vec3.sub(camera.target, camera.position, moveEye); + + const cameraDistance = Vec3.distance(camera.position, scene.boundingSphereVisible.center); + camera.setState({ minFar: cameraDistance + scene.boundingSphereVisible.radius }); + } + + function resetCameraMove() { + const { center, radius } = scene.boundingSphereVisible; + const cameraDistance = Vec3.distance(camera.position, center); + if (cameraDistance > radius) { + const focus = camera.getFocus(center, radius); + camera.setState({ ...focus, minFar: 0 }); + } else { + camera.setState({ + minFar: 0, + radius: scene.boundingSphereVisible.radius, + }); + } } function onLock(isLocked: boolean) { if (isLocked) { initCameraMove(); + } else { + resetCameraMove(); } } @@ -811,8 +830,12 @@ namespace TrackballControls { if (props.animate?.name === 'rock' && p.animate.name !== 'rock') { resetRock(); // start rocking from the center } - if (props.flyMode && !p.flyMode) { - initCameraMove(); + if (props.flyMode !== undefined && props.flyMode !== p.flyMode) { + if (props.flyMode) { + initCameraMove(); + } else { + resetCameraMove(); + } } Object.assign(p, props); Object.assign(b, props.bindings);