Browse Source

added materialId to render-items and reprs

Alexander Rose 6 years ago
parent
commit
8ebd2642f0
53 changed files with 177 additions and 251 deletions
  1. 3 2
      src/mol-canvas3d/helper/bounding-sphere-helper.ts
  2. 2 1
      src/mol-geo/geometry/base.ts
  3. 1 1
      src/mol-gl/_spec/renderer.spec.ts
  4. 11 9
      src/mol-gl/render-object.ts
  5. 3 3
      src/mol-gl/renderable/direct-volume.ts
  6. 1 1
      src/mol-gl/renderable/gaussian-density.ts
  7. 2 2
      src/mol-gl/renderable/lines.ts
  8. 2 2
      src/mol-gl/renderable/mesh.ts
  9. 2 2
      src/mol-gl/renderable/points.ts
  10. 26 21
      src/mol-gl/renderable/schema.ts
  11. 2 2
      src/mol-gl/renderable/spheres.ts
  12. 2 2
      src/mol-gl/renderable/text.ts
  13. 3 2
      src/mol-gl/renderer.ts
  14. 0 6
      src/mol-gl/shader/chunks/common-vert-params.glsl
  15. 1 30
      src/mol-gl/webgl/buffer.ts
  16. 2 0
      src/mol-gl/webgl/context.ts
  17. 4 46
      src/mol-gl/webgl/program.ts
  18. 10 8
      src/mol-gl/webgl/render-item.ts
  19. 0 15
      src/mol-gl/webgl/uniform.ts
  20. 1 1
      src/mol-math/geometry/gaussian-density/gpu.ts
  21. 2 2
      src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts
  22. 3 2
      src/mol-repr/shape/representation.ts
  23. 4 3
      src/mol-repr/structure/complex-representation.ts
  24. 8 8
      src/mol-repr/structure/complex-visual.ts
  25. 5 4
      src/mol-repr/structure/units-representation.ts
  26. 14 14
      src/mol-repr/structure/units-visual.ts
  27. 2 2
      src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts
  28. 2 2
      src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts
  29. 2 2
      src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts
  30. 2 2
      src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts
  31. 2 2
      src/mol-repr/structure/visual/element-point.ts
  32. 4 4
      src/mol-repr/structure/visual/element-sphere.ts
  33. 2 2
      src/mol-repr/structure/visual/gaussian-density-point.ts
  34. 2 2
      src/mol-repr/structure/visual/gaussian-density-volume.ts
  35. 2 2
      src/mol-repr/structure/visual/gaussian-surface-mesh.ts
  36. 2 2
      src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
  37. 2 2
      src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
  38. 2 2
      src/mol-repr/structure/visual/intra-unit-link-cylinder.ts
  39. 2 2
      src/mol-repr/structure/visual/nucleotide-block-mesh.ts
  40. 2 2
      src/mol-repr/structure/visual/nucleotide-ring-mesh.ts
  41. 2 2
      src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
  42. 2 2
      src/mol-repr/structure/visual/polymer-direction-wedge.ts
  43. 2 2
      src/mol-repr/structure/visual/polymer-gap-cylinder.ts
  44. 2 2
      src/mol-repr/structure/visual/polymer-trace-mesh.ts
  45. 2 2
      src/mol-repr/structure/visual/polymer-tube-mesh.ts
  46. 2 2
      src/mol-repr/volume/direct-volume.ts
  47. 4 4
      src/mol-repr/volume/isosurface.ts
  48. 8 7
      src/mol-repr/volume/representation.ts
  49. 1 1
      src/tests/browser/render-lines.ts
  50. 2 2
      src/tests/browser/render-mesh.ts
  51. 1 1
      src/tests/browser/render-spheres.ts
  52. 3 3
      src/tests/browser/render-structure.ts
  53. 2 2
      src/tests/browser/render-text.ts

+ 3 - 2
src/mol-canvas3d/helper/bounding-sphere-helper.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { createRenderObject, RenderObject } from 'mol-gl/render-object'
+import { createRenderObject, RenderObject, getNextMaterialId } from 'mol-gl/render-object'
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -136,7 +136,8 @@ function createBoundingSphereMesh(boundingSphere: Sphere3D, mesh?: Mesh) {
     return MeshBuilder.getMesh(builderState)
 }
 
+const boundingSphereHelberMaterialId = getNextMaterialId()
 function createBoundingSphereRenderObject(mesh: Mesh, color: Color, transform?: TransformData) {
     const values = Mesh.Utils.createValuesSimple(mesh, { alpha: 0.1, doubleSided: false }, color, 1, transform)
-    return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, opaque: false })
+    return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, opaque: false }, boundingSphereHelberMaterialId)
 }

+ 2 - 1
src/mol-geo/geometry/base.ts

@@ -64,9 +64,10 @@ export namespace BaseGeometry {
             uAlpha: ValueCell.create(props.alpha),
             uHighlightColor: ValueCell.create(Color.toArrayNormalized(props.highlightColor, Vec3.zero(), 0)),
             uSelectColor: ValueCell.create(Color.toArrayNormalized(props.selectColor, Vec3.zero(), 0)),
+            dUseFog: ValueCell.create(props.useFog),
+
             uGroupCount: ValueCell.create(counts.groupCount),
             drawCount: ValueCell.create(counts.drawCount),
-            dUseFog: ValueCell.create(props.useFog),
         }
     }
 

+ 1 - 1
src/mol-gl/_spec/renderer.spec.ts

@@ -102,7 +102,7 @@ function createPoints() {
         opaque: true
     }
 
-    return createRenderObject('points', values, state)
+    return createRenderObject('points', values, state, -1)
 }
 
 describe('renderer', () => {

+ 11 - 9
src/mol-gl/render-object.ts

@@ -18,7 +18,9 @@ import { TextValues, TextRenderable } from './renderable/text';
 
 const getNextId = idFactory(0, 0x7FFFFFFF)
 
-export interface BaseRenderObject { id: number, type: string, values: RenderableValues, state: RenderableState }
+export const getNextMaterialId = idFactory(0, 0x7FFFFFFF)
+
+export interface BaseRenderObject { id: number, type: string, values: RenderableValues, state: RenderableState, materialId: number }
 export interface MeshRenderObject extends BaseRenderObject { type: 'mesh', values: MeshValues }
 export interface PointsRenderObject extends BaseRenderObject { type: 'points', values: PointsValues }
 export interface SpheresRenderObject extends BaseRenderObject { type: 'spheres', values: SpheresValues }
@@ -60,18 +62,18 @@ export type RenderObjectType = keyof RenderObjectKindType
 
 //
 
-export function createRenderObject<T extends RenderObjectType>(type: T, values: RenderObjectValuesType[T], state: RenderableState): RenderObjectKindType[T] {
-    return { id: getNextId(), type, values, state } as RenderObjectKindType[T]
+export function createRenderObject<T extends RenderObjectType>(type: T, values: RenderObjectValuesType[T], state: RenderableState, materialId: number): RenderObjectKindType[T] {
+    return { id: getNextId(), type, values, state, materialId } as RenderObjectKindType[T]
 }
 
 export function createRenderable(ctx: WebGLContext, o: RenderObject): Renderable<any> {
     switch (o.type) {
-        case 'mesh': return MeshRenderable(ctx, o.id, o.values, o.state)
-        case 'points': return PointsRenderable(ctx, o.id, o.values, o.state)
-        case 'spheres': return SpheresRenderable(ctx, o.id, o.values, o.state)
-        case 'text': return TextRenderable(ctx, o.id, o.values, o.state)
-        case 'lines': return LinesRenderable(ctx, o.id, o.values, o.state)
-        case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values, o.state)
+        case 'mesh': return MeshRenderable(ctx, o.id, o.values, o.state, o.materialId)
+        case 'points': return PointsRenderable(ctx, o.id, o.values, o.state, o.materialId)
+        case 'spheres': return SpheresRenderable(ctx, o.id, o.values, o.state, o.materialId)
+        case 'text': return TextRenderable(ctx, o.id, o.values, o.state, o.materialId)
+        case 'lines': return LinesRenderable(ctx, o.id, o.values, o.state, o.materialId)
+        case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values, o.state, o.materialId)
 
         case 'gaussian-density': return GaussianDensityRenderable(ctx, o.id, o.values, o.state)
     }

+ 3 - 3
src/mol-gl/renderable/direct-volume.ts

@@ -67,13 +67,13 @@ export const DirectVolumeSchema = {
 export type DirectVolumeSchema = typeof DirectVolumeSchema
 export type DirectVolumeValues = Values<DirectVolumeSchema>
 
-export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: DirectVolumeValues, state: RenderableState): Renderable<DirectVolumeValues> {
+export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: DirectVolumeValues, state: RenderableState, materialId: number): Renderable<DirectVolumeValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...DirectVolumeSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
-        uPickable: ValueCell.create(state.pickable ? 1 : 0)
+        uPickable: ValueCell.create(state.pickable ? 1 : 0),
     }
     const shaderCode = DirectVolumeShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
     return createRenderable(renderItem, values, state);
 }

