Browse Source

wip, point & size

Alexander Rose 7 years ago
parent
commit
38882cefd4

+ 4 - 4
src/apps/render-test/state.ts

@@ -20,7 +20,7 @@ import { Run } from 'mol-task'
 import { Symmetry } from 'mol-model/structure'
 
 // import mcubes from './utils/mcubes'
-import { getStructuresFromPdbId } from './utils'
+import { getStructuresFromPdbId, log } from './utils'
 import { StructureRepresentation } from 'mol-geo/representation/structure';
 // import Cylinder from 'mol-geo/primitive/cylinder';
 
@@ -45,14 +45,14 @@ export default class State {
         this.loading.next(true)
 
         const structures = await getStructuresFromPdbId(pdbId)
-        const struct = await Run(Symmetry.buildAssembly(structures[0], '1'))
+        const struct = await Run(Symmetry.buildAssembly(structures[0], '1'), log, 100)
 
         const structPointRepr = StructureRepresentation(Point)
-        await Run(structPointRepr.create(struct))
+        await Run(structPointRepr.create(struct), log, 100)
         structPointRepr.renderObjects.forEach(viewer.add)
 
         // const structSpacefillRepr = StructureRepresentation(Spacefill)
-        // await Run(structSpacefillRepr.create(struct, { detail: 0 }))
+        // await Run(structSpacefillRepr.create(struct, { detail: 2 }), log, 100)
         // structSpacefillRepr.renderObjects.forEach(viewer.add)
 
         viewer.requestDraw()

+ 4 - 4
src/mol-geo/color/data.ts

@@ -5,15 +5,15 @@
  */
 
 import { ValueCell } from 'mol-util';
-import { ColorTexture, createColorTexture } from 'mol-gl/renderable/util';
+import { Texture, createColorTexture } from 'mol-gl/renderable/util';
 import Color from './color';
 import { Mesh } from '../shape/mesh';
 
 export type UniformColor = { type: 'uniform', value: number[] }
 export type AttributeColor = { type: 'attribute', value: ValueCell<Float32Array> }
-export type InstanceColor = { type: 'instance', value: ValueCell<ColorTexture> }
-export type ElementColor = { type: 'element', value: ValueCell<ColorTexture> }
-export type ElementInstanceColor = { type: 'element-instance', value: ValueCell<ColorTexture> }
+export type InstanceColor = { type: 'instance', value: ValueCell<Texture> }
+export type ElementColor = { type: 'element', value: ValueCell<Texture> }
+export type ElementInstanceColor = { type: 'element-instance', value: ValueCell<Texture> }
 export type ColorData = UniformColor | AttributeColor | InstanceColor | ElementColor | ElementInstanceColor
 
 export interface UniformColorProps {

+ 11 - 1
src/mol-geo/representation/structure/index.ts

@@ -9,6 +9,7 @@ import { EquivalenceClasses } from 'mol-data/util';
 import { OrderedSet } from 'mol-data/int'
 import { Task } from 'mol-task'
 import { RenderObject } from 'mol-gl/scene';
+// import { Mat4, EPSILON } from 'mol-math/linear-algebra';
 
 export interface RepresentationProps {
 
@@ -40,13 +41,22 @@ export function StructureRepresentation<Props>(reprCtor: () => UnitsRepresentati
                     (a, b) => a.unit.model.id === b.unit.model.id && OrderedSet.areEqual(a.group.elements, b.group.elements)
                 );
 
+                // const uniqueTransformations = EquivalenceClasses<number, { unit: Unit, group: ElementGroup }>(
+                //     ({ unit, group }) => unit.operator.matrix.join(','),
+                //     (a, b) => Mat4.areEqual(a.unit.operator.matrix, b.unit.operator.matrix, EPSILON.Value)
+                // );
+
                 const unitIndices = ElementSet.unitIndices(elements);
                 for (let i = 0, _i = unitIndices.length; i < _i; i++) {
                     const unitIndex = unitIndices[i];
                     const group = ElementSet.groupFromUnitIndex(elements, unitIndex);
-                    uniqueGroups.add(unitIndex, { unit: units[unitIndex], group });
+                    const unit = units[unitIndex]
+                    uniqueGroups.add(unitIndex, { unit, group });
+                    // uniqueTransformations.add(unitIndex, { unit, group });
                 }
 
+                // console.log({ uniqueGroups, uniqueTransformations })
+
                 for (let i = 0, _i = uniqueGroups.groups.length; i < _i; i++) {
                     const groupUnits: Unit[] = []
                     const group = uniqueGroups.groups[i]

+ 18 - 2
src/mol-geo/representation/structure/point.ts

@@ -17,6 +17,8 @@ import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
 import { createUniformColor, createInstanceColor } from '../../color/data';
 import { fillSerial } from 'mol-gl/renderable/util';
 import { ColorScale } from '../../color/scale';
+import { createUniformSize } from '../../size/data';
+import { vdwSizeData } from '../../size/structure/vdw';
 
 export const DefaultPointProps = {
 
@@ -59,18 +61,32 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 unitCount
             })
 
+            // const size = createUniformSize({ value: 1 })
+            const size = vdwSizeData({
+                units,
+                elementGroup,
+                offsetData: {
+                    primitiveCount: elementCount,
+                    offsetCount: elementCount + 1,
+                    offsets: fillSerial(new Uint32Array(elementCount + 1))
+                }
+            })
+            console.log(size)
+
             const points = createPointRenderObject({
                 objectId: 0,
 
                 position: ValueCell.create(ChunkedArray.compact(vertices, true) as Float32Array),
                 id: ValueCell.create(fillSerial(new Float32Array(unitCount))),
-                size: ValueCell.create(ChunkedArray.compact(sizes, true) as Float32Array),
+                size,
                 color,
                 transform: ValueCell.create(transformArray),
 
                 instanceCount: unitCount,
                 elementCount,
-                positionCount: vertices.elementCount
+                positionCount: vertices.elementCount,
+
+                usePointSizeAttenuation: true
             })
             renderObjects.push(points)
         }),

+ 48 - 0
src/mol-geo/size/data.ts

@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ValueCell } from 'mol-util';
+
+export type UniformSize = { type: 'uniform', value: number }
+export type AttributeSize = { type: 'attribute', value: ValueCell<Float32Array> }
+export type SizeData = UniformSize | AttributeSize
+
+export interface OffsetData {
+    primitiveCount: number,
+    offsetCount: number,
+    offsets: Uint32Array
+}
+
+export interface UniformSizeProps {
+    value: number
+}
+
+/** Creates size uniform */
+export function createUniformSize(props: UniformSizeProps): UniformSize {
+    return { type: 'uniform', value: props.value }
+}
+
+export interface AttributeSizeProps {
+    sizeFn: (elementIdx: number) => number
+    offsetData: OffsetData
+}
+
+/** Creates size attribute with size for each element (i.e. shared across indtances/units) */
+export function createAttributeSize(props: AttributeSizeProps): AttributeSize {
+    const { sizeFn, offsetData } = props
+    const { primitiveCount, offsetCount, offsets } = offsetData
+    const sizes = new Float32Array(primitiveCount);
+    const _offsets = offsets // .ref.value
+    for (let i = 0, il = offsetCount - 1; i < il; ++i) {
+        const start = _offsets[i]
+        const end = _offsets[i + 1]
+        const size = sizeFn(i)
+        for (let i = start, il = end; i < il; ++i) {
+            sizes[i] = size
+        }
+    }
+    return { type: 'attribute', value: ValueCell.create(sizes) }
+}

