Browse Source

improved color smoothing params handling

Alexander Rose 4 years ago
parent
commit
8d4e0730e8

+ 3 - 11
src/mol-geo/geometry/mesh/color-smoothing.ts

@@ -6,6 +6,7 @@
 
 import { TextureImage } from '../../../mol-gl/renderable/util';
 import { WebGLContext } from '../../../mol-gl/webgl/context';
+import { Texture } from '../../../mol-gl/webgl/texture';
 import { Box3D, Sphere3D } from '../../../mol-math/geometry';
 import { Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
 import { getVolumeTexture2dLayout } from '../../../mol-repr/volume/util';
@@ -24,7 +25,7 @@ interface ColorSmoothingInput {
     invariantBoundingSphere: Sphere3D
 }
 
-export function calcMeshColorSmoothing(webgl: WebGLContext, input: ColorSmoothingInput, resolution: number, stride: number) {
+export function calcMeshColorSmoothing(input: ColorSmoothingInput, resolution: number, stride: number, webgl: WebGLContext, texture?: Texture) {
     const isInstanceType = input.colorType.endsWith('Instance');
     const box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere);
 
@@ -127,18 +128,9 @@ export function calcMeshColorSmoothing(webgl: WebGLContext, input: ColorSmoothin
         array[i3 + 2] = Math.round(data[i3 + 2] / c);
     }
 
-    const texture = webgl.resources.texture('image-uint8', 'rgb', 'ubyte', 'linear');
+    if (!texture) texture = webgl.resources.texture('image-uint8', 'rgb', 'ubyte', 'linear');
     texture.load(textureImage);
 
-    // ValueCell.updateIfChanged(values.dColorType, isInstanceType ? 'volumeInstance' : 'volume');
-    // ValueCell.update(values.tColorGrid, texture);
-    // ValueCell.update(values.uColorTexDim, Vec2.create(width, height));
-    // ValueCell.update(values.uColorGridDim, dim);
-    // ValueCell.update(values.uColorGridTransform, Vec4.create(min[0], min[1], min[2], scaleFactor));
-    // ValueCell.updateIfChanged(values.dColorGridType, '2d');
-
-    // return values;
-
     const transform = Vec4.create(min[0], min[1], min[2], scaleFactor);
     const type = isInstanceType ? 'volumeInstance' : 'volume';
 

+ 7 - 4
src/mol-geo/geometry/texture-mesh/color-smoothing.ts

@@ -23,6 +23,7 @@ import { TextureImage } from '../../../mol-gl/renderable/util';
 export const ColorAccumulateSchema = {
     drawCount: ValueSpec('number'),
     instanceCount: ValueSpec('number'),
+    stride: ValueSpec('number'),
 
     uTotalCount: UniformSpec('i'),
     uInstanceCount: UniformSpec('i'),
@@ -75,13 +76,14 @@ function getAccumulateRenderable(ctx: WebGLContext, input: AccumulateInput, box:
         const extent = Vec3.sub(Vec3(), box.max, box.min);
         const v = ctx.namedComputeRenderables[ColorAccumulateName].values as ColorAccumulateValues;
 
-        const sampleCount = input.vertexCount / stride;
-        if (sampleCount > v.drawCount.ref.value) {
+        const sampleCount = Math.round(input.vertexCount / stride);
+        if (sampleCount > v.drawCount.ref.value || stride !== v.stride.ref.value) {
             ValueCell.update(v.aSample, getSampleBuffer(sampleCount, stride));
         }
 
         ValueCell.updateIfChanged(v.drawCount, sampleCount);
         ValueCell.updateIfChanged(v.instanceCount, input.instanceCount);
+        ValueCell.updateIfChanged(v.stride, stride);
 
         ValueCell.updateIfChanged(v.uTotalCount, input.vertexCount);
         ValueCell.updateIfChanged(v.uInstanceCount, input.instanceCount);
@@ -114,11 +116,12 @@ function getAccumulateRenderable(ctx: WebGLContext, input: AccumulateInput, box:
 
 function createAccumulateRenderable(ctx: WebGLContext, input: AccumulateInput, box: Box3D, resolution: number, stride: number) {
     const extent = Vec3.sub(Vec3(), box.max, box.min);
-    const sampleCount = input.vertexCount / stride;
+    const sampleCount = Math.round(input.vertexCount / stride);
 
     const values: ColorAccumulateValues = {
         drawCount: ValueCell.create(sampleCount),
         instanceCount: ValueCell.create(input.instanceCount),
+        stride: ValueCell.create(stride),
 
         uTotalCount: ValueCell.create(input.vertexCount),
         uInstanceCount: ValueCell.create(input.instanceCount),
@@ -243,7 +246,7 @@ interface ColorSmoothingInput extends AccumulateInput {
     invariantBoundingSphere: Sphere3D
 }
 
-export function calcTextureMeshColorSmoothing(webgl: WebGLContext, input: ColorSmoothingInput, resolution: number, stride: number, texture?: Texture) {
+export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolution: number, stride: number, webgl: WebGLContext, texture?: Texture) {
     const { gl, resources, state, extensions: { colorBufferHalfFloat, textureHalfFloat } } = webgl;
 
     const isInstanceType = input.colorType.endsWith('Instance');

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

@@ -23,13 +23,13 @@ import { WebGLContext } from '../../../mol-gl/webgl/context';
 import { MeshValues } from '../../../mol-gl/renderable/mesh';
 import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
 import { Texture } from '../../../mol-gl/webgl/texture';
-import { applyMeshColorSmoothing, applyTextureMeshColorSmoothing } from './util/color';
+import { applyMeshColorSmoothing, applyTextureMeshColorSmoothing, ColorSmoothingParams, getColorSmoothingProps } from './util/color';
 
 const SharedParams = {
     ...GaussianDensityParams,
+    ...ColorSmoothingParams,
     ignoreHydrogens: PD.Boolean(false),
     tryUseGpu: PD.Boolean(true),
-    smoothColors: PD.Select('auto', PD.arrayToOptions(['auto', 'on', 'off'] as const)),
 };
 type SharedParams = typeof SharedParams
 
@@ -118,16 +118,26 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
-            if (newProps.smoothColors !== currentProps.smoothColors) state.updateColor = true;
+            if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
+                state.updateColor = true;
+            } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
+                if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
+                if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
+            }
         },
         mustRecreate: (structureGroup: StructureGroup, props: PD.Values<GaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
             return props.tryUseGpu && !!webgl && suitableForGpu(structureGroup.structure, props, webgl);
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
-            const { resolution } = geometry.meta as GaussianSurfaceMeta;
-            if ((props.smoothColors === 'on' || (props.smoothColors === 'auto' && theme.color.preferSmoothing)) && resolution && webgl) {
-                applyMeshColorSmoothing(webgl, values, resolution);
+            const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
+            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            if (csp) {
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
+        },
+        dispose: (geometry: Mesh) => {
+            (geometry.meta as GaussianSurfaceMeta).colorTexture?.destroy();
         }
     }, materialId);
 }
@@ -168,16 +178,26 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
-            if (newProps.smoothColors !== currentProps.smoothColors) state.updateColor = true;
+            if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
+                state.updateColor = true;
+            } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
+                if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
+                if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
+            }
         },
         mustRecreate: (structure: Structure, props: PD.Values<StructureGaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
             return props.tryUseGpu && !!webgl && suitableForGpu(structure, props, webgl);
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
-            const { resolution } = geometry.meta as GaussianSurfaceMeta;
-            if ((props.smoothColors === 'on' || (props.smoothColors === 'auto' && theme.color.preferSmoothing)) && resolution && webgl) {
-                applyMeshColorSmoothing(webgl, values, resolution);
+            const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
+            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            if (csp) {
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
+        },
+        dispose: (geometry: Mesh) => {
+            (geometry.meta as GaussianSurfaceMeta).colorTexture?.destroy();
         }
     }, materialId);
 }
@@ -231,15 +251,21 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
-            if (newProps.smoothColors !== currentProps.smoothColors) state.updateColor = true;
+            if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
+                state.updateColor = true;
+            } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
+                if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
+                if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
+            }
         },
         mustRecreate: (structureGroup: StructureGroup, props: PD.Values<GaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
             return !props.tryUseGpu || !webgl || !suitableForGpu(structureGroup.structure, props, webgl);
         },
         processValues: (values: TextureMeshValues, geometry: TextureMesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            if ((props.smoothColors === 'on' || (props.smoothColors === 'auto' && theme.color.preferSmoothing)) && resolution && webgl) {
-                applyTextureMeshColorSmoothing(webgl, values, resolution, colorTexture);
+            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            if (csp) {
+                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
                 (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
         },
@@ -300,14 +326,22 @@ export function StructureGaussianSurfaceTextureMeshVisual(materialId: number): C
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
+            if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
+                state.updateColor = true;
+            } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
+                if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
+                if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
+            }
         },
         mustRecreate: (structure: Structure, props: PD.Values<StructureGaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
             return !props.tryUseGpu || !webgl || !suitableForGpu(structure, props, webgl);
         },
         processValues: (values: TextureMeshValues, geometry: TextureMesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            if ((props.smoothColors === 'on' || (props.smoothColors === 'auto' && theme.color.preferSmoothing)) && resolution && webgl) {
-                applyTextureMeshColorSmoothing(webgl, values, resolution, colorTexture);
+            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            if (csp) {
+                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
                 (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
         },

+ 14 - 7
src/mol-repr/structure/visual/molecular-surface-mesh.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -20,13 +20,13 @@ import { Sphere3D } from '../../../mol-math/geometry';
 import { MeshValues } from '../../../mol-gl/renderable/mesh';
 import { Texture } from '../../../mol-gl/webgl/texture';
 import { WebGLContext } from '../../../mol-gl/webgl/context';
-import { applyMeshColorSmoothing } from './util/color';
+import { applyMeshColorSmoothing, ColorSmoothingParams, getColorSmoothingProps } from './util/color';
 
 export const MolecularSurfaceMeshParams = {
     ...UnitsMeshParams,
     ...MolecularSurfaceCalculationParams,
     ...CommonSurfaceParams,
-    smoothColors: PD.Select('auto', PD.arrayToOptions(['auto', 'on', 'off'] as const)),
+    ...ColorSmoothingParams,
 };
 export type MolecularSurfaceMeshParams = typeof MolecularSurfaceMeshParams
 
@@ -71,12 +71,19 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
-            if (newProps.smoothColors !== currentProps.smoothColors) state.updateColor = true;
+            if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
+                state.updateColor = true;
+            } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
+                if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
+                if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
+            }
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<MolecularSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
-            const { resolution } = geometry.meta as MolecularSurfaceMeta;
-            if ((props.smoothColors === 'on' || (props.smoothColors === 'auto' && theme.color.preferSmoothing)) && resolution && webgl) {
-                applyMeshColorSmoothing(webgl, values, resolution);
+            const { resolution, colorTexture } = geometry.meta as MolecularSurfaceMeta;
+            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            if (csp) {
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                (geometry.meta as MolecularSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
         },
         dispose: (geometry: Mesh) => {

+ 41 - 6
src/mol-repr/structure/visual/util/color.ts

@@ -10,16 +10,49 @@ import { MeshValues } from '../../../../mol-gl/renderable/mesh';
 import { TextureMeshValues } from '../../../../mol-gl/renderable/texture-mesh';
 import { WebGLContext } from '../../../../mol-gl/webgl/context';
 import { Texture } from '../../../../mol-gl/webgl/texture';
+import { Theme } from '../../../../mol-theme/theme';
 import { ValueCell } from '../../../../mol-util';
+import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
+
+export const ColorSmoothingParams = {
+    smoothColors: PD.MappedStatic('auto', {
+        auto: PD.Group({}),
+        on: PD.Group({
+            resolutionFactor: PD.Numeric(2, { min: 1, max: 6, step: 0.1 }),
+            sampleStride: PD.Numeric(6, { min: 1, max: 12, step: 1 }),
+        }),
+        off: PD.Group({})
+    }),
+};
+export type ColorSmoothingParams = typeof ColorSmoothingParams
+
+export function getColorSmoothingProps(props: PD.Values<ColorSmoothingParams>, theme: Theme, resolution?: number, webgl?: WebGLContext) {
+    if ((props.smoothColors.name === 'on' || (props.smoothColors.name === 'auto' && theme.color.preferSmoothing)) && resolution && resolution < 3 && webgl) {
+        let stride = 6;
+        if (props.smoothColors.name === 'on') {
+            resolution *= props.smoothColors.params.resolutionFactor;
+            stride = props.smoothColors.params.sampleStride;
+        } else {
+            if (resolution > 0.5 && resolution < 1) {
+                resolution *= 2 * resolution;
+            } else if (resolution > 1) {
+                stride = 3;
+            } else {
+                resolution *= 2;
+            }
+        }
+        return { resolution, stride, webgl };
+    };
+}
 
 function isSupportedColorType(x: string): x is 'group' | 'groupInstance' {
     return x === 'group' || x === 'groupInstance';
 }
 
-export function applyMeshColorSmoothing(webgl: WebGLContext, values: MeshValues, resolution: number) {
+export function applyMeshColorSmoothing(values: MeshValues, resolution: number, stride: number, webgl: WebGLContext, colorTexture?: Texture) {
     if (!isSupportedColorType(values.dColorType.ref.value)) return;
 
-    const smoothingData = calcMeshColorSmoothing(webgl, {
+    const smoothingData = calcMeshColorSmoothing({
         vertexCount: values.uVertexCount.ref.value,
         instanceCount: values.uInstanceCount.ref.value,
         groupCount: values.uGroupCount.ref.value,
@@ -31,7 +64,7 @@ export function applyMeshColorSmoothing(webgl: WebGLContext, values: MeshValues,
         colorType: values.dColorType.ref.value,
         boundingSphere: values.boundingSphere.ref.value,
         invariantBoundingSphere: values.invariantBoundingSphere.ref.value,
-    }, resolution * 2, 6);
+    }, resolution, stride, webgl, colorTexture);
 
     ValueCell.updateIfChanged(values.dColorType, smoothingData.type);
     ValueCell.update(values.tColorGrid, smoothingData.texture);
@@ -41,10 +74,12 @@ export function applyMeshColorSmoothing(webgl: WebGLContext, values: MeshValues,
     ValueCell.updateIfChanged(values.dColorGridType, '2d');
 }
 
-export function applyTextureMeshColorSmoothing(webgl: WebGLContext, values: TextureMeshValues, resolution: number, colorTexture?: Texture) {
+export function applyTextureMeshColorSmoothing(values: TextureMeshValues, resolution: number, stride: number, webgl: WebGLContext, colorTexture?: Texture) {
     if (!isSupportedColorType(values.dColorType.ref.value)) return;
 
-    const smoothingData = calcTextureMeshColorSmoothing(webgl, {
+    stride *= 3; // triple because TextureMesh is never indexed (no elements buffer)
+
+    const smoothingData = calcTextureMeshColorSmoothing({
         vertexCount: values.uVertexCount.ref.value,
         instanceCount: values.uInstanceCount.ref.value,
         groupCount: values.uGroupCount.ref.value,
@@ -56,7 +91,7 @@ export function applyTextureMeshColorSmoothing(webgl: WebGLContext, values: Text
         colorType: values.dColorType.ref.value,
         boundingSphere: values.boundingSphere.ref.value,
         invariantBoundingSphere: values.invariantBoundingSphere.ref.value,
-    }, resolution * 2, 12, colorTexture);
+    }, resolution, stride, webgl, colorTexture);
 
     ValueCell.updateIfChanged(values.dColorType, smoothingData.type);
     ValueCell.update(values.tColorGrid, smoothingData.texture);