+ 1 - 1
src/mol-gl/renderable/gaussian-density.ts

@@ -38,7 +38,7 @@ export type GaussianDensityValues = Values<GaussianDensitySchema>
 export function GaussianDensityRenderable(ctx: WebGLContext, id: number, values: GaussianDensityValues, state: RenderableState): Renderable<GaussianDensityValues> {
     const schema = { ...GaussianDensitySchema }
     const shaderCode = GaussianDensityShaderCode
-    const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, values)
+    const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, values, -1)
 
     return createRenderable(renderItem, values, state);
 }

+ 2 - 2
src/mol-gl/renderable/lines.ts

@@ -25,14 +25,14 @@ export const LinesSchema = {
 export type LinesSchema = typeof LinesSchema
 export type LinesValues = Values<LinesSchema>
 
-export function LinesRenderable(ctx: WebGLContext, id: number, values: LinesValues, state: RenderableState): Renderable<LinesValues> {
+export function LinesRenderable(ctx: WebGLContext, id: number, values: LinesValues, state: RenderableState, materialId: number): Renderable<LinesValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...LinesSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
         uPickable: ValueCell.create(state.pickable ? 1 : 0)
     }
     const shaderCode = LinesShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
 
     return createRenderable(renderItem, values, state);
 }

+ 2 - 2
src/mol-gl/renderable/mesh.ts

@@ -23,14 +23,14 @@ export const MeshSchema = {
 export type MeshSchema = typeof MeshSchema
 export type MeshValues = Values<MeshSchema>
 
-export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues, state: RenderableState): Renderable<MeshValues> {
+export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues, state: RenderableState, materialId: number): Renderable<MeshValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...MeshSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
         uPickable: ValueCell.create(state.pickable ? 1 : 0)
     }
     const shaderCode = MeshShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
 
     return createRenderable(renderItem, values, state)
 }

+ 2 - 2
src/mol-gl/renderable/points.ts

@@ -22,13 +22,13 @@ export const PointsSchema = {
 export type PointsSchema = typeof PointsSchema
 export type PointsValues = Values<PointsSchema>
 
-export function PointsRenderable(ctx: WebGLContext, id: number, values: PointsValues, state: RenderableState): Renderable<PointsValues> {
+export function PointsRenderable(ctx: WebGLContext, id: number, values: PointsValues, state: RenderableState, materialId: number): Renderable<PointsValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...PointsSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
         uPickable: ValueCell.create(state.pickable ? 1 : 0)
     }
     const shaderCode = PointsShaderCode
-    const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues }, materialId)
     return createRenderable(renderItem, values, state);
 }

+ 26 - 21
src/mol-gl/renderable/schema.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -68,27 +68,32 @@ export function splitValues(schema: RenderableSchema, values: RenderableValues)
     const defineValues: DefineValues = {}
     const textureValues: TextureValues = {}
     const uniformValues: UniformValues = {}
+    const materialUniformValues: UniformValues = {}
     Object.keys(schema).forEach(k => {
-        if (schema[k].type === 'attribute') attributeValues[k] = values[k]
-        if (schema[k].type === 'define') defineValues[k] = values[k]
-        if (schema[k].type === 'texture') textureValues[k] = values[k]
-        if (schema[k].type === 'uniform') uniformValues[k] = values[k]
+        const spec = schema[k]
+        if (spec.type === 'attribute') attributeValues[k] = values[k]
+        if (spec.type === 'define') defineValues[k] = values[k]
+        if (spec.type === 'texture') textureValues[k] = values[k]
+        // check if k exists in values so that global uniforms are excluded here
+        if (spec.type === 'uniform' && values[k] !== undefined) {
+            if (spec.isMaterial) materialUniformValues[k] = values[k]
+            else uniformValues[k] = values[k]
+        }
     })
-    return { attributeValues, defineValues, textureValues, uniformValues }
+    return { attributeValues, defineValues, textureValues, uniformValues, materialUniformValues }
 }
 
 export function splitKeys(schema: RenderableSchema) {
     const attributeKeys: string[] = []
     const defineKeys: string[] = []
     const textureKeys: string[] = []
-    const uniformKeys: string[] = []
     Object.keys(schema).forEach(k => {
-        if (schema[k].type === 'attribute') attributeKeys.push(k)
-        if (schema[k].type === 'define') defineKeys.push(k)
-        if (schema[k].type === 'texture') textureKeys.push(k)
-        if (schema[k].type === 'uniform') uniformKeys.push(k)
+        const spec = schema[k]
+        if (spec.type === 'attribute') attributeKeys.push(k)
+        if (spec.type === 'define') defineKeys.push(k)
+        if (spec.type === 'texture') textureKeys.push(k)
     })
-    return { attributeKeys, defineKeys, textureKeys, uniformKeys }
+    return { attributeKeys, defineKeys, textureKeys }
 }
 
 export type Versions<T extends RenderableValues> = { [k in keyof T]: number }
@@ -107,9 +112,9 @@ export function AttributeSpec<K extends ArrayKind>(kind: K, itemSize: AttributeI
     return { type: 'attribute', kind, itemSize, divisor }
 }
 
-export type UniformSpec<K extends UniformKind> = { type: 'uniform', kind: K }
-export function UniformSpec<K extends UniformKind>(kind: K): UniformSpec<K> {
-    return { type: 'uniform', kind }
+export type UniformSpec<K extends UniformKind> = { type: 'uniform', kind: K, isMaterial: boolean }
+export function UniformSpec<K extends UniformKind>(kind: K, isMaterial = false): UniformSpec<K> {
+    return { type: 'uniform', kind, isMaterial }
 }
 
 export type TextureSpec<K extends TextureKind> = { type: 'texture', kind: K, format: TextureFormat, dataType: TextureType, filter: TextureFilter }
@@ -174,14 +179,14 @@ export type GlobalUniformValues = { [k in keyof GlobalUniformSchema]: ValueCell<
 
 export const InternalSchema = {
     uObjectId: UniformSpec('i'),
-    uPickable: UniformSpec('i'),
+    uPickable: UniformSpec('i', true),
 }
 export type InternalSchema = typeof InternalSchema
 export type InternalValues = { [k in keyof InternalSchema]: ValueCell<any> }
 
 export const ColorSchema = {
     // aColor: AttributeSpec('float32', 3, 0), // TODO
-    uColor: UniformSpec('v3'),
+    uColor: UniformSpec('v3', true),
     uColorTexDim: UniformSpec('v2'),
     tColor: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'),
     dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'group_instance']),
@@ -191,7 +196,7 @@ export type ColorValues = Values<ColorSchema>
 
 export const SizeSchema = {
     // aSize: AttributeSpec('float32', 1, 0), // TODO
-    uSize: UniformSpec('f'),
+    uSize: UniformSpec('f', true),
     uSizeTexDim: UniformSpec('v2'),
     tSize: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
     dSizeType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'group_instance']),
@@ -231,12 +236,12 @@ export const BaseSchema = {
     /**
      * final alpha, calculated as `values.alpha * state.alpha`
      */
-    uAlpha: UniformSpec('f'),
+    uAlpha: UniformSpec('f', true),
     uInstanceCount: UniformSpec('i'),
     uGroupCount: UniformSpec('i'),
 
-    uHighlightColor: UniformSpec('v3'),
-    uSelectColor: UniformSpec('v3'),
+    uHighlightColor: UniformSpec('v3', true),
+    uSelectColor: UniformSpec('v3', true),
 
     drawCount: ValueSpec('number'),
     instanceCount: ValueSpec('number'),

+ 2 - 2
src/mol-gl/renderable/spheres.ts

@@ -24,13 +24,13 @@ export const SpheresSchema = {
 export type SpheresSchema = typeof SpheresSchema
 export type SpheresValues = Values<SpheresSchema>
 
-export function SpheresRenderable(ctx: WebGLContext, id: number, values: SpheresValues, state: RenderableState): Renderable<SpheresValues> {
+export function SpheresRenderable(ctx: WebGLContext, id: number, values: SpheresValues, state: RenderableState, materialId: number): Renderable<SpheresValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...SpheresSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
         uPickable: ValueCell.create(state.pickable ? 1 : 0)
     }
     const shaderCode = SpheresShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
     return createRenderable(renderItem, values, state);
 }

+ 2 - 2
src/mol-gl/renderable/text.ts

@@ -34,13 +34,13 @@ export const TextSchema = {
 export type TextSchema = typeof TextSchema
 export type TextValues = Values<TextSchema>
 
-export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues, state: RenderableState): Renderable<TextValues> {
+export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues, state: RenderableState, materialId: number): Renderable<TextValues> {
     const schema = { ...GlobalUniformSchema, ...InternalSchema, ...TextSchema }
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
         uPickable: ValueCell.create(state.pickable ? 1 : 0)
     }
     const shaderCode = TextShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
     return createRenderable(renderItem, values, state);
 }

