diff --git a/src/mol-canvas3d/helper/bounding-sphere-helper.ts b/src/mol-canvas3d/helper/bounding-sphere-helper.ts
index 84bba56ef3442a9043305e96e9dbfc7ab4b43aea..58204e881171262f5cd869950debf45c8caac7ef 100644
--- a/src/mol-canvas3d/helper/bounding-sphere-helper.ts
+++ b/src/mol-canvas3d/helper/bounding-sphere-helper.ts
@@ -12,23 +12,24 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
 import Scene from 'mol-gl/scene';
 import { WebGLContext } from 'mol-gl/webgl/context';
 import { Sphere3D } from 'mol-math/geometry';
+import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 
 export const DebugHelperParams = {
     sceneBoundingSpheres: PD.Boolean(false, { description: 'Show scene bounding spheres.' }),
     objectBoundingSpheres: PD.Boolean(false, { description: 'Show bounding spheres of render objects.' }),
+    instanceBoundingSpheres: PD.Boolean(false, { description: 'Show bounding spheres of instances.' }),
 }
 export type DebugHelperParams = typeof DebugHelperParams
 export type DebugHelperProps = PD.Values<DebugHelperParams>
 
 type BoundingSphereData = { boundingSphere: Sphere3D, renderObject: RenderObject }
 
