diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd972e722db61d82e2c96afd1052da04c358560..da88454df5a946da68e11347064b7e280221ebb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf - Make `PluginContext.initContainer` checkered canvas background optional - Store URL of downloaded assets to detect zip/gzip based on extension - Add optional `operator.key`; can be referenced in `IndexPairBonds` +- Add overpaint/transparency/substance theme strength to representations ## [v3.23.0] - 2022-10-19 diff --git a/src/mol-geo/geometry/overpaint-data.ts b/src/mol-geo/geometry/overpaint-data.ts index 3c90b2bf0d46319461118aa639b47d0fd03a71ad..680a5eafeea9f79e2cbbdc39448f8437896fb7a4 100644 --- a/src/mol-geo/geometry/overpaint-data.ts +++ b/src/mol-geo/geometry/overpaint-data.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -21,6 +21,7 @@ export type OverpaintData = { uOverpaintGridDim: ValueCell<Vec3>, uOverpaintGridTransform: ValueCell<Vec4>, dOverpaintType: ValueCell<string>, + uOverpaintStrength: ValueCell<number>, } export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color) { @@ -54,6 +55,7 @@ export function createOverpaint(count: number, type: OverpaintType, overpaintDat uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dOverpaintType: ValueCell.create(type), + uOverpaintStrength: ValueCell.create(1), }; } } @@ -74,6 +76,7 @@ export function createEmptyOverpaint(overpaintData?: OverpaintData): OverpaintDa uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dOverpaintType: ValueCell.create('groupInstance'), + uOverpaintStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-geo/geometry/substance-data.ts b/src/mol-geo/geometry/substance-data.ts index 554d7e9f40fdcedc413249f5566decb70ad3e56c..d85a724556d636adff0f031e0acddd8fe4a4f4e2 100644 --- a/src/mol-geo/geometry/substance-data.ts +++ b/src/mol-geo/geometry/substance-data.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -21,6 +21,7 @@ export type SubstanceData = { uSubstanceGridDim: ValueCell<Vec3>, uSubstanceGridTransform: ValueCell<Vec4>, dSubstanceType: ValueCell<string>, + uSubstanceStrength: ValueCell<number>, } export function applySubstanceMaterial(array: Uint8Array, start: number, end: number, material: Material) { @@ -54,6 +55,7 @@ export function createSubstance(count: number, type: SubstanceType, substanceDat uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dSubstanceType: ValueCell.create(type), + uSubstanceStrength: ValueCell.create(1), }; } } @@ -74,6 +76,7 @@ export function createEmptySubstance(substanceData?: SubstanceData): SubstanceDa uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dSubstanceType: ValueCell.create('groupInstance'), + uSubstanceStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-geo/geometry/transparency-data.ts b/src/mol-geo/geometry/transparency-data.ts index a619443a7b99c42efc6db9e6e43f6e6abf6e4f36..942f95c278e6424b012b31fd715a92383d3cf137 100644 --- a/src/mol-geo/geometry/transparency-data.ts +++ b/src/mol-geo/geometry/transparency-data.ts @@ -21,6 +21,7 @@ export type TransparencyData = { uTransparencyGridDim: ValueCell<Vec3>, uTransparencyGridTransform: ValueCell<Vec4>, dTransparencyType: ValueCell<string>, + uTransparencyStrength: ValueCell<number>, } export function applyTransparencyValue(array: Uint8Array, start: number, end: number, value: number) { @@ -63,6 +64,7 @@ export function createTransparency(count: number, type: TransparencyType, transp uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dTransparencyType: ValueCell.create(type), + uTransparencyStrength: ValueCell.create(1), }; } } @@ -84,6 +86,7 @@ export function createEmptyTransparency(transparencyData?: TransparencyData): Tr uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dTransparencyType: ValueCell.create('groupInstance'), + uTransparencyStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 89b0752120f434019d180a3fab7f4773ab31dd77..23e7cbdb3df7b605f35226b73398fbcc279797c2 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -229,6 +229,7 @@ export const OverpaintSchema = { uOverpaintGridTransform: UniformSpec('v4'), tOverpaintGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'), dOverpaintType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uOverpaintStrength: UniformSpec('f', 'material'), } as const; export type OverpaintSchema = typeof OverpaintSchema export type OverpaintValues = Values<OverpaintSchema> @@ -242,7 +243,8 @@ export const TransparencySchema = { uTransparencyGridDim: UniformSpec('v3'), uTransparencyGridTransform: UniformSpec('v4'), tTransparencyGrid: TextureSpec('texture', 'alpha', 'ubyte', 'linear'), - dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']) + dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uTransparencyStrength: UniformSpec('f', 'material'), } as const; export type TransparencySchema = typeof TransparencySchema export type TransparencyValues = Values<TransparencySchema> @@ -256,6 +258,7 @@ export const SubstanceSchema = { uSubstanceGridTransform: UniformSpec('v4'), tSubstanceGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'), dSubstanceType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uSubstanceStrength: UniformSpec('f', 'material'), } as const; export type SubstanceSchema = typeof SubstanceSchema export type SubstanceValues = Values<SubstanceSchema> diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts b/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts index 7be1d4ff06dad0026c22c578131295e7ea8f37b7..1d7d510a0fdda00f327b7c40e7ea5a0f6a94001e 100644 --- a/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts +++ b/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts @@ -42,6 +42,7 @@ export const assign_color_varying = ` #else vOverpaint.rgb = mix(vColor.rgb, vOverpaint.rgb, vOverpaint.a); #endif + vOverpaint *= uOverpaintStrength; #endif #ifdef dSubstance @@ -58,6 +59,7 @@ export const assign_color_varying = ` // pre-mix to avoid artifacts due to empty substance vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a); + vSubstance *= uSubstanceStrength; #endif #elif defined(dRenderVariant_pick) #ifdef requiredDrawBuffers @@ -86,5 +88,6 @@ export const assign_color_varying = ` vec3 tgridPos = (uTransparencyGridTransform.w * (vModelPosition - uTransparencyGridTransform.xyz)) / uTransparencyGridDim; vTransparency = texture3dFrom2dLinear(tTransparencyGrid, tgridPos, uTransparencyGridDim, uTransparencyTexDim).a; #endif + vTransparency *= uTransparencyStrength; #endif `; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts index 30a830ad73651982363871cbb3fe8b1fcc20d431..aa9e5dff0b6d14581f917e18d676938398f6ed6d 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts @@ -39,6 +39,7 @@ uniform float uBumpiness; uniform vec4 uOverpaintGridTransform; uniform sampler2D tOverpaintGrid; #endif + uniform float uOverpaintStrength; #endif #ifdef dSubstance @@ -53,6 +54,7 @@ uniform float uBumpiness; uniform vec4 uSubstanceGridTransform; uniform sampler2D tSubstanceGrid; #endif + uniform float uSubstanceStrength; #endif #elif defined(dRenderVariant_pick) #if __VERSION__ == 100 || !defined(dVaryingGroup) @@ -86,5 +88,6 @@ uniform float uBumpiness; uniform vec4 uTransparencyGridTransform; uniform sampler2D tTransparencyGrid; #endif + uniform float uTransparencyStrength; #endif `; \ No newline at end of file diff --git a/src/mol-plugin-state/transforms/representation.ts b/src/mol-plugin-state/transforms/representation.ts index 32c564437b540369c43419285eb68e579a24a925..a6089db15deb00ce21368622784dfcadcb3731fc 100644 --- a/src/mol-plugin-state/transforms/representation.ts +++ b/src/mol-plugin-state/transforms/representation.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> @@ -43,6 +43,7 @@ import { Box3D } from '../../mol-math/geometry'; import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plane'; import { Substance } from '../../mol-theme/substance'; import { Material } from '../../mol-util/material'; +import { lerp } from '../../mol-math/interpolate'; export { StructureRepresentation3D }; export { ExplodeStructureRepresentation3D }; @@ -56,6 +57,7 @@ export { SubstanceStructureRepresentation3DFromScript }; export { SubstanceStructureRepresentation3DFromBundle }; export { ClippingStructureRepresentation3DFromScript }; export { ClippingStructureRepresentation3DFromBundle }; +export { ThemeStrengthRepresentation3D }; export { VolumeRepresentation3D }; type StructureRepresentation3D = typeof StructureRepresentation3D @@ -745,6 +747,62 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn } }); +type ThemeStrengthRepresentation3D = typeof ThemeStrengthRepresentation3D +const ThemeStrengthRepresentation3D = PluginStateTransform.BuiltIn({ + name: 'theme-strength-representation-3d', + display: 'Theme Strength 3D Representation', + from: SO.Molecule.Structure.Representation3D, + to: SO.Molecule.Structure.Representation3DState, + params: () => ({ + overpaintStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + transparencyStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + substanceStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + }) +})({ + canAutoUpdate() { + return true; + }, + apply({ a, params }) { + return new SO.Molecule.Structure.Representation3DState({ + state: { + themeStrength: { + overpaint: params.overpaintStrength, + transparency: params.transparencyStrength, + substance: params.substanceStrength + }, + }, + initialState: { + themeStrength: { overpaint: 1, transparency: 1, substance: 1 }, + }, + info: { }, + repr: a.data.repr + }, { label: 'Theme Strength', description: `${params.overpaintStrength.toFixed(2)}, ${params.transparencyStrength.toFixed(2)}, ${params.substanceStrength.toFixed(2)}` }); + }, + update({ a, b, newParams, oldParams }) { + if (newParams.overpaintStrength === b.data.state.themeStrength?.overpaint && + newParams.transparencyStrength === b.data.state.themeStrength?.transparency && + newParams.substanceStrength === b.data.state.themeStrength?.substance + ) return StateTransformer.UpdateResult.Unchanged; + + b.data.state.themeStrength = { + overpaint: newParams.overpaintStrength, + transparency: newParams.transparencyStrength, + substance: newParams.substanceStrength, + }; + b.data.repr = a.data.repr; + b.label = 'Theme Strength'; + b.description = `${newParams.overpaintStrength.toFixed(2)}, ${newParams.transparencyStrength.toFixed(2)}, ${newParams.substanceStrength.toFixed(2)}`; + return StateTransformer.UpdateResult.Updated; + }, + interpolate(src, tar, t) { + return { + overpaintStrength: lerp(src.overpaintStrength, tar.overpaintStrength, t), + transparencyStrength: lerp(src.transparencyStrength, tar.transparencyStrength, t), + substanceStrength: lerp(src.substanceStrength, tar.substanceStrength, t), + }; + } +}); + // export namespace VolumeRepresentation3DHelpers { diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts index 48f3c3fabfcd02942150caf224fafe0b696e3e4b..e0792376d11cca76f6c624226bb77047a368f62a 100644 --- a/src/mol-plugin/spec.ts +++ b/src/mol-plugin/spec.ts @@ -104,6 +104,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({ PluginSpec.Action(StateTransforms.Representation.TransparencyStructureRepresentation3DFromScript), PluginSpec.Action(StateTransforms.Representation.ClippingStructureRepresentation3DFromScript), PluginSpec.Action(StateTransforms.Representation.SubstanceStructureRepresentation3DFromScript), + PluginSpec.Action(StateTransforms.Representation.ThemeStrengthRepresentation3D), PluginSpec.Action(AssignColorVolume), PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4), diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index 17da5156448dd9e75ff88ae586a1106c9386825d..33b452e766d5d80467d38d2582cfdcbce22f9462 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -191,6 +191,8 @@ namespace Representation { substance: Substance /** Bit mask of per group clipping applied to the representation's renderobjects */ clipping: Clipping + /** Strength of the representations overpaint, transparency, substance*/ + themeStrength: { overpaint: number, transparency: number, substance: number } /** Controls if the representation's renderobjects are synced automatically with GPU or not */ syncManually: boolean /** A transformation applied to the representation's renderobjects */ @@ -199,7 +201,20 @@ namespace Representation { markerActions: MarkerActions } export function createState(): State { - return { visible: true, alphaFactor: 1, pickable: true, colorOnly: false, syncManually: false, transform: Mat4.identity(), overpaint: Overpaint.Empty, transparency: Transparency.Empty, substance: Substance.Empty, clipping: Clipping.Empty, markerActions: MarkerActions.All }; + return { + visible: true, + alphaFactor: 1, + pickable: true, + colorOnly: false, + syncManually: false, + transform: Mat4.identity(), + overpaint: Overpaint.Empty, + transparency: Transparency.Empty, + substance: Substance.Empty, + clipping: Clipping.Empty, + themeStrength: { overpaint: 1, transparency: 1, substance: 1 }, + markerActions: MarkerActions.All + }; } export function updateState(state: State, update: Partial<State>) { if (update.visible !== undefined) state.visible = update.visible; @@ -210,6 +225,7 @@ namespace Representation { if (update.transparency !== undefined) state.transparency = update.transparency; if (update.substance !== undefined) state.substance = update.substance; if (update.clipping !== undefined) state.clipping = update.clipping; + if (update.themeStrength !== undefined) state.themeStrength = update.themeStrength; if (update.syncManually !== undefined) state.syncManually = update.syncManually; if (update.transform !== undefined) Mat4.copy(state.transform, update.transform); if (update.markerActions !== undefined) state.markerActions = update.markerActions; @@ -432,6 +448,7 @@ namespace Representation { if (state.substance !== undefined) { // TODO } + if (state.themeStrength !== undefined) Visual.setThemeStrength(renderObject, state.themeStrength); if (state.transform !== undefined) Visual.setTransform(renderObject, state.transform); Representation.updateState(currentState, state); diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index a50d04ae0c47bda3e592bfd93e2aa2b25dcc4de3..e959f918968aaaed200bac13a026db2b64dc6b1d 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -127,6 +127,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string, const remappedClipping = Clipping.remap(state.clipping, _structure); visual.setClipping(remappedClipping); } + if (state.themeStrength !== undefined && visual) visual.setThemeStrength(state.themeStrength); if (state.transform !== undefined && visual) visual.setTransform(state.transform); if (state.unitTransforms !== undefined && visual) { // Since ComplexVisuals always renders geometries between units, the application diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 71f5314e921092800bf3a916e11bf2f480776687..526c5be397c93d512b344424b5015d7c8779a68c 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -299,6 +299,9 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge setClipping(clipping: Clipping) { Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) { diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index d7a2b6e0634e71156342aff34217ec67b23ac55b..b713ede00253e42f34151a19bd149f1157fd7e06 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -222,7 +222,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct } function setVisualState(visual: UnitsVisual<P>, group: Unit.SymmetryGroup, state: Partial<StructureRepresentationState>) { - const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms } = state; + const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms } = state; if (visible !== undefined) visual.setVisibility(visible); if (alphaFactor !== undefined) visual.setAlphaFactor(alphaFactor); @@ -231,6 +231,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct if (transparency !== undefined) visual.setTransparency(transparency, webgl); if (substance !== undefined) visual.setSubstance(substance, webgl); if (clipping !== undefined) visual.setClipping(clipping); + if (themeStrength !== undefined) visual.setThemeStrength(themeStrength); if (transform !== undefined) visual.setTransform(transform); if (unitTransforms !== undefined) { if (unitTransforms) { @@ -243,7 +244,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct } function setState(state: Partial<StructureRepresentationState>) { - const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms, syncManually, markerActions } = state; + const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms, syncManually, markerActions } = state; const newState: Partial<StructureRepresentationState> = {}; if (visible !== _state.visible) newState.visible = visible; @@ -261,6 +262,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct if (clipping !== undefined && _structure) { newState.clipping = Clipping.remap(clipping, _structure); } + if (themeStrength !== undefined) newState.themeStrength = themeStrength; if (transform !== undefined && !Mat4.areEqual(transform, _state.transform, EPSILON)) { newState.transform = transform; } diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 8c0e3a1d8b7e25488410100f02594b508ed4367a..cd5e898e7501affaa640e1b083bf543ebc30cc23 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -381,6 +381,9 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom setClipping(clipping: Clipping) { Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) { diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index 924e0fb81fa141c54b0b3e001f4b4fafeb02a3c2..4a3f41ebb38bef03cf66c8ec2d0f4ae026f0ba8b 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -55,6 +55,7 @@ interface Visual<D, P extends PD.Params> { setTransparency: (transparency: Transparency, webgl?: WebGLContext) => void setSubstance: (substance: Substance, webgl?: WebGLContext) => void setClipping: (clipping: Clipping) => void + setThemeStrength: (strength: { overpaint: number, transparency: number, substance: number }) => void destroy: () => void mustRecreate?: (data: D, props: PD.Values<P>, webgl?: WebGLContext) => boolean } @@ -349,6 +350,14 @@ namespace Visual { ValueCell.updateIfChanged(dClipping, clipping.layers.length > 0); } + export function setThemeStrength(renderObject: GraphicsRenderObject | undefined, strength: { overpaint: number, transparency: number, substance: number }) { + if (renderObject) { + ValueCell.updateIfChanged(renderObject.values.uOverpaintStrength, strength.overpaint); + ValueCell.updateIfChanged(renderObject.values.uTransparencyStrength, strength.transparency); + ValueCell.updateIfChanged(renderObject.values.uSubstanceStrength, strength.substance); + } + } + export function setTransform(renderObject: GraphicsRenderObject | undefined, transform?: Mat4, instanceTransforms?: Float32Array | null) { if (!renderObject || (!transform && !instanceTransforms)) return; diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index c6de383731b5f36a097cd321d19660c7e4502651..aa2f336d6208bc5524dff06f74278084c9cdf983 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -252,6 +252,9 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet setClipping(clipping: Clipping) { return Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) {