+ 3 - 2
src/mol-gl/renderer.ts

@@ -1,10 +1,9 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-// import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Viewport } from 'mol-canvas3d/camera/util';
 import { Camera } from 'mol-canvas3d/camera';
 
@@ -112,11 +111,13 @@ namespace Renderer {
             const program = r.getProgram(variant)
             if (r.state.visible) {
                 if (ctx.currentProgramId !== program.id) {
+                    // console.log('new program')
                     globalUniformsNeedUpdate = true
                 }
 
                 program.use()
                 if (globalUniformsNeedUpdate) {
+                    // console.log('globalUniformsNeedUpdate')
                     program.setUniforms(globalUniforms)
                     globalUniformsNeedUpdate = false
                 }

+ 0 - 6
src/mol-gl/shader/chunks/common-vert-params.glsl

@@ -1,12 +1,6 @@
 uniform mat4 uProjection, uModel, uView;
 uniform vec3 uCameraPosition;
 
-uniform Common {
-    mat4 uProjection;
-    int uObjectId;
-    int uInstanceCount;
-} uboCommon;
-
 uniform int uObjectId;
 uniform int uInstanceCount;
 uniform int uGroupCount;

+ 1 - 30
src/mol-gl/webgl/buffer.ts

@@ -215,33 +215,4 @@ export function createElementsBuffer(ctx: WebGLContext, array: ElementsType, usa
             gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _buffer);
         }
     }
-}
-
-//
-
-export type UniformType = Float32Array
-export type UniformKind = 'float32'
-
-// export type AttributeDefs = {
-//     [k: string]: { kind: ArrayKind, itemSize: BufferItemSize, divisor: number }
-// }
-// export type AttributeValues = { [k: string]: ValueCell<ArrayType> }
-export type UniformBuffers = { [k: string]: UniformBuffer }
-
-export interface UniformBuffer extends Buffer {
-    bind: (location: number) => void
-}
-
-export function createUniformBuffer(ctx: WebGLContext, array: UniformType, usageHint: UsageHint = 'dynamic'): UniformBuffer {
-    const gl = ctx.gl as WebGL2RenderingContext
-    const buffer = createBuffer(ctx, array, usageHint, 'uniform')
-    const { _buffer } = buffer
-
-    return {
-        ...buffer,
-        bind: (location: number) => {
-            gl.bindBuffer(gl.UNIFORM_BUFFER, _buffer)
-            gl.bindBufferBase(gl.UNIFORM_BUFFER, location, _buffer)
-        }
-    }
-}
+}

+ 2 - 0
src/mol-gl/webgl/context.ts

@@ -136,6 +136,7 @@ export interface WebGLContext {
     readonly framebufferCache: FramebufferCache
 
     currentProgramId: number
+    currentMaterialId: number
 
     bufferCount: number
     framebufferCount: number
@@ -263,6 +264,7 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
         framebufferCache,
 
         currentProgramId: -1,
+        currentMaterialId: -1,
 
         bufferCount: 0,
         framebufferCount: 0,

+ 4 - 46
src/mol-gl/webgl/program.ts

@@ -7,7 +7,8 @@
 import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code'
 import { WebGLContext } from './context';
 import { UniformValues, getUniformSetters } from './uniform';
-import { AttributeBuffers, UniformBuffers, createUniformBuffer } from './buffer';
+import { AttributeBuffers } from './buffer';
+// import { AttributeBuffers, UniformBuffers, createUniformBuffer } from './buffer';
 import { Textures, TextureId } from './texture';
 import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
 import { idFactory } from 'mol-util/id-factory';
@@ -21,8 +22,6 @@ export interface Program {
 
     use: () => void
     setUniforms: (uniformValues: UniformValues) => void
-    setUniformBuffers: (uniformBuffers: UniformBuffers, uniformValues: UniformValues) => void
-    bindUniformBuffers: (/* uniformBuffers: UniformBuffers */) => void
     bindAttributes: (attribueBuffers: AttributeBuffers) => void
     bindTextures: (textures: Textures) => void
 
@@ -79,32 +78,6 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
     const locations = getLocations(ctx, program, schema)
     const uniformSetters = getUniformSetters(schema)
 
-    interface UniformBufferInfo {
-        blockIndex: number,
-        blockSize: number,
-        uniformIndices: number[],
-        uniformOffsets: number[]
-    }
-    function getUniformBufferInfo(gl: WebGL2RenderingContext, program: WebGLProgram, name: string, uniformNames: string[]): UniformBufferInfo {
-        const blockIndex = gl.getUniformBlockIndex(program, name)
-        const blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE)
-        const uniformIndices = gl.getUniformIndices(program, uniformNames)
-        if (uniformIndices === null) throw new Error(`Could not get uniform indices`)
-        const uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET)
-        return { blockIndex, blockSize, uniformIndices, uniformOffsets }
-    }
-
-    const uniformBufferInfos: { [k: string]: UniformBufferInfo } = {
-        'Common': getUniformBufferInfo(gl as WebGL2RenderingContext, program, 'Common', [
-            'Common.uProjection', 'Common.uObjectId', 'Common.uInstanceCount'
-        ])
-    }
-    console.log(uniformBufferInfos)
-
-    const uniformBuffers: UniformBuffers = {
-        'Common': createUniformBuffer(ctx, new Float32Array(uniformBufferInfos['Common'].blockSize))
-    }
-
     let destroyed = false
 
     return {
@@ -124,23 +97,6 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
                 if (v) uniformSetters[k](gl, l, v.ref.value)
             }
         },
-        setUniformBuffers: (uniformBuffers: UniformBuffers, uniformValues: UniformValues) => {
-            const uniformBufferKeys = Object.keys(uniformBuffers)
-            for (let i = 0, il = uniformBufferKeys.length; i < il; ++i) {
-                // const k = uniformBufferKeys[i]
-                // const info = uniformBufferInfos[k]
-                // uniformBuffers[k].updateData()
-            }
-        },
-        bindUniformBuffers: (/* uniformBuffers: UniformBuffers */) => {
-            const uniformBufferKeys = Object.keys(uniformBuffers)
-            for (let i = 0, il = uniformBufferKeys.length; i < il; ++i) {
-                const k = uniformBufferKeys[i]
-                const info = uniformBufferInfos[k]
-                uniformBuffers[k].bind(i)
-                ;(gl as WebGL2RenderingContext).uniformBlockBinding(program, info.blockIndex, i)
-            }
-        },
         bindAttributes: (attribueBuffers: AttributeBuffers) => {
             const attributeKeys = Object.keys(attribueBuffers)
             for (let i = 0, il = attributeKeys.length; i < il; ++i) {
@@ -155,6 +111,8 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
                 const k = textureKeys[i]
                 const l = locations[k]
                 textures[k].bind(i as TextureId)
+                // TODO if the order and count of textures in a material can be made invariant
+                //      this needs to be set only when the material changes
                 uniformSetters[k](gl, l, i as TextureId)
             }
         },