+ 9 - 0
src/mol-geo/size/index.ts

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { SizeData } from './data'
+
+export { SizeData }

+ 14 - 0
src/mol-geo/size/structure/index.ts

@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ElementGroup, Unit } from 'mol-model/structure';
+import { OffsetData } from '../data';
+
+export interface StructureSizeDataProps {
+    units: ReadonlyArray<Unit>,
+    elementGroup: ElementGroup,
+    offsetData: OffsetData
+}

+ 22 - 0
src/mol-geo/size/structure/vdw.ts

@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { OrderedSet } from 'mol-data/int';
+import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
+import { StructureSizeDataProps } from '.';
+import { createAttributeSize } from '../data';
+
+export function vdwSizeData(props: StructureSizeDataProps) {
+    const { units, elementGroup, offsetData } = props
+    const { type_symbol } = units[0].model.hierarchy.atoms
+    return createAttributeSize({
+        sizeFn: (elementIdx: number) => {
+            const e = OrderedSet.getAt(elementGroup.elements, elementIdx)
+            return VdwRadius(type_symbol.value(e))
+        },
+        offsetData
+    })
+}

+ 7 - 2
src/mol-gl/renderable/point.ts

@@ -11,6 +11,7 @@ import { Renderable } from '../renderable'
 import { createBaseDefines, createBaseUniforms, createBaseAttributes, destroyUniforms, destroyAttributes } from './util'
 import { PointShaders, addDefines } from '../shaders'
 import { ColorData } from 'mol-geo/color';
