Bladeren bron

wip, point rendering

Alexander Rose 6 jaren geleden
bovenliggende
commit
3d050a49f6

+ 68 - 46
src/apps/canvas/component/structure-representation.tsx

@@ -11,6 +11,7 @@ import { ColorThemeProps, ColorThemeName, ColorThemeNames, ColorTheme } from 'mo
 import { Color } from 'mol-util/color';
 import { Progress } from 'mol-task';
 import { VisualQuality, VisualQualityNames } from 'mol-geo/geometry/geometry';
+import { SizeThemeProps } from 'mol-view/theme/size';
 
 export interface StructureRepresentationComponentProps {
     viewer: Viewer
@@ -23,43 +24,43 @@ export interface StructureRepresentationComponentState {
     alpha: number
     quality: VisualQuality
     colorTheme: ColorThemeProps
+    sizeTheme: SizeThemeProps
+    depthMask: boolean
 
     flatShaded?: boolean
     resolutionFactor?: number
     radiusOffset?: number
     smoothness?: number
+    pointSizeAttenuation?: boolean
+    pointFilledCircle?: boolean
+    pointEdgeBleach?: number
 }
 
 export class StructureRepresentationComponent extends React.Component<StructureRepresentationComponentProps, StructureRepresentationComponentState> {
-    state = {
-        label: this.props.representation.label,
-        visible: this.props.representation.props.visible,
-        alpha: this.props.representation.props.alpha,
-        quality: this.props.representation.props.quality,
-        colorTheme: this.props.representation.props.colorTheme,
+    state = this.stateFromRepresentation(this.props.representation)
 
-        flatShaded: (this.props.representation.props as any).flatShaded,
-        resolutionFactor: (this.props.representation.props as any).resolutionFactor,
-        radiusOffset: (this.props.representation.props as any).radiusOffset,
-        smoothness: (this.props.representation.props as any).smoothness,
-    }
-
-    componentWillMount() {
-        const repr = this.props.representation
-
-        this.setState({
-            ...this.state,
+    private stateFromRepresentation(repr: StructureRepresentation<StructureProps>) {
+        return {
             label: repr.label,
             visible: repr.props.visible,
             alpha: repr.props.alpha,
             quality: repr.props.quality,
             colorTheme: repr.props.colorTheme,
+            sizeTheme: repr.props.sizeTheme,
+            depthMask: repr.props.depthMask,
 
             flatShaded: (repr.props as any).flatShaded,
             resolutionFactor: (repr.props as any).resolutionFactor,
             radiusOffset: (repr.props as any).radiusOffset,
             smoothness: (repr.props as any).smoothness,
-        })
+            pointSizeAttenuation: (repr.props as any).pointSizeAttenuation,
+            pointFilledCircle: (repr.props as any).pointFilledCircle,
+            pointEdgeBleach: (repr.props as any).pointEdgeBleach,
+        }
+    }
+
+    componentWillMount() {
+        this.setState(this.stateFromRepresentation(this.props.representation))
     }
 
     async update(state: Partial<StructureRepresentationComponentState>) {
@@ -70,11 +71,16 @@ export class StructureRepresentationComponent extends React.Component<StructureR
         if (state.quality !== undefined) props.quality = state.quality
         if (state.alpha !== undefined) props.alpha = state.alpha
         if (state.colorTheme !== undefined) props.colorTheme = state.colorTheme
+        if (state.sizeTheme !== undefined) props.sizeTheme = state.sizeTheme
+        if (state.depthMask !== undefined) props.depthMask = state.depthMask
 
         if (state.flatShaded !== undefined) (props as any).flatShaded = state.flatShaded
         if (state.resolutionFactor !== undefined) (props as any).resolutionFactor = state.resolutionFactor
         if (state.radiusOffset !== undefined) (props as any).radiusOffset = state.radiusOffset
         if (state.smoothness !== undefined) (props as any).smoothness = state.smoothness
+        if (state.pointSizeAttenuation !== undefined) (props as any).pointSizeAttenuation = state.pointSizeAttenuation
+        if (state.pointFilledCircle !== undefined) (props as any).pointFilledCircle = state.pointFilledCircle
+        if (state.pointEdgeBleach !== undefined) (props as any).pointEdgeBleach = state.pointEdgeBleach
 
         await repr.createOrUpdate(props).run(
             progress => console.log(Progress.format(progress))
@@ -83,39 +89,13 @@ export class StructureRepresentationComponent extends React.Component<StructureR
         this.props.viewer.draw(true)
         console.log(this.props.viewer.stats)
 
-        console.log(
-            'drawCount',
-            repr.renderObjects[0].values.drawCount.ref.version,
-            repr.renderObjects[0].values.drawCount.ref.value,
-            'dColorType',
-            repr.renderObjects[0].values.dColorType.ref.version,
-            repr.renderObjects[0].values.dColorType.ref.value
-        )
-
-        const newState = {
-            ...this.state,
-            visible: repr.props.visible,
-            quality: repr.props.quality,
-            alpha: repr.props.alpha,
-            colorTheme: repr.props.colorTheme,
-
-            flatShaded: (repr.props as any).flatShaded,
-            resolutionFactor: (repr.props as any).resolutionFactor,
-            radiusOffset: (repr.props as any).radiusOffset,
-            isoValue: (repr.props as any).isoValue,
-        }
-        this.setState(newState)
+        this.setState(this.stateFromRepresentation(repr))
     }
 
     render() {
-        const { label, visible, quality, alpha, colorTheme } = this.state
-
+        const { label, visible, quality, alpha, colorTheme, depthMask } = this.state
         const ct = ColorTheme(colorTheme)
 
-        if (ct.legend && ct.legend.kind === 'scale-legend') {
-            // console.log(`linear-gradient(to right, ${ct.legend.colors.map(c => Color.toStyle(c)).join(', ')})`)
-        }
-
         return <div>
             <div>
                 <h4>{label}</h4>
@@ -127,6 +107,12 @@ export class StructureRepresentationComponent extends React.Component<StructureR
                         {visible ? 'Hide' : 'Show'}
                     </button>
                 </div>
+                <div>
+                    <span>Depth Mask </span>
+                    <button onClick={(e) => this.update({ depthMask: !depthMask }) }>
+                        {depthMask ? 'Deactivate' : 'Activate'}
+                    </button>
+                </div>
                 { this.state.flatShaded !== undefined ? <div>
                     <span>Flat Shaded </span>
                     <button onClick={(e) => this.update({ flatShaded: !this.state.flatShaded }) }>
@@ -183,6 +169,42 @@ export class StructureRepresentationComponent extends React.Component<StructureR
                     >
                     </input>
                 </div> : '' }
+                { this.state.pointSizeAttenuation !== undefined ? <div>
+                    <span>Size Attenuation </span>
+                    <button onClick={(e) => this.update({ pointSizeAttenuation: !this.state.pointSizeAttenuation }) }>
+                        {this.state.pointSizeAttenuation ? 'Deactivate' : 'Activate'}
+                    </button>
+                </div> : '' }
+                { this.state.pointFilledCircle !== undefined ? <div>
+                    <span>Filled Circle </span>
+                    <button onClick={(e) => this.update({ pointFilledCircle: !this.state.pointFilledCircle }) }>
+                        {this.state.pointFilledCircle ? 'Deactivate' : 'Activate'}
+                    </button>
+                </div> : '' }
+                { this.state.pointEdgeBleach !== undefined ? <div>
+                    <span>Edge Bleach </span>
+                    <input type='range'
+                        defaultValue={this.state.pointEdgeBleach.toString()}
+                        min='0'
+                        max='1'
+                        step='0.05'
+                        onInput={(e) => this.update({ pointEdgeBleach: parseFloat(e.currentTarget.value) })}
+                    >
+                    </input>
+                </div> : '' }
+                { this.state.sizeTheme !== undefined && this.state.sizeTheme.name === 'uniform' ? <div>
+                    <span>Uniform Size </span>
+                    <input type='range'
+                        defaultValue={this.state.sizeTheme.value!.toString()}
+                        min='0'
+                        max='10'
+                        step='0.1'
+                        onInput={(e) => this.update({
+                            sizeTheme: { name: 'uniform', value: parseFloat(e.currentTarget.value) }
+                        })}
+                    >
+                    </input>
+                </div> : '' }
                 <div>
                     <span>Color Theme </span>
                     <select value={colorTheme.name} onChange={(e) => this.update({ colorTheme: { name: e.target.value as ColorThemeName } }) }>

+ 6 - 0
src/mol-geo/geometry/point/point.ts

@@ -55,6 +55,8 @@ export namespace Point {
     export const DefaultProps = {
         ...Geometry.DefaultProps,
         pointSizeAttenuation: false,
+        pointFilledCircle: false,
+        pointEdgeBleach: 0.2,
         sizeTheme: { name: 'uniform', value: 1 } as SizeThemeProps,
     }
     export type Props = typeof DefaultProps
@@ -77,11 +79,15 @@ export namespace Point {
 
             ...Geometry.createValues(props, counts),
             dPointSizeAttenuation: ValueCell.create(props.pointSizeAttenuation),
+            dPointFilledCircle: ValueCell.create(props.pointFilledCircle),
+            uPointEdgeBleach: ValueCell.create(props.pointEdgeBleach),
         }
     }
 
     export function updateValues(values: PointValues, props: Props) {
         Geometry.updateValues(values, props)
         ValueCell.updateIfChanged(values.dPointSizeAttenuation, props.pointSizeAttenuation)
+        ValueCell.updateIfChanged(values.dPointFilledCircle, props.pointFilledCircle)
+        ValueCell.updateIfChanged(values.uPointEdgeBleach, props.pointEdgeBleach)
     }
 }

+ 6 - 1
src/mol-geo/representation/structure/units-visual.ts

@@ -20,6 +20,7 @@ import { Interval } from 'mol-data/int';
 import { Point } from '../../geometry/point/point';
 import { updateRenderableState } from '../../geometry/geometry';
 import { createColors } from '../../geometry/color-data';
+import { createSizes } from '../../geometry/size-data';
 
 export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup }
 
@@ -245,7 +246,7 @@ export function UnitsPointVisual<P extends UnitsPointProps>(builder: UnitsPointV
 
         if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
 
-        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createGeometry = true
+        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.updateSize = true
         if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateState.updateColor = true
         if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
 
@@ -267,6 +268,10 @@ export function UnitsPointVisual<P extends UnitsPointProps>(builder: UnitsPointV
             updateState.updateColor = true
         }
 
+        if (updateState.updateSize) {
+            await createSizes(ctx, locationIt, newProps.sizeTheme, renderObject.values)
+        }
+
         if (updateState.updateColor) {
             await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values)
         }

+ 2 - 0
src/mol-gl/_spec/renderer.spec.ts

@@ -73,6 +73,8 @@ function createPoints() {
         instanceCount: ValueCell.create(1),
 
         dPointSizeAttenuation: ValueCell.create(true),
+        dPointFilledCircle: ValueCell.create(false),
+        uPointEdgeBleach: ValueCell.create(0.5),
         dUseFog: ValueCell.create(true),
     }
     const state: RenderableState = {

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

@@ -19,6 +19,7 @@ export interface Renderable<T extends RenderableValues & BaseValues> {
     readonly values: T
     readonly state: RenderableState
     readonly boundingSphere: Sphere3D
+    readonly opaque: boolean
 
     render: (variant: RenderVariant) => void
     getProgram: (variant: RenderVariant) => Program
@@ -37,6 +38,7 @@ export function createRenderable<T extends Values<RenderableSchema> & BaseValues
             boundingSphere = calculateBoundingSphereFromValues(values)
             return boundingSphere
         },
+        get opaque () { return values.uAlpha.ref.value === 1 },
 
         render: (variant: RenderVariant) => renderItem.render(variant),
         getProgram: (variant: RenderVariant) => renderItem.getProgram(variant),

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

@@ -27,8 +27,8 @@ export function MeshRenderable(ctx: Context, id: number, values: MeshValues, sta
     const internalValues = {
         uObjectId: ValueCell.create(id)
     }
-    const schaderCode = MeshShaderCode
-    const renderItem = createRenderItem(ctx, 'triangles', schaderCode, schema, { ...values, ...internalValues })
+    const shaderCode = MeshShaderCode
+    const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
 
     return createRenderable(renderItem, values, state)
 }

+ 11 - 3
src/mol-gl/renderable/point.ts

@@ -19,6 +19,8 @@ export const PointSchema = {
     tSize: TextureSpec('alpha', 'ubyte'),
     dSizeType: DefineSpec('string', ['uniform', 'attribute']),
     dPointSizeAttenuation: DefineSpec('boolean'),
+    dPointFilledCircle: DefineSpec('boolean'),
+    uPointEdgeBleach: UniformSpec('f'),
 }
 export type PointSchema = typeof PointSchema
 export type PointValues = Values<PointSchema>
@@ -28,8 +30,14 @@ export function PointRenderable(ctx: Context, id: number, values: PointValues, s
     const internalValues = {
         uObjectId: ValueCell.create(id)
     }
-    const schaderCode = PointShaderCode
-    const renderItem = createRenderItem(ctx, 'points', schaderCode, schema, { ...values, ...internalValues })
+    const shaderCode = PointShaderCode
+    const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues })
+    const renderable = createRenderable(renderItem, values, state);
 
-    return createRenderable(renderItem, values, state)
+    const isOpaque = Object.getOwnPropertyDescriptor(renderable, 'opaque')!.get as () => boolean
+    Object.defineProperty(renderable, 'opaque', {
+        get: () => isOpaque() && !values.dPointFilledCircle.ref.value && values.uPointEdgeBleach.ref.value === 0
+    });
+
+    return renderable
 }

+ 2 - 2
src/mol-gl/scene.ts

@@ -90,12 +90,12 @@ namespace Scene {
             },
             eachOpaque: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
                 renderableMap.forEach((r, o) => {
-                    if (o.values.uAlpha.ref.value === 1) callbackFn(r, o)
+                    if (r.opaque) callbackFn(r, o)
                 })
             },
             eachTransparent: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
                 renderableMap.forEach((r, o) => {
-                    if (o.values.uAlpha.ref.value < 1) callbackFn(r, o)
+                    if (!r.opaque) callbackFn(r, o)
                 })
             },
             get count() {

+ 21 - 3
src/mol-gl/shader/point.frag

@@ -10,11 +10,29 @@ precision highp int;
 #pragma glslify: import('./chunks/common-frag-params.glsl')
 #pragma glslify: import('./chunks/color-frag-params.glsl')
 
+#ifdef dPointFilledCircle
+    uniform float uPointEdgeBleach;
+#endif
+
+const vec2 center = vec2(0.5);
+const float radius = 0.5;
+
 void main(){
     #pragma glslify: import('./chunks/assign-material-color.glsl')
 
-    gl_FragColor = material;
+    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+        gl_FragColor = material;
+    #else
+        gl_FragColor = material;
+
+        #ifdef dPointFilledCircle
+            float dist = distance(gl_PointCoord, center);
+            float alpha = 1.0 - smoothstep(radius - uPointEdgeBleach * 2.0, radius, dist);
+            gl_FragColor.a *= alpha;
+            if (gl_FragColor.a < 0.1) discard;
+        #endif
 
-    #pragma glslify: import('./chunks/apply-marker-color.glsl')
-    #pragma glslify: import('./chunks/apply-fog.glsl')
+        #pragma glslify: import('./chunks/apply-marker-color.glsl')
+        #pragma glslify: import('./chunks/apply-fog.glsl')
+    #endif
 }