+ 10 - 8
src/mol-gl/webgl/render-item.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -58,7 +58,7 @@ interface ValueChanges {
     defines: boolean
     elements: boolean
     textures: boolean
-    uniforms: boolean
+    // uniforms: boolean
 }
 function createValueChanges() {
     return {
@@ -66,7 +66,6 @@ function createValueChanges() {
         defines: false,
         elements: false,
         textures: false,
-        uniforms: false,
     }
 }
 function resetValueChanges(valueChanges: ValueChanges) {
@@ -74,7 +73,6 @@ function resetValueChanges(valueChanges: ValueChanges) {
     valueChanges.defines = false
     valueChanges.elements = false
     valueChanges.textures = false
-    valueChanges.uniforms = false
 }
 
 // TODO make `RenderVariantDefines` a parameter for `createRenderItem`
@@ -84,12 +82,12 @@ function resetValueChanges(valueChanges: ValueChanges) {
  *
  * - assumes that `values.drawCount` and `values.instanceCount` exist
  */
-export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues): RenderItem {
+export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number): RenderItem {
     const id = getNextRenderItemId()
     const { programCache } = ctx
     const { instancedArrays, vertexArrayObject } = ctx.extensions
 
-    const { attributeValues, defineValues, textureValues, uniformValues } = splitValues(schema, values)
+    const { attributeValues, defineValues, textureValues, uniformValues, materialUniformValues } = splitValues(schema, values)
     const { attributeKeys, defineKeys, textureKeys } = splitKeys(schema)
     const versions = getValueVersions(values)
 
@@ -139,7 +137,12 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
             const program = programs[variant].value
             const vertexArray = vertexArrays[variant]
             program.setUniforms(uniformValues)
-            program.bindUniformBuffers()
+            if (materialId === -1 || materialId !== ctx.currentMaterialId) {
+                // console.log('materialId changed or -1', materialId)
+                program.setUniforms(materialUniformValues)
+                ctx.currentMaterialId = materialId
+            }
+            program.bindTextures(textures)
             if (vertexArrayObject && vertexArray) {
                 vertexArrayObject.bindVertexArray(vertexArray)
                 // need to bind elements buffer explicitly since it is not always recorded in the VAO
@@ -148,7 +151,6 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
                 if (elementsBuffer) elementsBuffer.bind()
                 program.bindAttributes(attributeBuffers)
             }
-            program.bindTextures(textures)
             if (elementsBuffer) {
                 instancedArrays.drawElementsInstanced(glDrawMode, drawCount, elementsBuffer._dataType, 0, instanceCount);
             } else {

+ 0 - 15
src/mol-gl/webgl/uniform.ts

@@ -8,7 +8,6 @@ import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra'
 import { ValueCell } from 'mol-util';
 import { GLRenderingContext } from './compat';
 import { RenderableSchema } from 'mol-gl/renderable/schema';
-import { WebGLContext } from './context';
 
 export type UniformKindValue = {
     'f': number
@@ -73,18 +72,4 @@ export function getUniformSetters(schema: RenderableSchema) {
         }
     })
     return setters
-}
-
-//
-
-export interface UniformBlock {
-    update(): void
-    bind(): void
-}
-
-export function createUniformBlock(ctx: WebGLContext, ) {
-
-    return {
-        
-    }
 }

+ 1 - 1
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -237,7 +237,7 @@ function getGaussianDensityRenderObject(webgl: WebGLContext, drawCount: number,
         opaque: true
     }
 
-    const renderObject = createRenderObject('gaussian-density', values, state)
+    const renderObject = createRenderObject('gaussian-density', values, state, -1)
 
     return renderObject
 }

+ 2 - 2
src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts

@@ -59,7 +59,7 @@ export const AssemblySymmetryAxesRepresentationProvider: StructureRepresentation
 
 //
 
-export function AssemblySymmetryAxesVisual(): ComplexVisual<AssemblySymmetryAxesParams> {
+export function AssemblySymmetryAxesVisual(materialId: number): ComplexVisual<AssemblySymmetryAxesParams> {
     return ComplexMeshVisual<AssemblySymmetryAxesParams>({
         defaultProps: PD.getDefaultValues(AssemblySymmetryAxesParams),
         createGeometry: createAssemblySymmetryAxesMesh,
@@ -73,7 +73,7 @@ export function AssemblySymmetryAxesVisual(): ComplexVisual<AssemblySymmetryAxes
                 newProps.symmetryId !== currentProps.symmetryId
             )
         }
-    })
+    }, materialId)
 }
 
 function createLocationIterator(structure: Structure) {

+ 3 - 2
src/mol-repr/shape/representation.ts

@@ -5,7 +5,7 @@
  */
 
 import { Task, RuntimeContext } from 'mol-task'
-import { createRenderObject, GraphicsRenderObject } from 'mol-gl/render-object';
+import { createRenderObject, GraphicsRenderObject, getNextMaterialId } from 'mol-gl/render-object';
 import { Representation } from '../representation';
 import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
 import { ValueCell } from 'mol-util';
@@ -35,6 +35,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
     let version = 0
     const updated = new Subject<number>()
     const _state = Representation.createState()
+    const materialId = getNextMaterialId()
     const renderObjects: GraphicsRenderObject[] = []
     let _renderObject: GraphicsRenderObject | undefined
     let _shape: Shape<G>
@@ -101,7 +102,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
                 const values = geometryUtils.createValues(_shape.geometry, transform, locationIt, _theme, newProps)
                 const state = geometryUtils.createRenderableState(newProps)
 
-                _renderObject = createRenderObject(_shape.geometry.kind, values, state)
+                _renderObject = createRenderObject(_shape.geometry.kind, values, state, materialId)
                 if (_renderObject) renderObjects.push(_renderObject) // add new renderObject to list
             } else {
                 if (!_renderObject) {

+ 4 - 3
src/mol-repr/structure/complex-representation.ts

@@ -16,11 +16,12 @@ import { RepresentationContext, RepresentationParamsGetter } from 'mol-repr/repr
 import { Theme, createEmptyTheme } from 'mol-theme/theme';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Subject } from 'rxjs';
-import { GraphicsRenderObject } from 'mol-gl/render-object';
+import { GraphicsRenderObject, getNextMaterialId } from 'mol-gl/render-object';
 
-export function ComplexRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> {
+export function ComplexRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number) => ComplexVisual<P>): StructureRepresentation<P> {
     let version = 0
     const updated = new Subject<number>()
+    const materialId = getNextMaterialId()
     const renderObjects: GraphicsRenderObject[] = []
     const _state = StructureRepresentationStateBuilder.create()
     let visual: ComplexVisual<P> | undefined
@@ -39,7 +40,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
         _props = Object.assign({}, _props, props)
 
         return Task.create('Creating or updating ComplexRepresentation', async runtime => {
-            if (!visual) visual = visualCtor()
+            if (!visual) visual = visualCtor(materialId)
             const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, structure)
             if (promise) await promise
             // update list of renderObjects

+ 8 - 8
src/mol-repr/structure/complex-visual.ts

@@ -32,12 +32,12 @@ import { Overpaint } from 'mol-theme/overpaint';
 
 export interface  ComplexVisual<P extends StructureParams> extends Visual<Structure, P> { }
 
-function createComplexRenderObject<G extends Geometry>(structure: Structure, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>) {
+function createComplexRenderObject<G extends Geometry>(structure: Structure, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>, materialId: number) {
     const { createValues, createRenderableState } = Geometry.getUtils(geometry)
     const transform = createIdentityTransform()
     const values = createValues(geometry, transform, locationIt, theme, props)
     const state = createRenderableState(props)
-    return createRenderObject(geometry.kind, values, state)
+    return createRenderObject(geometry.kind, values, state, materialId)
 }
 
 const ComplexParams = {
@@ -59,7 +59,7 @@ interface ComplexVisualGeometryBuilder<P extends UnitsParams, G extends Geometry
     geometryUtils: GeometryUtils<G>
 }
 
-export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geometry.Params<G>>(builder: ComplexVisualGeometryBuilder<P, G>): ComplexVisual<P> {
+export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geometry.Params<G>>(builder: ComplexVisualGeometryBuilder<P, G>, materialId: number): ComplexVisual<P> {
     const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder
     const { updateValues, updateBoundingSphere, updateRenderableState } = builder.geometryUtils
     const updateState = VisualUpdateState.create()
@@ -117,7 +117,7 @@ export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geom
         if (updateState.createNew) {
             locationIt = createLocationIterator(newStructure)
             if (newGeometry) {
-                renderObject = createComplexRenderObject(newStructure, newGeometry, locationIt, newTheme, newProps)
+                renderObject = createComplexRenderObject(newStructure, newGeometry, locationIt, newTheme, newProps, materialId)
             } else {
                 throw new Error('expected geometry to be given')
             }
@@ -216,7 +216,7 @@ export type ComplexMeshParams = typeof ComplexMeshParams
 
 export interface ComplexMeshVisualBuilder<P extends ComplexMeshParams> extends ComplexVisualBuilder<P, Mesh> { }
 
-export function ComplexMeshVisual<P extends ComplexMeshParams>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> {
+export function ComplexMeshVisual<P extends ComplexMeshParams>(builder: ComplexMeshVisualBuilder<P>, materialId: number): ComplexVisual<P> {
     return ComplexVisual<Mesh, StructureMeshParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -224,7 +224,7 @@ export function ComplexMeshVisual<P extends ComplexMeshParams>(builder: ComplexM
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         geometryUtils: Mesh.Utils
-    })
+    }, materialId)
 }
 
 // direct-volume
@@ -237,7 +237,7 @@ export type ComplexDirectVolumeParams = typeof ComplexDirectVolumeParams
 
 export interface ComplexDirectVolumeVisualBuilder<P extends ComplexDirectVolumeParams> extends ComplexVisualBuilder<P, DirectVolume> { }
 
-export function ComplexDirectVolumeVisual<P extends ComplexDirectVolumeParams>(builder: ComplexDirectVolumeVisualBuilder<P>): ComplexVisual<P> {
+export function ComplexDirectVolumeVisual<P extends ComplexDirectVolumeParams>(builder: ComplexDirectVolumeVisualBuilder<P>, materialId: number): ComplexVisual<P> {
     return ComplexVisual<DirectVolume, StructureDirectVolumeParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -245,5 +245,5 @@ export function ComplexDirectVolumeVisual<P extends ComplexDirectVolumeParams>(b
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         geometryUtils: DirectVolume.Utils
-    })
+    }, materialId)
 }

+ 5 - 4
src/mol-repr/structure/units-representation.ts

@@ -7,7 +7,7 @@
 
 import { Structure, Unit } from 'mol-model/structure';
 import { Task } from 'mol-task'
-import { GraphicsRenderObject } from 'mol-gl/render-object';
+import { GraphicsRenderObject, getNextMaterialId } from 'mol-gl/render-object';
 import { RepresentationContext, RepresentationParamsGetter } from '../representation';
 import { Visual } from '../visual';
 import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci';
@@ -28,9 +28,10 @@ export type UnitsParams = typeof UnitsParams
 
 export interface UnitsVisual<P extends UnitsParams> extends Visual<StructureGroup, P> { }
 
-export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> {
+export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number) => UnitsVisual<P>): StructureRepresentation<P> {
     let version = 0
     const updated = new Subject<number>()
+    const materialId = getNextMaterialId()
     const renderObjects: GraphicsRenderObject[] = []
     const _state = StructureRepresentationStateBuilder.create()
     let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>()
@@ -57,7 +58,7 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R
                 _groups = structure.unitSymmetryGroups;
                 for (let i = 0; i < _groups.length; i++) {
                     const group = _groups[i];
-                    const visual = visualCtor()
+                    const visual = visualCtor(materialId)
                     const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure })
                     if (promise) await promise
                     visuals.set(group.hashCode, { visual, group })
@@ -86,7 +87,7 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R
                     } else {
                         // console.log(label, 'not found visualGroup to reuse, creating new')
                         // newGroups.push(group)
-                        const visual = visualCtor()
+                        const visual = visualCtor(materialId)
                         const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure })
                         if (promise) await promise
                         visuals.set(group.hashCode, { visual, group })

