Browse Source

wip, isosurface renderable

Alexander Rose 6 years ago
parent
commit
db6405541c

+ 7 - 0
src/mol-geo/geometry/geometry.ts

@@ -21,6 +21,7 @@ import { TransformData } from './transform-data';
 import { Theme } from 'mol-theme/theme';
 import { RenderObjectValuesType } from 'mol-gl/render-object';
 import { ValueOf } from 'mol-util/type-helpers';
+import { Isosurface } from './isosurface/isosurface';
 
 export type GeometryKindType = {
     'mesh': Mesh,
@@ -29,6 +30,7 @@ export type GeometryKindType = {
     'text': Text,
     'lines': Lines,
     'direct-volume': DirectVolume,
+    'isosurface': Isosurface,
 }
 export type GeometryKindParams = {
     'mesh': Mesh.Params,
@@ -37,6 +39,7 @@ export type GeometryKindParams = {
     'text': Text.Params,
     'lines': Lines.Params,
     'direct-volume': DirectVolume.Params,
+    'isosurface': Isosurface.Params,
 }
 export type GeometryKind = keyof GeometryKindType
 export type Geometry = ValueOf<GeometryKindType>
@@ -63,6 +66,7 @@ export namespace Geometry {
             case 'text': return geometry.charCount * 2 * 3
             case 'lines': return geometry.lineCount * 2 * 3
             case 'direct-volume': return 12 * 3
+            case 'isosurface': return geometry.vertexCount.ref.value * 3
         }
     }
 
@@ -76,6 +80,8 @@ export namespace Geometry {
                 return getDrawCount(geometry) === 0 ? 0 : (arrayMax(geometry.groupBuffer.ref.value) + 1)
             case 'direct-volume':
                 return 1
+            case 'isosurface':
+                return geometry.groupCount.ref.value
         }
     }
 
@@ -88,6 +94,7 @@ export namespace Geometry {
             case 'text': return Text.Utils as any
             case 'lines': return Lines.Utils as any
             case 'direct-volume': return DirectVolume.Utils as any
+            case 'isosurface': return Isosurface.Utils as any
         }
         throw new Error('unknown geometry kind')
     }

+ 159 - 0
src/mol-geo/geometry/isosurface/isosurface.ts

