diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95b25c6dc00d9ba2df24f89a930b85364449f203..6c282c0cb71ab886338287d29e03b0d489cc5b14 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
- Fix Dual depth peeling when post-processing is off or when rendering direct-volumes
+- Add `cameraClipping.minNear` parameter
## [v3.18.0] - 2022-09-17
diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index 2b82c50df22dd208c232a961817a14dc06d11247..169478586e24ba8d072321be640a24eccfb887e2 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -260,7 +260,8 @@ namespace Camera {
radius: 0,
radiusMax: 10,
fog: 50,
- clipFar: true
+ clipFar: true,
+ minNear: 5,
};
}
@@ -276,6 +277,7 @@ namespace Camera {
radiusMax: number
fog: number
clipFar: boolean
+ minNear: number
}
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
@@ -292,6 +294,7 @@ namespace Camera {
if (typeof source.radiusMax !== 'undefined') out.radiusMax = source.radiusMax;
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;
return out;
}
@@ -303,6 +306,7 @@ namespace Camera {
&& a.radiusMax === b.radiusMax
&& a.fog === b.fog
&& a.clipFar === b.clipFar
+ && a.minNear === b.minNear
&& Vec3.exactEquals(a.position, b.position)
&& Vec3.exactEquals(a.up, b.up)
&& Vec3.exactEquals(a.target, b.target);
@@ -370,7 +374,7 @@ function updatePers(camera: Camera) {
}
function updateClip(camera: Camera) {
- let { radius, radiusMax, mode, fog, clipFar } = camera.state;
+ let { radius, radiusMax, mode, fog, clipFar, minNear } = camera.state;
if (radius < 0.01) radius = 0.01;
const normalizedFar = clipFar ? radius : radiusMax;
@@ -384,12 +388,12 @@ function updateClip(camera: Camera) {
if (mode === 'perspective') {
// set at least to 5 to avoid slow sphere impostor rendering
- near = Math.max(Math.min(radiusMax, 5), near);
- far = Math.max(5, far);
+ near = Math.max(Math.min(radiusMax, minNear), near);
+ far = Math.max(minNear, far);
} else {
// not too close to 0 as it causes issues with outline rendering
- near = Math.max(Math.min(radiusMax, 5), near);
- far = Math.max(5, far);
+ near = Math.max(Math.min(radiusMax, minNear), near);
+ far = Math.max(minNear, far);
}
if (near === far) {
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 24223dca18e018e7a326bfc59225cbb60879278d..ed05d3a357ba32df5d8d88e57981a2b654d5c205 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -65,6 +65,7 @@ export const Canvas3DParams = {
cameraClipping: PD.Group({
radius: PD.Numeric(100, { min: 0, max: 99, step: 1 }, { label: 'Clipping', description: 'How much of the scene to show.' }),
far: PD.Boolean(true, { description: 'Hide scene in the distance' }),
+ minNear: PD.Numeric(5, { min: 0.1, max: 10, step: 0.1 }, { description: 'Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
}, { pivot: 'radius' }),
viewport: PD.MappedStatic('canvas', {
canvas: PD.Group({}),
@@ -322,6 +323,7 @@ namespace Canvas3D {
mode: p.camera.mode,
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
clipFar: p.cameraClipping.far,
+ minNear: p.cameraClipping.minNear,
fov: degToRad(p.camera.fov),
}, { x, y, width, height }, { pixelScale: attribs.pixelScale });
const stereoCamera = new StereoCamera(camera, p.camera.stereo.params);
@@ -687,7 +689,7 @@ namespace Canvas3D {
cameraFog: camera.state.fog > 0
? { name: 'on' as const, params: { intensity: camera.state.fog } }
: { name: 'off' as const, params: {} },
- cameraClipping: { far: camera.state.clipFar, radius },
+ cameraClipping: { far: camera.state.clipFar, radius, minNear: camera.state.minNear },
cameraResetDurationMs: p.cameraResetDurationMs,
sceneRadiusFactor: p.sceneRadiusFactor,
transparentBackground: p.transparentBackground,
@@ -814,6 +816,9 @@ namespace Canvas3D {
if (props.cameraClipping.far !== undefined && props.cameraClipping.far !== camera.state.clipFar) {
cameraState.clipFar = props.cameraClipping.far;
}
+ if (props.cameraClipping.minNear !== undefined && props.cameraClipping.minNear !== camera.state.minNear) {
+ cameraState.minNear = props.cameraClipping.minNear;
+ }
if (props.cameraClipping.radius !== undefined) {
const radius = (getSceneRadius() / 100) * (100 - props.cameraClipping.radius);
if (radius > 0 && radius !== cameraState.radius) {
diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx
index 77772e62b3047fbb12b8c3a77897456380b734ff..a3f7eb6d939a26fb0db47839521823779989c94f 100644
--- a/src/mol-plugin-ui/viewport/simple-settings.tsx
+++ b/src/mol-plugin-ui/viewport/simple-settings.tsx
@@ -135,6 +135,7 @@ const SimpleSettingsMapping = ParamMapping({
canvas.cameraClipping = {
radius: s.clipping.radius,
far: s.clipping.far,
+ minNear: s.clipping.minNear,
};
props.layout = s.layout;