Browse Source

wip, point representation, point shader fixes

Alexander Rose 6 years ago
parent
commit
a04086ff6b

+ 56 - 36
src/apps/canvas/structure-view.ts

@@ -10,7 +10,7 @@ import { BallAndStickRepresentation } from 'mol-geo/representation/structure/rep
 import { getStructureFromModel } from './util';
 import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry';
 import { ShapeRepresentation, ShapeProps } from 'mol-geo/representation/shape';
-import { getAxesShape } from './assembly-symmetry';
+import { getAxesShape, getClusterColorTheme } from './assembly-symmetry';
 import Viewer from 'mol-view/viewer';
 import { CarbohydrateRepresentation } from 'mol-geo/representation/structure/representation/carbohydrate';
 import { MeshBuilder } from 'mol-geo/mesh/mesh-builder';
@@ -19,6 +19,7 @@ import { Shape } from 'mol-model/shape';
 import { Color } from 'mol-util/color';
 import { computeUnitBoundary } from 'mol-model/structure/structure/util/boundary';
 import { addBoundingBox } from 'mol-geo/mesh/builder/bounding-box';
+import { PointRepresentation } from 'mol-geo/representation/structure/representation/point';
 
 export interface StructureView {
     readonly label: string
@@ -52,6 +53,7 @@ interface StructureViewProps {
 
 export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> {
     const cartoon = CartoonRepresentation()
+    const point = PointRepresentation()
     const ballAndStick = BallAndStickRepresentation()
     const carbohydrate = CarbohydrateRepresentation()
     const symmetryAxes = ShapeRepresentation()
@@ -154,55 +156,63 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
     async function createStructureRepr() {
         if (structure) {
             console.log('createStructureRepr')
-            await cartoon.createOrUpdate({
-                colorTheme: { name: 'chain-id' },
+            // await cartoon.createOrUpdate({
+            //     colorTheme: { name: 'unit-index' },
+            //     sizeTheme: { name: 'uniform', value: 0.2 },
+            //     useFog: false // TODO fog not working properly
+            // }, structure).run()
+
+            await point.createOrUpdate({
+                colorTheme: { name: 'unit-index' },
                 sizeTheme: { name: 'uniform', value: 0.2 },
                 useFog: false // TODO fog not working properly
             }, structure).run()
 
-            await ballAndStick.createOrUpdate({
-                colorTheme: { name: 'element-symbol' },
-                sizeTheme: { name: 'uniform', value: 0.1 },
-                useFog: false // TODO fog not working properly
-            }, structure).run()
+            // await ballAndStick.createOrUpdate({
+            //     colorTheme: { name: 'unit-index' },
+            //     sizeTheme: { name: 'uniform', value: 0.1 },
+            //     useFog: false // TODO fog not working properly
+            // }, structure).run()
 
-            await carbohydrate.createOrUpdate({
-                colorTheme: { name: 'carbohydrate-symbol' },
-                sizeTheme: { name: 'uniform', value: 1, factor: 1 },
-                useFog: false // TODO fog not working properly
-            }, structure).run()
+            // await carbohydrate.createOrUpdate({
+            //     colorTheme: { name: 'carbohydrate-symbol' },
+            //     sizeTheme: { name: 'uniform', value: 1, factor: 1 },
+            //     useFog: false // TODO fog not working properly
+            // }, structure).run()
 
             viewer.center(structure.boundary.sphere.center)
 
-            const mb = MeshBuilder.create()
-            mb.setGroup(0)
-            addSphere(mb, structure.boundary.sphere.center, structure.boundary.sphere.radius, 3)
-            addBoundingBox(mb, structure.boundary.box, 1, 2, 8)
-            for (let i = 0, il = structure.units.length; i < il; ++i) {
-                mb.setGroup(1)
-                const u = structure.units[i]
-                const ci = u.model.atomicHierarchy.chainAtomSegments.index[u.elements[0]]
-                const ek = u.model.atomicHierarchy.getEntityKey(ci)
-                if (u.model.entities.data.type.value(ek) === 'water') continue
-                const boundary = computeUnitBoundary(u)
-                addSphere(mb, boundary.sphere.center, boundary.sphere.radius, 3)
-                addBoundingBox(mb, boundary.box, 0.5, 2, 8)
-            }
-            const shape = Shape.create('boundary', mb.getMesh(), [Color(0xCC6633), Color(0x3366CC)], ['sphere boundary'])
-            await polymerSphere.createOrUpdate({
-                alpha: 0.5,
-                doubleSided: false,
-                depthMask: false,
-                useFog: false // TODO fog not working properly
-            }, shape).run()
+            // const mb = MeshBuilder.create()
+            // mb.setGroup(0)
+            // addSphere(mb, structure.boundary.sphere.center, structure.boundary.sphere.radius, 3)
+            // addBoundingBox(mb, structure.boundary.box, 1, 2, 8)
+            // for (let i = 0, il = structure.units.length; i < il; ++i) {
+            //     mb.setGroup(1)
+            //     const u = structure.units[i]
+            //     const ci = u.model.atomicHierarchy.chainAtomSegments.index[u.elements[0]]
+            //     const ek = u.model.atomicHierarchy.getEntityKey(ci)
+            //     if (u.model.entities.data.type.value(ek) === 'water') continue
+            //     const boundary = computeUnitBoundary(u)
+            //     addSphere(mb, boundary.sphere.center, boundary.sphere.radius, 3)
+            //     addBoundingBox(mb, boundary.box, 0.5, 2, 8)
+            // }
+            // const shape = Shape.create('boundary', mb.getMesh(), [Color(0xCC6633), Color(0x3366CC)], ['sphere boundary'])
+            // await polymerSphere.createOrUpdate({
+            //     alpha: 0.5,
+            //     doubleSided: false,
+            //     depthMask: false,
+            //     useFog: false // TODO fog not working properly
+            // }, shape).run()
         } else {
             cartoon.destroy()
+            point.destroy()
             ballAndStick.destroy()
             carbohydrate.destroy()
             polymerSphere.destroy()
         }
 
         viewer.add(cartoon)
+        viewer.add(point)
         viewer.add(ballAndStick)
         viewer.add(carbohydrate)
         viewer.add(polymerSphere)
@@ -214,9 +224,19 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
             if (features._rowCount) {
                 const axesShape = getAxesShape(symmetryFeatureId, assemblySymmetry)
                 if (axesShape) {
-                    // getClusterColorTheme(symmetryFeatureId, assemblySymmetry)
+                    const colorTheme = getClusterColorTheme(symmetryFeatureId, assemblySymmetry)
+                    // await cartoon.createOrUpdate({
+                    //     colorTheme: { name: 'custom', ...colorTheme },
+                    //     sizeTheme: { name: 'uniform', value: 0.2 },
+                    //     useFog: false // TODO fog not working properly
+                    // }).run()
+                    // await ballAndStick.createOrUpdate({
+                    //     colorTheme:  { name: 'custom', ...colorTheme },
+                    //     sizeTheme: { name: 'uniform', value: 0.1 },
+                    //     useFog: false // TODO fog not working properly
+                    // }).run()
                     await symmetryAxes.createOrUpdate({
-                        colorTheme: { name: 'shape-group' },
+                        colorTheme: { name: 'shape-group', ...colorTheme },
                         // colorTheme: { name: 'uniform', value: Color(0xFFCC22) },
                         useFog: false // TODO fog not working properly
                     }, axesShape).run()

+ 20 - 0
src/mol-geo/representation/structure/representation/point.ts

@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { UnitsRepresentation } from '..';
+import { ElementPointVisual, DefaultElementPointProps } from '../visual/element-point';
+import { StructureRepresentation } from '../units-representation';
+
+export const DefaultSpacefillProps = {
+    ...DefaultElementPointProps
+}
+export type PointProps = typeof DefaultElementPointProps
+
+export type PointRepresentation = StructureRepresentation<PointProps>
+
+export function PointRepresentation(): PointRepresentation {
+    return UnitsRepresentation(ElementPointVisual)
+}

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

@@ -94,7 +94,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
             createTransforms(currentGroup, renderObject.values)
             createMarkers(instanceCount * groupCount, renderObject.values)
             ValueCell.update(renderObject.values.instanceCount, instanceCount)
-            ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO
+            ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO reuse array
             updateState.updateColor = true
         }
 

+ 54 - 21
src/mol-geo/representation/structure/visual/element-point.ts

@@ -24,33 +24,33 @@ import { fillSerial } from 'mol-util/array';
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { LocationIterator } from '../../../util/location-iterator';
 
-export const DefaultPointProps = {
+export const DefaultElementPointProps = {
     ...DefaultStructureProps,
     sizeTheme: { name: 'physical' } as SizeThemeProps
 }
-export type PointProps = Partial<typeof DefaultPointProps>
+export type ElementPointProps = Partial<typeof DefaultElementPointProps>
 
-export function createPointVertices(unit: Unit) {
+// TODO make async
+export function createElementPointVertices(unit: Unit, vertices?: ValueCell<Float32Array>) {
     const elements = unit.elements
-    const elementCount = elements.length
-    const vertices = new Float32Array(elementCount * 3)
+    const n = elements.length * 3
+    const array = vertices && vertices.ref.value.length >= n ? vertices.ref.value : new Float32Array(n)
 
     const pos = unit.conformation.invariantPosition
 
     const p = Vec3.zero()
-    for (let i = 0; i < elementCount; i++) {
-        const i3 = i * 3
-        pos(elements[i], p)
-        vertices[i3] = p[0]
-        vertices[i3 + 1] = p[1]
-        vertices[i3 + 2] = p[2]
+    for (let i = 0; i < n; i += 3) {
+        pos(elements[i / 3], p)
+        array[i] = p[0]
+        array[i + 1] = p[1]
+        array[i + 2] = p[2]
     }
-    return vertices
+    return vertices ? ValueCell.update(vertices, array) : ValueCell.create(array)
 }
 
-export default function PointVisual(): UnitsVisual<PointProps> {
+export function ElementPointVisual(): UnitsVisual<ElementPointProps> {
     let renderObject: PointRenderObject | undefined
-    let currentProps = DefaultPointProps
+    let currentProps = DefaultElementPointProps
     let currentGroup: Unit.SymmetryGroup
     let locationIt: LocationIterator
 
@@ -59,11 +59,11 @@ export default function PointVisual(): UnitsVisual<PointProps> {
 
     return {
         get renderObject () { return renderObject },
-        async createOrUpdate(ctx: RuntimeContext, props: PointProps = {}, group?: Unit.SymmetryGroup) {
+        async createOrUpdate(ctx: RuntimeContext, props: ElementPointProps = {}, group?: Unit.SymmetryGroup) {
             if (!group && !currentGroup) {
                 throw new Error('missing group')
             } else if (group && !currentGroup) {
-                currentProps = Object.assign({}, DefaultPointProps, props)
+                currentProps = Object.assign({}, DefaultElementPointProps, props)
                 currentGroup = group
                 locationIt = StructureElementIterator.fromGroup(group)
 
@@ -74,14 +74,16 @@ export default function PointVisual(): UnitsVisual<PointProps> {
                 const elementCount = _elements.length
                 const instanceCount = group.units.length
 
-                const vertices = createPointVertices(_units[0])
+                const vertices = createElementPointVertices(_units[0])
                 const transform = createTransforms(group)
+                // console.time('createColors point')
                 const color = await createColors(ctx, locationIt, colorTheme)
+                // console.timeEnd('createColors point')
                 const size = createSizes(locationIt, sizeTheme)
                 const marker = createMarkers(instanceCount * elementCount)
 
                 const values: PointValues = {
-                    aPosition: ValueCell.create(vertices),
+                    aPosition: vertices,
                     aGroup: ValueCell.create(fillSerial(new Float32Array(elementCount))),
                     aInstance: ValueCell.create(fillSerial(new Float32Array(instanceCount))),
                     ...transform,
@@ -93,7 +95,7 @@ export default function PointVisual(): UnitsVisual<PointProps> {
                     uInstanceCount: ValueCell.create(instanceCount),
                     uGroupCount: ValueCell.create(group.elements.length),
 
-                    drawCount: ValueCell.create(vertices.length / 3),
+                    drawCount: ValueCell.create(group.elements.length),
                     instanceCount: ValueCell.create(instanceCount),
 
                     dPointSizeAttenuation: ValueCell.create(true),
@@ -106,13 +108,44 @@ export default function PointVisual(): UnitsVisual<PointProps> {
 
                 renderObject = createPointRenderObject(values, state)
             } else if (renderObject) {
+                if (group) currentGroup = group
+
                 const newProps = { ...currentProps, ...props }
 
-                if (!deepEqual(currentProps.colorTheme, newProps.colorTheme)) {
+                let updateTransform = false
+                let createVertices = false
+                let updateColor = false
+                let updateSize = false
+
+                if (currentGroup.units.length !== locationIt.instanceCount) updateTransform = true
+                if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) createVertices = true
+                if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateColor = true
+                if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateSize = true
+
+                if (updateTransform) {
+                    locationIt = StructureElementIterator.fromGroup(currentGroup)
+                    const { instanceCount, groupCount } = locationIt
+                    createTransforms(currentGroup, renderObject.values)
+                    createMarkers(instanceCount * groupCount, renderObject.values)
+                    ValueCell.update(renderObject.values.instanceCount, instanceCount)
+                    ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO reuse array
+                    updateColor = true
+                    updateSize = true
+                }
+
+                if (createVertices) {
+                    createElementPointVertices(currentGroup.units[0], renderObject.values.aPosition)
+                    ValueCell.update(renderObject.values.aGroup, fillSerial(new Float32Array(locationIt.groupCount))) // TODO reuse array
+                    ValueCell.update(renderObject.values.drawCount, currentGroup.elements.length)
+                    updateColor = true
+                    updateSize = true
+                }
+
+                if (updateColor) {
                     await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values)
                 }
 
-                if (!deepEqual(currentProps.sizeTheme, newProps.sizeTheme)) {
+                if (updateSize) {
                     createSizes(locationIt, newProps.sizeTheme, renderObject.values)
                 }
 

+ 1 - 0
src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts

@@ -73,6 +73,7 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> {
     return UnitsMeshVisual<PolymerBackboneProps>({
         defaultProps: DefaultPolymerBackboneProps,
         createMesh: createPolymerBackboneCylinderMesh,
+        // TODO create a specialized location iterator
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
         mark: markElement,

+ 2 - 2
src/mol-geo/representation/structure/visual/util/common.ts

@@ -62,9 +62,9 @@ type StructureMeshProps = Required<MeshProps & StructureProps>
 
 async function _createMeshValues(ctx: RuntimeContext, transforms: TransformData, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): Promise<MeshValues> {
     const { instanceCount, groupCount } = locationIt
-    console.time('createColors1')
+    console.time('createColors mesh')
     const color = await createColors(ctx, locationIt, props.colorTheme)
-    console.timeEnd('createColors1')
+    console.timeEnd('createColors mesh')
     const marker = createMarkers(instanceCount * groupCount)
 
     const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount }

+ 18 - 6
src/mol-gl/renderer.ts

@@ -92,16 +92,28 @@ namespace Renderer {
                     program.setUniforms(globalUniforms)
                     currentProgramId = program.id
                 }
-                if (r.values.dDoubleSided.ref.value) {
-                    gl.disable(gl.CULL_FACE)
+
+                if (r.values.dDoubleSided) {
+                    if (r.values.dDoubleSided.ref.value) {
+                        gl.disable(gl.CULL_FACE)
+                    } else {
+                        gl.enable(gl.CULL_FACE)
+                    }
                 } else {
-                    gl.enable(gl.CULL_FACE)
+                    // webgl default
+                    gl.disable(gl.CULL_FACE)
                 }
 
-                if (r.values.dFlipSided.ref.value) {
-                    gl.frontFace(gl.CW)
-                    gl.cullFace(gl.FRONT)
+                if (r.values.dFlipSided) {
+                    if (r.values.dFlipSided.ref.value) {
+                        gl.frontFace(gl.CW)
+                        gl.cullFace(gl.FRONT)
+                    } else {
+                        gl.frontFace(gl.CCW)
+                        gl.cullFace(gl.BACK)
+                    }
                 } else {
+                    // webgl default
                     gl.frontFace(gl.CCW)
                     gl.cullFace(gl.BACK)
                 }

+ 1 - 1
src/mol-gl/shader/chunks/assign-material-color.glsl

@@ -1,5 +1,5 @@
 #if defined(dColorType_uniform)
-    vec4 material = vec4(uColor, 1.0);
+    vec4 material = vec4(uColor, uAlpha);
 #elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
     vec4 material = vColor;
 #endif

+ 5 - 1
src/mol-gl/shader/chunks/common-frag-params.glsl

@@ -6,6 +6,10 @@ uniform vec3 uHighlightColor;
 uniform vec3 uSelectColor;
 varying float vMarker;
 
+varying vec3 vViewPosition;
+
 uniform float uFogNear;
 uniform float uFogFar;
-uniform vec3 uFogColor;
+uniform vec3 uFogColor;
+
+uniform float uAlpha;

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

@@ -7,4 +7,7 @@ uniform int uGroupCount;
 uniform vec2 uMarkerTexDim;
 uniform sampler2D tMarker;
 varying float vMarker;
+
+varying vec3 vViewPosition;
+
 #pragma glslify: readFromTexture = require(../utils/read-from-texture.glsl)

+ 1 - 3
src/mol-gl/shader/mesh.frag

@@ -18,12 +18,10 @@ precision highp int;
 uniform vec3 uLightColor;
 uniform vec3 uLightAmbient;
 uniform mat4 uView;
-uniform float uAlpha;
 
 #ifndef dFlatShaded
     varying vec3 vNormal;
 #endif
-varying vec3 vViewPosition;
 
 #pragma glslify: attenuation = require(./utils/attenuation.glsl)
 #pragma glslify: calculateSpecular = require(./utils/phong-specular.glsl)
@@ -74,7 +72,7 @@ void main() {
         // gl_FragColor.a = 1.0;
         // gl_FragColor.rgb = vec3(1.0, 0.0, 0.0);
         gl_FragColor.rgb = finalColor;
-        gl_FragColor.a = uAlpha;
+        gl_FragColor.a = material.a;
 
         #pragma glslify: import('./chunks/apply-marker-color.glsl')
         #pragma glslify: import('./chunks/apply-fog.glsl')

+ 0 - 2
src/mol-gl/shader/mesh.vert

@@ -20,8 +20,6 @@ attribute float aGroup;
     varying vec3 vNormal;
 #endif
 
-varying vec3 vViewPosition;
-
 #pragma glslify: inverse = require(./utils/inverse.glsl)
 #pragma glslify: transpose = require(./utils/transpose.glsl)
 

+ 2 - 4
src/mol-gl/shader/point.frag

@@ -10,12 +10,10 @@ precision highp int;
 #pragma glslify: import('./chunks/common-frag-params.glsl')
 #pragma glslify: import('./chunks/color-frag-params.glsl')
 
-uniform float uAlpha;
-
 void main(){
     #pragma glslify: import('./chunks/assign-material-color.glsl')
-    
-    gl_FragColor = vec4(material, uAlpha);
+
+    gl_FragColor = material;
 
     #pragma glslify: import('./chunks/apply-marker-color.glsl')
     #pragma glslify: import('./chunks/apply-fog.glsl')

+ 1 - 1
src/mol-view/theme/color/unit-index.ts

@@ -34,5 +34,5 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme {
         color = () => DefaultColor
     }
 
-    return { kind: 'groupInstance', color }
+    return { kind: 'instance', color }
 }

+ 1 - 1
src/mol-view/viewer.ts

@@ -104,7 +104,7 @@ namespace Viewer {
         // const renderer = Renderer.create(ctx, camera, { clearColor: 0xFFFFFF })
         const renderer = Renderer.create(ctx, camera, { clearColor: Color(0x000000) })
 
-        const pickScale = 1 / 4
+        const pickScale = 1
         const pickWidth = Math.round(canvas.width * pickScale)
         const pickHeight = Math.round(canvas.height * pickScale)
         const objectPickTarget = createRenderTarget(ctx, pickWidth, pickHeight)