@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ValueCell } from 'mol-util'
+import { Sphere3D } from 'mol-math/geometry'
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { LocationIterator } from 'mol-geo/util/location-iterator';
+import { TransformData } from '../transform-data';
+import { createColors } from '../color-data';
+import { createMarkers } from '../marker-data';
+import { GeometryUtils } from '../geometry';
+import { Theme } from 'mol-theme/theme';
+import { Color } from 'mol-util/color';
+import { BaseGeometry } from '../base';
+import { createEmptyOverpaint } from '../overpaint-data';
+import { createEmptyTransparency } from '../transparency-data';
+import { IsosurfaceValues } from 'mol-gl/renderable/isosurface';
+import { calculateTransformBoundingSphere } from 'mol-gl/renderable/util';
+import { Texture } from 'mol-gl/webgl/texture';
+import { Vec2 } from 'mol-math/linear-algebra';
+import { fillSerial } from 'mol-util/array';
+
+export interface Isosurface {
+    readonly kind: 'isosurface',
+
+    /** Number of vertices in the isosurface */
+    readonly vertexCount: ValueCell<number>,
+    /** Number of groups in the isosurface */
+    readonly groupCount: ValueCell<number>,
+
+    readonly vertexTexture: ValueCell<Texture>,
+    readonly vertexTextureDim: ValueCell<Vec2>,
+
+    /** Normal buffer as array of xyz values for each vertex wrapped in a value cell */
+    readonly normalBuffer: ValueCell<Float32Array>,
+    /** Group buffer as array of group ids for each vertex wrapped in a value cell */
+    readonly groupBuffer: ValueCell<Float32Array>,
+
+    readonly boundingSphere: ValueCell<Sphere3D>,
+}
+
+export namespace Isosurface {
+    export function create(vertexCount: number, groupCount: number, vertexTexture: Texture, normalBuffer: Float32Array, groupBuffer: Float32Array, boundingSphere: Sphere3D, isosurface?: Isosurface): Isosurface {
+        const { width, height } = vertexTexture
+        if (isosurface) {
+            ValueCell.update(isosurface.vertexCount, vertexCount)
+            ValueCell.update(isosurface.groupCount, groupCount)
+            ValueCell.update(isosurface.vertexTexture, vertexTexture)
+            ValueCell.update(isosurface.vertexTextureDim, Vec2.set(isosurface.vertexTextureDim.ref.value, width, height))
+            ValueCell.update(isosurface.normalBuffer, normalBuffer)
+            ValueCell.update(isosurface.groupBuffer, groupBuffer)
+            ValueCell.update(isosurface.boundingSphere, boundingSphere)
+            return isosurface
+        } else {
+            return {
+                kind: 'isosurface',
+                vertexCount: ValueCell.create(vertexCount),
+                groupCount: ValueCell.create(groupCount),
+                vertexTexture: ValueCell.create(vertexTexture),
+                vertexTextureDim: ValueCell.create(Vec2.create(width, height)),
+                normalBuffer: ValueCell.create(normalBuffer),
+                groupBuffer: ValueCell.create(groupBuffer),
+                boundingSphere: ValueCell.create(boundingSphere),
+            }
+        }
+    }
+
+    export function createEmpty(isosurface?: Isosurface): Isosurface {
+        return {} as Isosurface // TODO
+    }
+
+    export const Params = {
+        ...BaseGeometry.Params,
+        doubleSided: PD.Boolean(false),
+        flipSided: PD.Boolean(false),
+        flatShaded: PD.Boolean(false),
+    }
+    export type Params = typeof Params
+
+    export const Utils: GeometryUtils<Isosurface, Params> = {
+        Params,
+        createEmpty,
+        createValues,
+        createValuesSimple,
+        updateValues,
+        updateBoundingSphere,
+        createRenderableState: BaseGeometry.createRenderableState,
+        updateRenderableState: BaseGeometry.updateRenderableState
+    }
+
+    function createValues(isosurface: Isosurface, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): IsosurfaceValues {
+        const { instanceCount, groupCount } = locationIt
+        const color = createColors(locationIt, theme.color)
+        const marker = createMarkers(instanceCount * groupCount)
+        const overpaint = createEmptyOverpaint()
+        const transparency = createEmptyTransparency()
+
+        const counts = { drawCount: isosurface.vertexCount.ref.value, groupCount, instanceCount }
+
+        const transformBoundingSphere = calculateTransformBoundingSphere(isosurface.boundingSphere.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value)
+
+        return {
+            tPosition: isosurface.vertexTexture,
+            uPositionTexDim: isosurface.vertexTextureDim,
+            aIndex: ValueCell.create(fillSerial(new Float32Array(isosurface.vertexCount.ref.value))),
+            aNormal: isosurface.normalBuffer,
+            aGroup: isosurface.groupBuffer,
+            boundingSphere: ValueCell.create(transformBoundingSphere),
+            invariantBoundingSphere: isosurface.boundingSphere,
+
+            ...color,
+            ...marker,
+            ...overpaint,
+            ...transparency,
+            ...transform,
+
+            ...BaseGeometry.createValues(props, counts),
+            dDoubleSided: ValueCell.create(props.doubleSided),
+            dFlatShaded: ValueCell.create(props.flatShaded),
+            dFlipSided: ValueCell.create(props.flipSided),
+            dPositionTexture: ValueCell.create(true),
+        }
+    }
+
+    function createValuesSimple(isosurface: Isosurface, props: Partial<PD.Values<Params>>, colorValue: Color, sizeValue: number, transform?: TransformData) {
+        const s = BaseGeometry.createSimple(colorValue, sizeValue, transform)
+        const p = { ...PD.getDefaultValues(Params), ...props }
+        return createValues(isosurface, s.transform, s.locationIterator, s.theme, p)
+    }
+
+    function updateValues(values: IsosurfaceValues, props: PD.Values<Params>) {
+        if (Color.fromNormalizedArray(values.uHighlightColor.ref.value, 0) !== props.highlightColor) {
+            ValueCell.update(values.uHighlightColor, Color.toArrayNormalized(props.highlightColor, values.uHighlightColor.ref.value, 0))
+        }
+        if (Color.fromNormalizedArray(values.uSelectColor.ref.value, 0) !== props.selectColor) {
+            ValueCell.update(values.uSelectColor, Color.toArrayNormalized(props.selectColor, values.uSelectColor.ref.value, 0))
+        }
+        ValueCell.updateIfChanged(values.alpha, props.alpha) // `uAlpha` is set in renderable.render
+        ValueCell.updateIfChanged(values.dUseFog, props.useFog)
+
+        ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
+        ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded)
+        ValueCell.updateIfChanged(values.dFlipSided, props.flipSided)
+    }
+
+    function updateBoundingSphere(values: IsosurfaceValues, isosurface: Isosurface) {
+        const invariantBoundingSphere = isosurface.boundingSphere.ref.value
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
+        if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
+            ValueCell.update(values.boundingSphere, boundingSphere)
+        }
+        if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
+            ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
+        }
+    }
+}

+ 6 - 1
src/mol-gl/render-object.ts

@@ -14,6 +14,7 @@ import { PointsValues, PointsRenderable } from './renderable/points';
 import { LinesValues, LinesRenderable } from './renderable/lines';
 import { SpheresValues, SpheresRenderable } from './renderable/spheres';
 import { TextValues, TextRenderable } from './renderable/text';