+ 14 - 14
src/mol-repr/structure/units-visual.ts

@@ -37,12 +37,12 @@ export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup }
 
 export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<StructureGroup, P> { }
 
-function createUnitsRenderObject<G extends Geometry>(group: Unit.SymmetryGroup, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>) {
+function createUnitsRenderObject<G extends Geometry>(group: Unit.SymmetryGroup, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>, materialId: number) {
     const { createValues, createRenderableState } = Geometry.getUtils(geometry)
     const transform = createUnitsTransform(group)
     const values = createValues(geometry, transform, locationIt, theme, props)
     const state = createRenderableState(props)
-    return createRenderObject(geometry.kind, values, state)
+    return createRenderObject(geometry.kind, values, state, materialId)
 }
 
 interface UnitsVisualBuilder<P extends UnitsParams, G extends Geometry> {
@@ -58,7 +58,7 @@ interface UnitsVisualGeometryBuilder<P extends UnitsParams, G extends Geometry>
     geometryUtils: GeometryUtils<G>
 }
 
-export function UnitsVisual<G extends Geometry, P extends UnitsParams & Geometry.Params<G>>(builder: UnitsVisualGeometryBuilder<P, G>): UnitsVisual<P> {
+export function UnitsVisual<G extends Geometry, P extends UnitsParams & Geometry.Params<G>>(builder: UnitsVisualGeometryBuilder<P, G>, materialId: number): UnitsVisual<P> {
     const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder
     const { createEmpty: createEmptyGeometry, updateValues, updateBoundingSphere, updateRenderableState } = builder.geometryUtils
     const updateState = VisualUpdateState.create()
@@ -140,7 +140,7 @@ export function UnitsVisual<G extends Geometry, P extends UnitsParams & Geometry
         if (updateState.createNew) {
             locationIt = createLocationIterator(newStructureGroup.group)
             if (newGeometry) {
-                renderObject = createUnitsRenderObject(newStructureGroup.group, newGeometry, locationIt, newTheme, newProps)
+                renderObject = createUnitsRenderObject(newStructureGroup.group, newGeometry, locationIt, newTheme, newProps, materialId)
             } else {
                 throw new Error('expected geometry to be given')
             }
@@ -258,7 +258,7 @@ export const UnitsMeshParams = { ...StructureMeshParams, ...UnitsParams }
 export type UnitsMeshParams = typeof UnitsMeshParams
 export interface UnitsMeshVisualBuilder<P extends UnitsMeshParams> extends UnitsVisualBuilder<P, Mesh> { }
 
-export function UnitsMeshVisual<P extends UnitsMeshParams>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> {
+export function UnitsMeshVisual<P extends UnitsMeshParams>(builder: UnitsMeshVisualBuilder<P>, materialId: number): UnitsVisual<P> {
     return UnitsVisual<Mesh, StructureMeshParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -266,7 +266,7 @@ export function UnitsMeshVisual<P extends UnitsMeshParams>(builder: UnitsMeshVis
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         geometryUtils: Mesh.Utils
-    })
+    }, materialId)
 }
 
 // spheres
@@ -275,7 +275,7 @@ export const UnitsSpheresParams = { ...StructureSpheresParams, ...UnitsParams }
 export type UnitsSpheresParams = typeof UnitsSpheresParams
 export interface UnitsSpheresVisualBuilder<P extends UnitsSpheresParams> extends UnitsVisualBuilder<P, Spheres> { }
 
-export function UnitsSpheresVisual<P extends UnitsSpheresParams>(builder: UnitsSpheresVisualBuilder<P>): UnitsVisual<P> {
+export function UnitsSpheresVisual<P extends UnitsSpheresParams>(builder: UnitsSpheresVisualBuilder<P>, materialId: number): UnitsVisual<P> {
     return UnitsVisual<Spheres, StructureSpheresParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -283,7 +283,7 @@ export function UnitsSpheresVisual<P extends UnitsSpheresParams>(builder: UnitsS
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true
         },
         geometryUtils: Spheres.Utils
-    })
+    }, materialId)
 }
 
 // points
@@ -292,7 +292,7 @@ export const UnitsPointsParams = { ...StructurePointsParams, ...UnitsParams }
 export type UnitsPointsParams = typeof UnitsPointsParams
 export interface UnitsPointVisualBuilder<P extends UnitsPointsParams> extends UnitsVisualBuilder<P, Points> { }
 
-export function UnitsPointsVisual<P extends UnitsPointsParams>(builder: UnitsPointVisualBuilder<P>): UnitsVisual<P> {
+export function UnitsPointsVisual<P extends UnitsPointsParams>(builder: UnitsPointVisualBuilder<P>, materialId: number): UnitsVisual<P> {
     return UnitsVisual<Points, StructurePointsParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -300,7 +300,7 @@ export function UnitsPointsVisual<P extends UnitsPointsParams>(builder: UnitsPoi
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true
         },
         geometryUtils: Points.Utils
-    })
+    }, materialId)
 }
 
 // lines
@@ -309,7 +309,7 @@ export const UnitsLinesParams = { ...StructureLinesParams, ...UnitsParams }
 export type UnitsLinesParams = typeof UnitsLinesParams
 export interface UnitsLinesVisualBuilder<P extends UnitsLinesParams> extends UnitsVisualBuilder<P, Lines> { }
 