+import { SizeData } from 'mol-geo/size';
 
 type Point = 'point'
 
@@ -19,15 +20,17 @@ namespace Point {
         objectId: number
 
         position: ValueCell<Float32Array>
-        size?: ValueCell<Float32Array>
         id: ValueCell<Float32Array>
 
+        size: SizeData
         color: ColorData
         transform: ValueCell<Float32Array>
 
         instanceCount: number
         elementCount: number
-        positionCount: number
+        positionCount: number,
+
+        usePointSizeAttenuation?: boolean
     }
 
     export function create(regl: REGL.Regl, props: Data): Renderable {
@@ -35,6 +38,8 @@ namespace Point {
         const uniforms = createBaseUniforms(regl, props)
         const attributes = createBaseAttributes(regl, props)
 
+        if (props.usePointSizeAttenuation) defines.POINT_SIZE_ATTENUATION = ''
+
         const command = regl({
             ...addDefines(defines, PointShaders),
             uniforms,

+ 29 - 12
src/mol-gl/renderable/util.ts

@@ -11,6 +11,7 @@ import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
 import Attribute from '../attribute'
 import { ColorData } from 'mol-geo/color';
 import { ShaderDefines } from '../shaders';
+import { SizeData } from 'mol-geo/size';
 
 export type ReglUniforms = { [k: string]: REGL.Uniform | REGL.Texture }
 export type ReglAttributes = { [k: string]: REGL.AttributeConfig }
@@ -23,12 +24,12 @@ export function calculateTextureInfo (n: number, itemSize: number) {
     return { width, height, length: width * height * itemSize }
 }
 
-export interface ColorTexture extends Uint8Array {
+export interface Texture extends Uint8Array {
     width: number,
     height: number
 }
 
-export function createColorTexture (n: number): ColorTexture {
+export function createColorTexture (n: number): Texture {
     const colorTexInfo = calculateTextureInfo(n, 3)
     const colorTexture = new Uint8Array(colorTexInfo.length)
     return Object.assign(colorTexture, {
@@ -50,7 +51,7 @@ export function createTransformAttributes (regl: REGL.Regl, transform: ValueCell
     }
 }
 
-export function createColorUniforms (regl: REGL.Regl, color: ValueCell<ColorTexture>) {
+export function createColorUniforms (regl: REGL.Regl, color: ValueCell<Texture>) {
     const colorTex = regl.texture({
         width: color.ref.value.width,
         height: color.ref.value.height,
@@ -78,6 +79,15 @@ export function getColorDefines(color: ColorData) {
     return defines
 }
 
+export function getSizeDefines(size: SizeData) {
+    const defines: ShaderDefines = {}
+    switch (size.type) {
+        case 'uniform': defines.UNIFORM_SIZE = ''; break;
+        case 'attribute': defines.ATTRIBUTE_SIZE = ''; break;
+    }
+    return defines
+}
+
 export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
     const buffers: AttributesBuffers<any> = {}
     for (const k of Object.keys(attributes)) {
@@ -100,20 +110,24 @@ interface BaseProps {
 
     position: ValueCell<Float32Array>
     normal?: ValueCell<Float32Array>
-    size?: ValueCell<Float32Array>
     id: ValueCell<Float32Array>
     transform: ValueCell<Float32Array>
+
+    size?: SizeData
     color: ColorData
 }
 
 export function createBaseUniforms(regl: REGL.Regl, props: BaseProps): ReglUniforms {
-    const { objectId, instanceCount, elementCount, color } = props
+    const { objectId, instanceCount, elementCount, color, size } = props
     const uniforms = { objectId, instanceCount, elementCount }
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
         Object.assign(uniforms, createColorUniforms(regl, color.value))
     } else if (color.type === 'uniform') {
         Object.assign(uniforms, { color: color.value })
     }
+    if (size && size.type === 'uniform') {
+        Object.assign(uniforms, { size: size.value })
+    }
     return uniforms
 }
 
@@ -126,20 +140,23 @@ export function createBaseAttributes(regl: REGL.Regl, props: BaseProps): ReglAtt
         elementId: Attribute.create(regl, id, positionCount, { size: 1 }),
         ...createTransformAttributes(regl, transform, instanceCount)
     })
-    if (color.type === 'attribute') {
-        attributes.color = Attribute.create(regl, color.value, positionCount, { size: 3 }).buffer
-    }
     if (normal) {
         attributes.normal = Attribute.create(regl, normal as any, positionCount, { size: 3 }).buffer
     }
-    if (size) {
-        attributes.size = Attribute.create(regl, size, positionCount, { size: 1 }).buffer
+    if (color.type === 'attribute') {
+        attributes.color = Attribute.create(regl, color.value, positionCount, { size: 3 }).buffer
+    }
+    if (size && size.type === 'attribute') {
+        attributes.size = Attribute.create(regl, size.value, positionCount, { size: 1 }).buffer
     }
     return attributes
 }
 
-export function createBaseDefines(regl: REGL.Regl, props: BaseProps) {
-    return getColorDefines(props.color)
+export function createBaseDefines(regl: REGL.Regl, props: BaseProps): ShaderDefines {
+    return {
+        ...getColorDefines(props.color),
+        ...(props.size ? getSizeDefines(props.size) : undefined)
+    }
 }
 
 export function destroyAttributes(attributes: ReglAttributes) {

+ 8 - 0
src/mol-gl/renderer.ts

@@ -39,6 +39,10 @@ const optionalExtensions = [
     'EXT_disjoint_timer_query'
 ]
 
+function getPixelRatio() {
+    return (typeof window !== 'undefined') ? window.devicePixelRatio : 1
+}
+
 namespace Renderer {
     export function create(canvas: HTMLCanvasElement, camera: Camera): Renderer {
         const regl = glContext.create({ canvas, extensions, optionalExtensions, profile: false })
@@ -52,10 +56,14 @@ namespace Renderer {
                 projection: camera.projection,
             },
             uniforms: {
+                pixelRatio: getPixelRatio(),
+                viewportHeight: regl.context('viewportHeight'),
+
                 model: regl.context('model' as any),
                 transform: regl.context('transform' as any),
                 view: regl.context('view' as any),
                 projection: regl.context('projection' as any),
+
                 'light.position': Vec3.create(0, 0, -100),
                 'light.color': Vec3.create(1.0, 1.0, 1.0),
                 'light.ambient': Vec3.create(0.5, 0.5, 0.5),

+ 1 - 1
src/mol-gl/shader/chunks/color-vert-params.glsl

@@ -9,4 +9,4 @@
     uniform sampler2D colorTex;
 #endif
 
-#pragma glslify: read_vec3 = require(../utils/read-vec3.glsl)
+#pragma glslify: read_vec3 = require(../utils/read-from-texture.glsl)

+ 17 - 2
src/mol-gl/shader/point.vert

@@ -12,8 +12,17 @@ uniform int objectId;
 uniform int instanceCount;
 uniform int elementCount;
 
+uniform float pixelRatio;
+uniform float viewportHeight;
+
 #pragma glslify: import('./chunks/color-vert-params.glsl')
 
+#if defined(UNIFORM_SIZE)
+    uniform float size;
+#elif defined(ATTRIBUTE_SIZE)
+    attribute float size;
+#endif
+
 attribute vec3 position;
 attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
 attribute float instanceId;
@@ -24,7 +33,13 @@ void main(){
 
     mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
     mat4 modelView = view * model * transform;
+    vec4 mvPosition = modelView * vec4(position, 1.0);
+
+    #ifdef POINT_SIZE_ATTENUATION
+        gl_PointSize = size * pixelRatio * ((viewportHeight / 2.0) / -mvPosition.z) * 5.0;
+    #else
+        gl_PointSize = size * pixelRatio;
+    #endif
 
-    gl_PointSize = 1.0;
-    gl_Position = projection * modelView * vec4(position, 1.0);
+    gl_Position = projection * mvPosition;
 }

+ 0 - 0
src/mol-gl/shader/utils/read-vec3.glsl → src/mol-gl/shader/utils/read-from-texture.glsl


+ 3 - 1
src/mol-gl/shaders.ts

@@ -21,7 +21,9 @@ export const MeshShaders = {
 }
 
 type ShaderDefine = (
-    'UNIFORM_COLOR' | 'ATTRIBUTE_COLOR' | 'INSTANCE_COLOR' | 'ELEMENT_COLOR' | 'ELEMENT_INSTANCE_COLOR'
+    'UNIFORM_COLOR' | 'ATTRIBUTE_COLOR' | 'INSTANCE_COLOR' | 'ELEMENT_COLOR' | 'ELEMENT_INSTANCE_COLOR' |
+    'UNIFORM_SIZE' | 'ATTRIBUTE_SIZE' |
+    'POINT_SIZE_ATTENUATION'
 )
 export type ShaderDefines = {
     [k in ShaderDefine]?: number|string

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

@@ -86,7 +86,7 @@ namespace Viewer {
 
             get stats() {
                 return renderer.stats
-            }
+            },
             dispose: () => {
                 input.dispose()
                 controls.dispose()