+import { IsosurfaceValues, IsosurfaceRenderable } from './renderable/isosurface';
 
 const getNextId = idFactory(0, 0x7FFFFFFF)
 
@@ -26,10 +27,11 @@ export interface SpheresRenderObject extends BaseRenderObject { type: 'spheres',
 export interface TextRenderObject extends BaseRenderObject { type: 'text', values: TextValues }
 export interface LinesRenderObject extends BaseRenderObject { type: 'lines', values: LinesValues }
 export interface DirectVolumeRenderObject extends BaseRenderObject { type: 'direct-volume', values: DirectVolumeValues }
+export interface IsosurfaceRenderObject extends BaseRenderObject { type: 'isosurface', values: IsosurfaceValues }
 
 //
 
-export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | TextRenderObject | LinesRenderObject | DirectVolumeRenderObject
+export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | TextRenderObject | LinesRenderObject | DirectVolumeRenderObject | IsosurfaceRenderObject
 
 export type RenderObjectKindType = {
     'mesh': MeshRenderObject
@@ -38,6 +40,7 @@ export type RenderObjectKindType = {
     'text': TextRenderObject
     'lines': LinesRenderObject
     'direct-volume': DirectVolumeRenderObject
+    'isosurface': IsosurfaceRenderObject
 }
 export type RenderObjectValuesType = {
     'mesh': MeshValues
@@ -46,6 +49,7 @@ export type RenderObjectValuesType = {
     'text': TextValues
     'lines': LinesValues
     'direct-volume': DirectVolumeValues
+    'isosurface': IsosurfaceValues
 }
 export type RenderObjectType = keyof RenderObjectKindType
 
@@ -63,5 +67,6 @@ export function createRenderable(ctx: WebGLContext, o: GraphicsRenderObject): Re
         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 'isosurface': return IsosurfaceRenderable(ctx, o.id, o.values, o.state, o.materialId)
     }
 }

+ 41 - 0
src/mol-gl/renderable/isosurface.ts

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Renderable, RenderableState, createRenderable } from '../renderable'
+import { WebGLContext } from '../webgl/context';
+import { createGraphicsRenderItem } from '../webgl/render-item';
+import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, InternalValues, UniformSpec, TextureSpec } from './schema';
+import { MeshShaderCode } from '../shader-code';
+import { ValueCell } from 'mol-util';
+
+export const IsosurfaceSchema = {
+    ...BaseSchema,
+
+    aIndex: AttributeSpec('float32', 1, 0),
+    aNormal: AttributeSpec('float32', 3, 0),
+
+    uPositionTexDim: UniformSpec('v2'),
+    tPosition: TextureSpec('texture', 'rgba', 'float', 'nearest'),
+
+    dFlatShaded: DefineSpec('boolean'),
+    dDoubleSided: DefineSpec('boolean'),
+    dFlipSided: DefineSpec('boolean'),
+    dPositionTexture: DefineSpec('boolean'),
+}
+export type IsosurfaceSchema = typeof IsosurfaceSchema
+export type IsosurfaceValues = Values<IsosurfaceSchema>
+
+export function IsosurfaceRenderable(ctx: WebGLContext, id: number, values: IsosurfaceValues, state: RenderableState, materialId: number): Renderable<IsosurfaceValues> {
+    const schema = { ...GlobalUniformSchema, ...InternalSchema, ...IsosurfaceSchema }
+    const internalValues: InternalValues = {
+        uObjectId: ValueCell.create(id),
+        uPickable: ValueCell.create(state.pickable ? 1 : 0)
+    }
+    const shaderCode = MeshShaderCode
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId)
+
+    return createRenderable(renderItem, values, state)
+}

+ 6 - 1
src/mol-gl/shader/chunks/assign-position.glsl

@@ -1,4 +1,9 @@
 mat4 modelView = uView * uModel * aTransform;
-vec4 mvPosition = modelView * vec4(aPosition, 1.0);
+#ifdef dPositionTexture
+    vec3 position = readFromTexture(tPosition, aIndex, uPositionTexDim).xyz;
+#else
+    vec3 position = aPosition;
+#endif
+vec4 mvPosition = modelView * vec4(position, 1.0);
 vViewPosition = mvPosition.xyz;
 gl_Position = uProjection * mvPosition;

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

@@ -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>
  */
@@ -10,7 +10,13 @@ precision highp int;
 #pragma glslify: import('./chunks/common-vert-params.glsl')
 #pragma glslify: import('./chunks/color-vert-params.glsl')
 
-attribute vec3 aPosition;
+#ifdef dPositionTexture
+    attribute float aIndex;
+    uniform vec2 uPositionTexDim;
+    uniform sampler2D tPosition;
+#else
+    attribute vec3 aPosition;
+#endif
 attribute mat4 aTransform;
 attribute float aInstance;
 attribute float aGroup;