-export function UnitsLinesVisual<P extends UnitsLinesParams>(builder: UnitsLinesVisualBuilder<P>): UnitsVisual<P> {
+export function UnitsLinesVisual<P extends UnitsLinesParams>(builder: UnitsLinesVisualBuilder<P>, materialId: number): UnitsVisual<P> {
     return UnitsVisual<Lines, StructureLinesParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -317,7 +317,7 @@ export function UnitsLinesVisual<P extends UnitsLinesParams>(builder: UnitsLines
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true
         },
         geometryUtils: Lines.Utils
-    })
+    }, materialId)
 }
 
 // direct-volume
@@ -326,7 +326,7 @@ export const UnitsDirectVolumeParams = { ...StructureDirectVolumeParams, ...Unit
 export type UnitsDirectVolumeParams = typeof UnitsDirectVolumeParams
 export interface UnitsDirectVolumeVisualBuilder<P extends UnitsDirectVolumeParams> extends UnitsVisualGeometryBuilder<P, DirectVolume> { }
 
-export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeParams>(builder: UnitsDirectVolumeVisualBuilder<P>): UnitsVisual<P> {
+export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeParams>(builder: UnitsDirectVolumeVisualBuilder<P>, materialId: number): UnitsVisual<P> {
     return UnitsVisual<DirectVolume, StructureDirectVolumeParams & UnitsParams>({
         ...builder,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme) => {
@@ -334,5 +334,5 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeParams>(build
             if (!SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         geometryUtils: DirectVolume.Utils
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts

@@ -55,7 +55,7 @@ export const CarbohydrateLinkParams = {
 }
 export type CarbohydrateLinkParams = typeof CarbohydrateLinkParams
 
-export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkParams> {
+export function CarbohydrateLinkVisual(materialId: number): ComplexVisual<CarbohydrateLinkParams> {
     return ComplexMeshVisual<CarbohydrateLinkParams>({
         defaultProps: PD.getDefaultValues(CarbohydrateLinkParams),
         createGeometry: createCarbohydrateLinkCylinderMesh,
@@ -68,7 +68,7 @@ export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkParams>
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }
 
 function CarbohydrateLinkIterator(structure: Structure): LocationIterator {

+ 2 - 2
src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts

@@ -148,7 +148,7 @@ export const CarbohydrateSymbolParams = {
 }
 export type CarbohydrateSymbolParams = typeof CarbohydrateSymbolParams
 
-export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolParams> {
+export function CarbohydrateSymbolVisual(materialId: number): ComplexVisual<CarbohydrateSymbolParams> {
     return ComplexMeshVisual<CarbohydrateSymbolParams>({
         defaultProps: PD.getDefaultValues(CarbohydrateSymbolParams),
         createGeometry: createCarbohydrateSymbolMesh,
@@ -161,7 +161,7 @@ export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolPara
                 newProps.detail !== currentProps.detail
             )
         }
-    })
+    }, materialId)
 }
 
 function CarbohydrateElementIterator(structure: Structure): LocationIterator {

+ 2 - 2
src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts

@@ -65,7 +65,7 @@ export const CarbohydrateTerminalLinkParams = {
 }
 export type CarbohydrateTerminalLinkParams = typeof CarbohydrateTerminalLinkParams
 
-export function CarbohydrateTerminalLinkVisual(): ComplexVisual<CarbohydrateTerminalLinkParams> {
+export function CarbohydrateTerminalLinkVisual(materialId: number): ComplexVisual<CarbohydrateTerminalLinkParams> {
     return ComplexMeshVisual<CarbohydrateTerminalLinkParams>({
         defaultProps: PD.getDefaultValues(CarbohydrateTerminalLinkParams),
         createGeometry: createCarbohydrateTerminalLinkCylinderMesh,
@@ -78,7 +78,7 @@ export function CarbohydrateTerminalLinkVisual(): ComplexVisual<CarbohydrateTerm
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }
 
 function CarbohydrateTerminalLinkIterator(structure: Structure): LocationIterator {

+ 2 - 2
src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts

@@ -58,7 +58,7 @@ export const CrossLinkRestraintParams = {
 }
 export type CrossLinkRestraintParams = typeof CrossLinkRestraintParams
 
-export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintParams> {
+export function CrossLinkRestraintVisual(materialId: number): ComplexVisual<CrossLinkRestraintParams> {
     return ComplexMeshVisual<CrossLinkRestraintParams>({
         defaultProps: PD.getDefaultValues(CrossLinkRestraintParams),
         createGeometry: createCrossLinkRestraintCylinderMesh,
@@ -71,7 +71,7 @@ export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintPara
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }
 
 function CrossLinkRestraintIterator(structure: Structure): LocationIterator {

+ 2 - 2
src/mol-repr/structure/visual/element-point.ts

@@ -42,7 +42,7 @@ export function createElementPoint(ctx: VisualContext, unit: Unit, structure: St
     return builder.getPoints()
 }
 
-export function ElementPointVisual(): UnitsVisual<ElementPointParams> {
+export function ElementPointVisual(materialId: number): UnitsVisual<ElementPointParams> {
     return UnitsPointsVisual<ElementPointParams>({
         defaultProps: PD.getDefaultValues(ElementPointParams),
         createGeometry: createElementPoint,
@@ -52,5 +52,5 @@ export function ElementPointVisual(): UnitsVisual<ElementPointParams> {
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementPointParams>, currentProps: PD.Values<ElementPointParams>) => {
 
         }
-    })
+    }, materialId)
 }

+ 4 - 4
src/mol-repr/structure/visual/element-sphere.ts

@@ -24,7 +24,7 @@ export function getElementSphereVisual(webgl?: WebGLContext) {
     return webgl && webgl.extensions.fragDepth ? ElementSphereImpostorVisual : ElementSphereMeshVisual
 }
 
-export function ElementSphereImpostorVisual(): UnitsVisual<ElementSphereParams> {
+export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<ElementSphereParams> {
     return UnitsSpheresVisual<ElementSphereParams>({
         defaultProps: PD.getDefaultValues(ElementSphereParams),
         createGeometry: createElementSphereImpostor,
@@ -34,10 +34,10 @@ export function ElementSphereImpostorVisual(): UnitsVisual<ElementSphereParams>
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => {
 
         }
-    })
+    }, materialId)
 }
 
-export function ElementSphereMeshVisual(): UnitsVisual<ElementSphereParams> {
+export function ElementSphereMeshVisual(materialId: number): UnitsVisual<ElementSphereParams> {
     return UnitsMeshVisual<ElementSphereParams>({
         defaultProps: PD.getDefaultValues(ElementSphereParams),
         createGeometry: createElementSphereMesh,
@@ -50,5 +50,5 @@ export function ElementSphereMeshVisual(): UnitsVisual<ElementSphereParams> {
                 newProps.detail !== currentProps.detail
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/gaussian-density-point.ts

@@ -55,7 +55,7 @@ export async function createGaussianDensityPoint(ctx: VisualContext, unit: Unit,
     return builder.getPoints()
 }
 
-export function GaussianDensityPointVisual(): UnitsVisual<GaussianDensityPointParams> {
+export function GaussianDensityPointVisual(materialId: number): UnitsVisual<GaussianDensityPointParams> {
     return UnitsPointsVisual<GaussianDensityPointParams>({
         defaultProps: PD.getDefaultValues(GaussianDensityPointParams),
         createGeometry: createGaussianDensityPoint,
@@ -68,5 +68,5 @@ export function GaussianDensityPointVisual(): UnitsVisual<GaussianDensityPointPa
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/gaussian-density-volume.ts

@@ -34,7 +34,7 @@ export const GaussianDensityVolumeParams = {
 }
 export type GaussianDensityVolumeParams = typeof GaussianDensityVolumeParams
 
-export function GaussianDensityVolumeVisual(): ComplexVisual<GaussianDensityVolumeParams> {
+export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<GaussianDensityVolumeParams> {
     return ComplexDirectVolumeVisual<GaussianDensityVolumeParams>({
         defaultProps: PD.getDefaultValues(GaussianDensityVolumeParams),
         createGeometry: createGaussianDensityVolume,
@@ -49,5 +49,5 @@ export function GaussianDensityVolumeVisual(): ComplexVisual<GaussianDensityVolu
                 newProps.isoValueNorm = Math.exp(-newProps.smoothness)
             }
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -40,7 +40,7 @@ export const GaussianSurfaceParams = {
 }
 export type GaussianSurfaceParams = typeof GaussianSurfaceParams
 
-export function GaussianSurfaceVisual(): UnitsVisual<GaussianSurfaceParams> {
+export function GaussianSurfaceVisual(materialId: number): UnitsVisual<GaussianSurfaceParams> {
     return UnitsMeshVisual<GaussianSurfaceParams>({
         defaultProps: PD.getDefaultValues(GaussianSurfaceParams),
         createGeometry: createGaussianSurfaceMesh,
@@ -53,5 +53,5 @@ export function GaussianSurfaceVisual(): UnitsVisual<GaussianSurfaceParams> {
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/gaussian-surface-wireframe.ts

@@ -39,7 +39,7 @@ export const GaussianWireframeParams = {
 }
 export type GaussianWireframeParams = typeof GaussianWireframeParams
 
-export function GaussianWireframeVisual(): UnitsVisual<GaussianWireframeParams> {
+export function GaussianWireframeVisual(materialId: number): UnitsVisual<GaussianWireframeParams> {
     return UnitsLinesVisual<GaussianWireframeParams>({
         defaultProps: PD.getDefaultValues(GaussianWireframeParams),
         createGeometry: createGaussianWireframe,
@@ -52,5 +52,5 @@ export function GaussianWireframeVisual(): UnitsVisual<GaussianWireframeParams>
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/inter-unit-link-cylinder.ts

@@ -58,7 +58,7 @@ export const InterUnitLinkParams = {
 }
 export type InterUnitLinkParams = typeof InterUnitLinkParams
 
-export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkParams> {
+export function InterUnitLinkVisual(materialId: number): ComplexVisual<InterUnitLinkParams> {
     return ComplexMeshVisual<InterUnitLinkParams>({
         defaultProps: PD.getDefaultValues(InterUnitLinkParams),
         createGeometry: createInterUnitLinkCylinderMesh,
@@ -74,7 +74,7 @@ export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkParams> {
                 newProps.linkSpacing !== currentProps.linkSpacing
             )
         }
-    })
+    }, materialId)
 }
 
 function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {

+ 2 - 2
src/mol-repr/structure/visual/intra-unit-link-cylinder.ts

@@ -78,7 +78,7 @@ export const IntraUnitLinkParams = {
 }
 export type IntraUnitLinkParams = typeof IntraUnitLinkParams
 
-export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkParams> {
+export function IntraUnitLinkVisual(materialId: number): UnitsVisual<IntraUnitLinkParams> {
     return UnitsMeshVisual<IntraUnitLinkParams>({
         defaultProps: PD.getDefaultValues(IntraUnitLinkParams),
         createGeometry: createIntraUnitLinkCylinderMesh,
@@ -94,7 +94,7 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkParams> {
                 newProps.linkSpacing !== currentProps.linkSpacing
             )
         }
-    })
+    }, materialId)
 }
 
 function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {

+ 2 - 2
src/mol-repr/structure/visual/nucleotide-block-mesh.ts

@@ -128,7 +128,7 @@ export const NucleotideBlockParams = {
 }
 export type NucleotideBlockParams = typeof NucleotideBlockParams
 
-export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockParams> {
+export function NucleotideBlockVisual(materialId: number): UnitsVisual<NucleotideBlockParams> {
     return UnitsMeshVisual<NucleotideBlockParams>({
         defaultProps: PD.getDefaultValues(NucleotideBlockParams),
         createGeometry: createNucleotideBlockMesh,
@@ -141,5 +141,5 @@ export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockParams> {
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/nucleotide-ring-mesh.ts

@@ -175,7 +175,7 @@ export const NucleotideRingParams = {
 }
 export type NucleotideRingParams = typeof NucleotideRingParams
 
-export function NucleotideRingVisual(): UnitsVisual<NucleotideRingParams> {
+export function NucleotideRingVisual(materialId: number): UnitsVisual<NucleotideRingParams> {
     return UnitsMeshVisual<NucleotideRingParams>({
         defaultProps: PD.getDefaultValues(NucleotideRingParams),
         createGeometry: createNucleotideRingMesh,
@@ -188,5 +188,5 @@ export function NucleotideRingVisual(): UnitsVisual<NucleotideRingParams> {
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/polymer-backbone-cylinder.ts

@@ -67,7 +67,7 @@ export const PolymerBackboneParams = {
 }
 export type PolymerBackboneParams = typeof PolymerBackboneParams
 
-export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneParams> {
+export function PolymerBackboneVisual(materialId: number): UnitsVisual<PolymerBackboneParams> {
     return UnitsMeshVisual<PolymerBackboneParams>({
         defaultProps: PD.getDefaultValues(PolymerBackboneParams),
         createGeometry: createPolymerBackboneCylinderMesh,
@@ -81,5 +81,5 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneParams> {
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/polymer-direction-wedge.ts

@@ -92,7 +92,7 @@ export const PolymerDirectionParams = {
 }
 export type PolymerDirectionParams = typeof PolymerDirectionParams
 
-export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionParams> {
+export function PolymerDirectionVisual(materialId: number): UnitsVisual<PolymerDirectionParams> {
     return UnitsMeshVisual<PolymerDirectionParams>({
         defaultProps: PD.getDefaultValues(PolymerDirectionParams),
         createGeometry: createPolymerDirectionWedgeMesh,
@@ -104,5 +104,5 @@ export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionParams> {
                 newProps.sizeFactor !== currentProps.sizeFactor
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/polymer-gap-cylinder.ts

@@ -85,7 +85,7 @@ export const PolymerGapParams = {
 }
 export type PolymerGapParams = typeof PolymerGapParams
 
-export function PolymerGapVisual(): UnitsVisual<PolymerGapParams> {
+export function PolymerGapVisual(materialId: number): UnitsVisual<PolymerGapParams> {
     return UnitsMeshVisual<PolymerGapParams>({
         defaultProps: PD.getDefaultValues(PolymerGapParams),
         createGeometry: createPolymerGapCylinderMesh,
@@ -98,5 +98,5 @@ export function PolymerGapVisual(): UnitsVisual<PolymerGapParams> {
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/polymer-trace-mesh.ts

@@ -104,7 +104,7 @@ export const PolymerTraceParams = {
 }
 export type PolymerTraceParams = typeof PolymerTraceParams
 
-export function PolymerTraceVisual(): UnitsVisual<PolymerTraceParams> {
+export function PolymerTraceVisual(materialId: number): UnitsVisual<PolymerTraceParams> {
     return UnitsMeshVisual<PolymerTraceParams>({
         defaultProps: PD.getDefaultValues(PolymerTraceParams),
         createGeometry: createPolymerTraceMesh,
@@ -120,5 +120,5 @@ export function PolymerTraceVisual(): UnitsVisual<PolymerTraceParams> {
                 newProps.arrowFactor !== currentProps.arrowFactor
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/structure/visual/polymer-tube-mesh.ts

@@ -70,7 +70,7 @@ export const PolymerTubeParams = {
 }
 export type PolymerTubeParams = typeof PolymerTubeParams
 
-export function PolymerTubeVisual(): UnitsVisual<PolymerTubeParams> {
+export function PolymerTubeVisual(materialId: number): UnitsVisual<PolymerTubeParams> {
     return UnitsMeshVisual<PolymerTubeParams>({
         defaultProps: PD.getDefaultValues(PolymerTubeParams),
         createGeometry: createPolymerTubeMesh,
@@ -84,5 +84,5 @@ export function PolymerTubeVisual(): UnitsVisual<PolymerTubeParams> {
                 newProps.radialSegments !== currentProps.radialSegments
             )
         }
-    })
+    }, materialId)
 }

+ 2 - 2
src/mol-repr/volume/direct-volume.ts

@@ -163,7 +163,7 @@ export function getDirectVolumeParams(ctx: ThemeRegistryContext, volume: VolumeD
     return PD.clone(DirectVolumeParams)
 }
 
-export function DirectVolumeVisual(): VolumeVisual<DirectVolumeParams> {
+export function DirectVolumeVisual(materialId: number): VolumeVisual<DirectVolumeParams> {
     return VolumeVisual<DirectVolume, DirectVolumeParams>({
         defaultProps: PD.getDefaultValues(DirectVolumeParams),
         createGeometry: createDirectVolume,
@@ -173,7 +173,7 @@ export function DirectVolumeVisual(): VolumeVisual<DirectVolumeParams> {
         setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<DirectVolumeParams>, currentProps: PD.Values<DirectVolumeParams>) => {
         },
         geometryUtils: DirectVolume.Utils
-    })
+    }, materialId)
 }
 
 export function DirectVolumeRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, DirectVolumeParams>): VolumeRepresentation<DirectVolumeParams> {

+ 4 - 4
src/mol-repr/volume/isosurface.ts

@@ -89,7 +89,7 @@ export const IsosurfaceMeshParams = {
 }
 export type IsosurfaceMeshParams = typeof IsosurfaceMeshParams
 
-export function IsosurfaceMeshVisual(): VolumeVisual<IsosurfaceMeshParams> {
+export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<IsosurfaceMeshParams> {
     return VolumeVisual<Mesh, IsosurfaceMeshParams>({
         defaultProps: PD.getDefaultValues(IsosurfaceMeshParams),
         createGeometry: createVolumeIsosurfaceMesh,
@@ -100,7 +100,7 @@ export function IsosurfaceMeshVisual(): VolumeVisual<IsosurfaceMeshParams> {
             if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true
         },
         geometryUtils: Mesh.Utils
-    })
+    }, materialId)
 }
 
 //
@@ -125,7 +125,7 @@ export const IsosurfaceWireframeParams = {
 }
 export type IsosurfaceWireframeParams = typeof IsosurfaceWireframeParams
 
-export function IsosurfaceWireframeVisual(): VolumeVisual<IsosurfaceWireframeParams> {
+export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<IsosurfaceWireframeParams> {
     return VolumeVisual<Lines, IsosurfaceWireframeParams>({
         defaultProps: PD.getDefaultValues(IsosurfaceWireframeParams),
         createGeometry: createVolumeIsosurfaceWireframe,
@@ -136,7 +136,7 @@ export function IsosurfaceWireframeVisual(): VolumeVisual<IsosurfaceWireframePar
             if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true
         },
         geometryUtils: Lines.Utils
-    })
+    }, materialId)
 }
 
 //

+ 8 - 7
src/mol-repr/volume/representation.ts

@@ -13,7 +13,7 @@ import { Geometry, GeometryUtils } from 'mol-geo/geometry/geometry';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
-import { GraphicsRenderObject, createRenderObject } from 'mol-gl/render-object';
+import { GraphicsRenderObject, createRenderObject, getNextMaterialId } from 'mol-gl/render-object';
 import { Interval } from 'mol-data/int';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { VisualUpdateState } from 'mol-repr/util';
@@ -30,12 +30,12 @@ import { Overpaint } from 'mol-theme/overpaint';
 
 export interface VolumeVisual<P extends VolumeParams> extends Visual<VolumeData, P> { }
 
-function createVolumeRenderObject<G extends Geometry>(volume: VolumeData, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>) {
+function createVolumeRenderObject<G extends Geometry>(volume: VolumeData, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>, materialId: number) {
     const { createValues, createRenderableState } = Geometry.getUtils(geometry)
     const transform = createIdentityTransform()
     const values = createValues(geometry, transform, locationIt, theme, props)
     const state = createRenderableState(props)
-    return createRenderObject(geometry.kind, values, state)
+    return createRenderObject(geometry.kind, values, state, materialId)
 }
 
 interface VolumeVisualBuilder<P extends VolumeParams, G extends Geometry> {
@@ -51,7 +51,7 @@ interface VolumeVisualGeometryBuilder<P extends VolumeParams, G extends Geometry
     geometryUtils: GeometryUtils<G>
 }
 
-export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geometry.Params<G>>(builder: VolumeVisualGeometryBuilder<P, G>): VolumeVisual<P> {
+export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geometry.Params<G>>(builder: VolumeVisualGeometryBuilder<P, G>, materialId: number): VolumeVisual<P> {
     const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder
     const { updateValues, updateBoundingSphere, updateRenderableState } = builder.geometryUtils
     const updateState = VisualUpdateState.create()
@@ -104,7 +104,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
         if (updateState.createNew) {
             locationIt = createLocationIterator(newVolume)
             if (newGeometry) {
-                renderObject = createVolumeRenderObject(newVolume, newGeometry, locationIt, newTheme, newProps)
+                renderObject = createVolumeRenderObject(newVolume, newGeometry, locationIt, newTheme, newProps, materialId)
             } else {
                 throw new Error('expected geometry to be given')
             }
@@ -204,9 +204,10 @@ export const VolumeParams = {
 }
 export type VolumeParams = typeof VolumeParams
 
-export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, P>, visualCtor: () => VolumeVisual<P>): VolumeRepresentation<P> {
+export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, P>, visualCtor: (materialId: number) => VolumeVisual<P>): VolumeRepresentation<P> {
     let version = 0
     const updated = new Subject<number>()
+    const materialId = getNextMaterialId()
     const renderObjects: GraphicsRenderObject[] = []
     const _state = Representation.createState()
     let visual: VolumeVisual<P> | undefined
@@ -225,7 +226,7 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx:
         _props = Object.assign({}, _props, props)
 
         return Task.create('Creating or updating VolumeRepresentation', async runtime => {
-            if (!visual) visual = visualCtor()
+            if (!visual) visual = visualCtor(materialId)
             const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, volume)
             if (promise) await promise
             // update list of renderObjects

+ 1 - 1
src/tests/browser/render-lines.ts

@@ -35,7 +35,7 @@ function linesRepr() {
 
     const values = Lines.Utils.createValuesSimple(lines, {}, Color(0xFF0000), 3)
     const state = Lines.Utils.createRenderableState({})
-    const renderObject = createRenderObject('lines', values, state)
+    const renderObject = createRenderObject('lines', values, state, -1)
     const repr = Representation.fromRenderObject('cage-lines', renderObject)
     return repr
 }

+ 2 - 2
src/tests/browser/render-mesh.ts

@@ -29,7 +29,7 @@ canvas3d.animate()
 
 function meshRepr() {
     const builderState = MeshBuilder.createState()
-    
+
     const t = Mat4.identity()
     MeshBuilder.addCage(builderState, t, HexagonalPrismCage(), 0.005, 2)
 
@@ -41,7 +41,7 @@ function meshRepr() {
 
     const values = Mesh.Utils.createValuesSimple(mesh, {}, Color(0xFF0000), 1)
     const state = Mesh.Utils.createRenderableState({})
-    const renderObject = createRenderObject('mesh', values, state)
+    const renderObject = createRenderObject('mesh', values, state, -1)
     const repr = Representation.fromRenderObject('mesh', renderObject)
     return repr
 }

+ 1 - 1
src/tests/browser/render-spheres.ts

@@ -33,7 +33,7 @@ function spheresRepr() {
 
     const values = Spheres.Utils.createValuesSimple(spheres, {}, Color(0xFF0000), 1)
     const state = Spheres.Utils.createRenderableState({})
-    const renderObject = createRenderObject('spheres', values, state)
+    const renderObject = createRenderObject('spheres', values, state, -1)
     console.log(renderObject)
     const repr = Representation.fromRenderObject('spheres', renderObject)
     return repr

+ 3 - 3
src/tests/browser/render-structure.ts

@@ -66,8 +66,8 @@ async function init() {
     const models = await getModels(cif)
     console.time('computeModelDSSP')
     const secondaryStructure = computeModelDSSP(models[0].atomicHierarchy, models[0].atomicConformation)
-    console.timeEnd('computeModelDSSP')
-    ;(models[0].properties as any).secondaryStructure = secondaryStructure
+    console.timeEnd('computeModelDSSP');
+    (models[0].properties as any).secondaryStructure = secondaryStructure
     const structure = await getStructure(models[0])
     const cartoonRepr = getCartoonRepr()
 
@@ -76,7 +76,7 @@ async function init() {
         size: reprCtx.sizeThemeRegistry.create('uniform', { structure })
     })
     await cartoonRepr.createOrUpdate({ ...CartoonRepresentationProvider.defaultValues, quality: 'auto' }, structure).run()
-    
+
     canvas3d.add(cartoonRepr)
     canvas3d.resetCamera()
 }

+ 2 - 2
src/tests/browser/render-text.ts

@@ -51,7 +51,7 @@ function textRepr() {
 
     const values = Text.Utils.createValuesSimple(text, props, Color(0xFFDD00), 1)
     const state = Text.Utils.createRenderableState(props)
-    const renderObject = createRenderObject('text', values, state)
+    const renderObject = createRenderObject('text', values, state, -1)
     console.log('text', renderObject, props)
     const repr = Representation.fromRenderObject('text', renderObject)
     return repr
@@ -66,7 +66,7 @@ function spheresRepr() {
 
     const values = Spheres.Utils.createValuesSimple(spheres, {}, Color(0xFF0000), 0.2)
     const state = Spheres.Utils.createRenderableState({})
-    const renderObject = createRenderObject('spheres', values, state)
+    const renderObject = createRenderObject('spheres', values, state, -1)
     console.log('spheres', renderObject)
     const repr = Representation.fromRenderObject('spheres', renderObject)
     return repr