-// TODO per-object-transform bounding spheres
-
 export class BoundingSphereHelper {
     readonly scene: Scene
     private readonly parent: Scene
     private _props: DebugHelperProps
     private objectsData = new Map<RenderObject, BoundingSphereData>()
+    private instancesData = new Map<RenderObject, BoundingSphereData>()
     private sceneData: BoundingSphereData | undefined
 
     constructor(ctx: WebGLContext, parent: Scene, props: Partial<DebugHelperProps>) {
@@ -43,9 +44,16 @@ export class BoundingSphereHelper {
 
         const oldRO = new Set<RenderObject>()
         this.parent.forEach((r, ro) => {
-            let objectData = this.objectsData.get(ro)
+            const objectData = this.objectsData.get(ro)
             const newObjectData = updateBoundingSphereData(this.scene, r.boundingSphere, objectData)
             if (newObjectData) this.objectsData.set(ro, newObjectData)
+
+            if (ro.type === 'mesh' || ro.type === 'lines' || ro.type === 'points') {
+                const instanceData = this.instancesData.get(ro)
+                const newInstanceData = updateBoundingSphereData(this.scene, ro.values.invariantBoundingSphere.ref.value, instanceData, ro.values.aTransform.ref.value, ro.values.instanceCount.ref.value)
+                if (newInstanceData) this.instancesData.set(ro, newInstanceData)
+            }
+
             oldRO.delete(ro)
         })
         oldRO.forEach(ro => {
@@ -65,7 +73,9 @@ export class BoundingSphereHelper {
         this.parent.forEach((_, ro) => {
             const objectData = this.objectsData.get(ro)
             if (objectData) objectData.renderObject.state.visible = ro.state.visible && this._props.objectBoundingSpheres
-            else console.error('expected to have debug render object')
+
+            const instanceData = this.instancesData.get(ro)
+            if (instanceData) instanceData.renderObject.state.visible = ro.state.visible && this._props.instanceBoundingSpheres
         })
     }
 
@@ -76,7 +86,7 @@ export class BoundingSphereHelper {
     }
 
     get isEnabled() {
-        return this._props.sceneBoundingSpheres || this._props.objectBoundingSpheres
+        return this._props.sceneBoundingSpheres || this._props.objectBoundingSpheres || this._props.instanceBoundingSpheres
     }
     get props() { return this._props as Readonly<DebugHelperProps> }
 
@@ -86,21 +96,28 @@ export class BoundingSphereHelper {
     }
 }
 
-function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data?: BoundingSphereData) {
+function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data: BoundingSphereData | undefined, transform?: Float32Array, transformCount?: number) {
     if (!data || !Sphere3D.exactEquals(data.boundingSphere, boundingSphere)) {
         if (data) scene.remove(data.renderObject)
-        const renderObject = createBoundingSphereRenderObject(boundingSphere)
+        const renderObject = createBoundingSphereRenderObject(boundingSphere, transform, transformCount)
         scene.add(renderObject)
         return { boundingSphere, renderObject }
     }
 }
 
-function createBoundingSphereRenderObject(boundingSphere: Sphere3D) {
+const tmpCenter = Vec3.zero()
+const tmpM = Mat4.identity()
+function createBoundingSphereRenderObject(boundingSphere: Sphere3D, transform?: Float32Array, transformCount?: number) {
     const builderState = MeshBuilder.createState(1024, 512)
-    if (boundingSphere.radius) {
-        addSphere(builderState, boundingSphere.center, boundingSphere.radius, 2)
-    } else if (isNaN(boundingSphere.radius)) {
-        console.warn('boundingSphere.radius is NaN')
+    if (transform && transformCount) {
+        // TODO create instanced mesh?
+        for (let i = 0, _i = transformCount; i < _i; ++i) {
+            Mat4.fromArray(tmpM, transform, i * 16)
+            Vec3.transformMat4(tmpCenter, boundingSphere.center, tmpM)
+            if (boundingSphere.radius) addSphere(builderState, tmpCenter, boundingSphere.radius, 1)
+        }
+    } else {
+        if (boundingSphere.radius) addSphere(builderState, boundingSphere.center, boundingSphere.radius, 2)
     }
     const mesh = MeshBuilder.getMesh(builderState)
     const values = Mesh.createValuesSimple(mesh, { alpha: 0.1, doubleSided: false })
diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts
index c26c7d9c02e93a681a84d899bc35eda7a8bce4f9..66472e954b4d4e69ed7ed9fca40193ba2c90e44e 100644
--- a/src/mol-geo/geometry/direct-volume/direct-volume.ts
+++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts
@@ -91,7 +91,7 @@ export namespace DirectVolume {
 
         const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount }
 
-        const boundingSphere = getBoundingSphere(gridDimension.ref.value, gridTransform.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value)
+        const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(gridDimension.ref.value, gridTransform.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value)
 
         const controlPoints = getControlPointsFromVec2Array(props.controlPoints)
         const transferTex = createTransferFunctionTexture(controlPoints, props.list)
@@ -107,6 +107,7 @@ export namespace DirectVolume {
             aPosition: ValueCell.create(VolumeBox.vertices as Float32Array),
             elements: ValueCell.create(VolumeBox.indices as Uint32Array),
             boundingSphere: ValueCell.create(boundingSphere),
+            invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
 
             uIsoValue: ValueCell.create(props.isoValue),
             uBboxMin: bboxMin,
@@ -135,10 +136,13 @@ export namespace DirectVolume {
     }
 
     export function updateBoundingSphere(values: DirectVolumeValues, directVolume: DirectVolume) {
-        const boundingSphere = getBoundingSphere(values.uGridDim.ref.value, values.uTransform.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value)
+        const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(values.uGridDim.ref.value, values.uTransform.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value)
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere)
         }
+        if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
+            ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
+        }
     }
 
     export function createRenderableState(props: PD.Values<Params>): RenderableState {
diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts
index 5f9fc1d1cfa77586af8792468e05a8207e268d0a..d9d377cefab034ee4a72c95ccee3f3ddf7f71b68 100644
--- a/src/mol-geo/geometry/lines/lines.ts
+++ b/src/mol-geo/geometry/lines/lines.ts
@@ -106,17 +106,9 @@ export namespace Lines {
 
         const counts = { drawCount: lines.lineCount * 2 * 3, groupCount, instanceCount }
 
-        const boundingSphere = Sphere3D.addSphere(
-            calculateBoundingSphere(
-                lines.startBuffer.ref.value, lines.lineCount,
-                transform.aTransform.ref.value, transform.instanceCount.ref.value
-            ),
-            calculateBoundingSphere(
-                lines.startBuffer.ref.value, lines.lineCount,
-                transform.aTransform.ref.value, transform.instanceCount.ref.value
-            )
-        )
-
+        const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(lines.startBuffer.ref.value, lines.endBuffer.ref.value, lines.lineCount,
+            transform.aTransform.ref.value, transform.instanceCount.ref.value)
+        
         return {
             aMapping: lines.mappingBuffer,
             aGroup: lines.groupBuffer,
@@ -124,6 +116,7 @@ export namespace Lines {
             aEnd: lines.endBuffer,
             elements: lines.indexBuffer,
             boundingSphere: ValueCell.create(boundingSphere),
+            invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
             ...color,
             ...size,
             ...marker,
@@ -142,18 +135,22 @@ export namespace Lines {
     }
 
     export function updateBoundingSphere(values: LinesValues, lines: Lines) {
-        const boundingSphere = Sphere3D.addSphere(
-            calculateBoundingSphere(
-                values.aStart.ref.value, lines.lineCount,
-                values.aTransform.ref.value, values.instanceCount.ref.value
-            ),
-            calculateBoundingSphere(
-                values.aEnd.ref.value, lines.lineCount,
-                values.aTransform.ref.value, values.instanceCount.ref.value
-            ),
-        )
+        const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(values.aStart.ref.value, values.aEnd.ref.value, lines.lineCount,
+            values.aTransform.ref.value, values.instanceCount.ref.value)
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere)
         }
+        if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
+            ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
+        }
+    }
+}
+
+function getBoundingSphere(lineStart: Float32Array, lineEnd: Float32Array, lineCount: number, transform: Float32Array, transformCount: number) {
+    const start = calculateBoundingSphere(lineStart, lineCount, transform, transformCount)
+    const end = calculateBoundingSphere(lineEnd, lineCount, transform, transformCount)
+    return {
+        boundingSphere: Sphere3D.addSphere(start.boundingSphere, end.boundingSphere),
+        invariantBoundingSphere: Sphere3D.addSphere(start.invariantBoundingSphere, end.invariantBoundingSphere)
     }
 }
\ No newline at end of file
diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts
index f6381256b11423d73cd42726c6d4819e6258185f..c638c8fa69cb1c1f3d5492d456c7bd593cde5803 100644
--- a/src/mol-geo/geometry/mesh/mesh.ts
+++ b/src/mol-geo/geometry/mesh/mesh.ts
@@ -356,7 +356,7 @@ export namespace Mesh {
 
         const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount }
 
-        const boundingSphere = calculateBoundingSphere(
+        const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
             mesh.vertexBuffer.ref.value, mesh.vertexCount,
             transform.aTransform.ref.value, transform.instanceCount.ref.value
         )
@@ -367,6 +367,7 @@ export namespace Mesh {
             aGroup: mesh.groupBuffer,
             elements: mesh.indexBuffer,
             boundingSphere: ValueCell.create(boundingSphere),
+            invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
             ...color,
             ...marker,
             ...transform,
@@ -386,7 +387,7 @@ export namespace Mesh {
 
         const counts = { drawCount: mesh.triangleCount * 3, groupCount: 1, instanceCount: 1 }
 
-        const boundingSphere = calculateBoundingSphere(
+        const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
             mesh.vertexBuffer.ref.value, mesh.vertexCount,
             transform.aTransform.ref.value, transform.instanceCount.ref.value
         )
@@ -397,6 +398,7 @@ export namespace Mesh {
             aGroup: mesh.groupBuffer,
             elements: mesh.indexBuffer,
             boundingSphere: ValueCell.create(boundingSphere),
+            invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
             ...color,
             ...marker,
             ...transform,
@@ -416,13 +418,16 @@ export namespace Mesh {
     }
 
     export function updateBoundingSphere(values: MeshValues, mesh: Mesh) {
-        const boundingSphere = calculateBoundingSphere(
+        const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
             values.aPosition.ref.value, mesh.vertexCount,
             values.aTransform.ref.value, values.instanceCount.ref.value
         )
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere)
         }
+        if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
+            ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
+        }
     }
 }
 
diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts
index 2a3e2288065610d2b7a178eab9aa22cd8188a537..598c3b00cec4479bb9461040b9eb4a7739f8960d 100644
--- a/src/mol-geo/geometry/points/points.ts
+++ b/src/mol-geo/geometry/points/points.ts
@@ -71,7 +71,7 @@ export namespace Points {
 
         const counts = { drawCount: points.pointCount, groupCount, instanceCount }
 
-        const boundingSphere = calculateBoundingSphere(
+        const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
             points.centerBuffer.ref.value, points.pointCount,
             transform.aTransform.ref.value, transform.instanceCount.ref.value
         )
@@ -80,6 +80,7 @@ export namespace Points {
             aPosition: points.centerBuffer,
             aGroup: points.groupBuffer,
             boundingSphere: ValueCell.create(boundingSphere),
+            invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
             ...color,
             ...size,
             ...marker,
@@ -100,13 +101,16 @@ export namespace Points {
     }
 
     export function updateBoundingSphere(values: PointsValues, points: Points) {
-        const boundingSphere = calculateBoundingSphere(
+        const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
             values.aPosition.ref.value, points.pointCount,
             values.aTransform.ref.value, values.instanceCount.ref.value
         )
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere)
         }
+        if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
+            ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
+        }
     }
 
     export function createRenderableState(props: PD.Values<Params>): RenderableState {
diff --git a/src/mol-gl/_spec/renderable.spec.ts b/src/mol-gl/_spec/renderable.spec.ts
index 9053ec9d130ac52dd20f2aad02565bc4fc6e029c..ab0f26a504a1bcd49f6a50d44153c0a12f59e67f 100644
--- a/src/mol-gl/_spec/renderable.spec.ts
+++ b/src/mol-gl/_spec/renderable.spec.ts
@@ -29,12 +29,12 @@ describe('renderable', () => {
             2, 0, 0, 0
         ])
 
-        const bs = calculateBoundingSphere(
+        const { boundingSphere } = calculateBoundingSphere(
             position, position.length / 3,
             transform, transform.length / 16
         )
 
-        expect(bs.radius).toBe(1.5)
-        expect(bs.center).toEqual([1.5, 0.0, 0.0])
+        expect(boundingSphere.radius).toBe(1.5)
+        expect(boundingSphere.center).toEqual([1.5, 0.0, 0.0])
     })
 })
diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts
index c36edb83df75e780804a5e4379d428c274f30aff..64a859e14cd5a44824cad68fd517bc284ecb5ffe 100644
--- a/src/mol-gl/_spec/renderer.spec.ts
+++ b/src/mol-gl/_spec/renderer.spec.ts
@@ -58,6 +58,7 @@ function createPoints() {
     Mat4.toArray(m4, aTransform.ref.value, 0)
 
     const boundingSphere = ValueCell.create(Sphere3D.create(Vec3.zero(), 2))
+    const invariantBoundingSphere = ValueCell.create(Sphere3D.create(Vec3.zero(), 2))
 
     const values: PointsValues = {
         aPosition,
@@ -77,6 +78,7 @@ function createPoints() {
         drawCount: ValueCell.create(3),
         instanceCount: ValueCell.create(1),
         boundingSphere,
+        invariantBoundingSphere,
 
         dPointSizeAttenuation: ValueCell.create(true),
         dPointFilledCircle: ValueCell.create(false),
diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts
index a4c9d533b0956fb733a0ec38e4be70702f0a0d8c..228cdec89e6fb0f5111b0c4e41d7d12d527ef7b9 100644
--- a/src/mol-gl/renderable/direct-volume.ts
+++ b/src/mol-gl/renderable/direct-volume.ts
@@ -29,6 +29,7 @@ export const DirectVolumeSchema = {
     drawCount: ValueSpec('number'),
     instanceCount: ValueSpec('number'),
     boundingSphere: ValueSpec('sphere'),
+    invariantBoundingSphere: ValueSpec('sphere'),
 
     aPosition: AttributeSpec('float32', 3, 0),
     elements: ElementsSpec('uint32'),
diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts
index 9cf03c9b48fd055f3dabaa4dfbeddabfed62e442..3bfac0c71e543d278ab36709b3210c8241a10f63 100644
--- a/src/mol-gl/renderable/schema.ts
+++ b/src/mol-gl/renderable/schema.ts
@@ -199,6 +199,7 @@ export const BaseSchema = {
     drawCount: ValueSpec('number'),
     instanceCount: ValueSpec('number'),
     boundingSphere: ValueSpec('sphere'),
+    invariantBoundingSphere: ValueSpec('sphere'),
 
     dUseFog: DefineSpec('boolean'),
 }
diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts
index aa77abc80ca4623901e7ac251d87425c630ab345..75d3046f6983a5bf1d0ab3972ace5d05cf43cd0b 100644
--- a/src/mol-gl/renderable/util.ts
+++ b/src/mol-gl/renderable/util.ts
@@ -55,7 +55,7 @@ export function calculateBoundingSphereFromValues(values: PositionValues) {
     return calculateBoundingSphere(position, positionCount, transform, transformCount)
 }
 
-export function calculateBoundingSphere(position: Float32Array, positionCount: number, transform: Float32Array, transformCount: number): Sphere3D {
+export function calculateBoundingSphere(position: Float32Array, positionCount: number, transform: Float32Array, transformCount: number): { boundingSphere: Sphere3D, invariantBoundingSphere: Sphere3D } {
 
     const m = Mat4.zero()
 
@@ -105,5 +105,5 @@ export function calculateBoundingSphere(position: Float32Array, positionCount: n
         radius = Math.max(radius, Vec3.distance(center, ct) + r)
     }
 
-    return { center, radius };
+    return { boundingSphere: { center, radius }, invariantBoundingSphere: { center: c, radius: r } };
 }
\ No newline at end of file