Bladeren bron

renderable refactoring

Alexander Rose 6 jaren geleden
bovenliggende
commit
b6bb956d3b

+ 4 - 4
src/mol-canvas3d/helper/bounding-sphere-helper.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { createRenderObject, RenderObject, getNextMaterialId } from 'mol-gl/render-object'
+import { createRenderObject, GraphicsRenderObject, getNextMaterialId } from 'mol-gl/render-object'
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -27,15 +27,15 @@ export const DebugHelperParams = {
 export type DebugHelperParams = typeof DebugHelperParams
 export type DebugHelperProps = PD.Values<DebugHelperParams>
 
-type BoundingSphereData = { boundingSphere: Sphere3D, renderObject: RenderObject, mesh: Mesh }
+type BoundingSphereData = { boundingSphere: Sphere3D, renderObject: GraphicsRenderObject, mesh: Mesh }
 
 export class BoundingSphereHelper {
     readonly scene: Scene
 
     private readonly parent: Scene
     private _props: DebugHelperProps
-    private objectsData = new Map<RenderObject, BoundingSphereData>()
-    private instancesData = new Map<RenderObject, BoundingSphereData>()
+    private objectsData = new Map<GraphicsRenderObject, BoundingSphereData>()
+    private instancesData = new Map<GraphicsRenderObject, BoundingSphereData>()
     private sceneData: BoundingSphereData | undefined
 
     constructor(ctx: WebGLContext, parent: Scene, props: Partial<DebugHelperProps>) {

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

@@ -8,7 +8,6 @@ import { RenderableState, Renderable } from './renderable'
 import { RenderableValues } from './renderable/schema';
 import { idFactory } from 'mol-util/id-factory';
 import { WebGLContext } from './webgl/context';
-import { GaussianDensityValues, GaussianDensityRenderable } from './renderable/gaussian-density';
 import { DirectVolumeValues, DirectVolumeRenderable } from './renderable/direct-volume';
 import { MeshValues, MeshRenderable } from './renderable/mesh';
 import { PointsValues, PointsRenderable } from './renderable/points';
@@ -28,16 +27,10 @@ export interface TextRenderObject extends BaseRenderObject { type: 'text', value
 export interface LinesRenderObject extends BaseRenderObject { type: 'lines', values: LinesValues }
 export interface DirectVolumeRenderObject extends BaseRenderObject { type: 'direct-volume', values: DirectVolumeValues }
 
-export interface GaussianDensityRenderObject extends BaseRenderObject { type: 'gaussian-density', values: GaussianDensityValues }
-
 //
 
 export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | TextRenderObject | LinesRenderObject | DirectVolumeRenderObject
 
-export type ComputeRenderObject = GaussianDensityRenderObject
-
-export type RenderObject = GraphicsRenderObject | ComputeRenderObject
-
 export type RenderObjectKindType = {
     'mesh': MeshRenderObject
     'points': PointsRenderObject
@@ -45,8 +38,6 @@ export type RenderObjectKindType = {
     'text': TextRenderObject
     'lines': LinesRenderObject
     'direct-volume': DirectVolumeRenderObject
-
-    'gaussian-density': GaussianDensityRenderObject
 }
 export type RenderObjectValuesType = {
     'mesh': MeshValues
@@ -55,8 +46,6 @@ export type RenderObjectValuesType = {
     'text': TextValues
     'lines': LinesValues
     'direct-volume': DirectVolumeValues
-
-    'gaussian-density': GaussianDensityValues
 }
 export type RenderObjectType = keyof RenderObjectKindType
 
@@ -66,7 +55,7 @@ export function createRenderObject<T extends RenderObjectType>(type: T, values:
     return { id: getNextId(), type, values, state, materialId } as RenderObjectKindType[T]
 }
 
-export function createRenderable(ctx: WebGLContext, o: RenderObject): Renderable<any> {
+export function createRenderable(ctx: WebGLContext, o: GraphicsRenderObject): Renderable<any> {
     switch (o.type) {
         case 'mesh': return MeshRenderable(ctx, o.id, o.values, o.state, o.materialId)
         case 'points': return PointsRenderable(ctx, o.id, o.values, o.state, o.materialId)
@@ -74,7 +63,5 @@ export function createRenderable(ctx: WebGLContext, o: RenderObject): Renderable
         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 'gaussian-density': return GaussianDensityRenderable(ctx, o.id, o.values, o.state)
     }
 }

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

@@ -50,4 +50,28 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
         update: () => renderItem.update(),
         dispose: () => renderItem.destroy()
     }
+}
+
+//
+
+export interface ComputeRenderable<T extends RenderableValues> {
+    readonly id: number
+    readonly values: T
+
+    render: () => void
+    getProgram: () => Program
+    update: () => void
+    dispose: () => void
+}
+
+export function createComputeRenderable<T extends Values<RenderableSchema>>(renderItem: RenderItem, values: T): ComputeRenderable<T> {
+    return {
+        id: getNextRenderableId(),
+        values,
+
+        render: () => renderItem.render('draw'),
+        getProgram: () => renderItem.getProgram('draw'),
+        update: () => renderItem.update(),
+        dispose: () => renderItem.destroy()
+    }
 }

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

@@ -7,7 +7,7 @@
 import { Renderable } from './renderable'
 import { WebGLContext } from './webgl/context';
 import { RenderableValues, BaseValues } from './renderable/schema';
-import { RenderObject, createRenderable, GraphicsRenderObject } from './render-object';
+import { GraphicsRenderObject, createRenderable } from './render-object';
 import { Object3D } from './object3d';
 import { Sphere3D } from 'mol-math/geometry';
 import { Vec3 } from 'mol-math/linear-algebra';
@@ -58,16 +58,16 @@ interface Scene extends Object3D {
     readonly boundingSphere: Sphere3D
 
     update: (objects: ArrayLike<GraphicsRenderObject> | undefined, keepBoundingSphere: boolean) => void
-    add: (o: RenderObject) => Renderable<any>
-    remove: (o: RenderObject) => void
-    has: (o: RenderObject) => boolean
+    add: (o: GraphicsRenderObject) => Renderable<any>
+    remove: (o: GraphicsRenderObject) => void
+    has: (o: GraphicsRenderObject) => boolean
     clear: () => void
-    forEach: (callbackFn: (value: Renderable<RenderableValues & BaseValues>, key: RenderObject) => void) => void
+    forEach: (callbackFn: (value: Renderable<RenderableValues & BaseValues>, key: GraphicsRenderObject) => void) => void
 }
 
 namespace Scene {
     export function create(ctx: WebGLContext): Scene {
-        const renderableMap = new Map<RenderObject, Renderable<RenderableValues & BaseValues>>()
+        const renderableMap = new Map<GraphicsRenderObject, Renderable<RenderableValues & BaseValues>>()
         const renderables: Renderable<RenderableValues & BaseValues>[] = []
         const boundingSphere = Sphere3D.zero()
         let boundingSphereDirty = true
@@ -95,7 +95,7 @@ namespace Scene {
                 }
                 if (!keepBoundingSphere) boundingSphereDirty = true
             },
-            add: (o: RenderObject) => {
+            add: (o: GraphicsRenderObject) => {
                 if (!renderableMap.has(o)) {
                     const renderable = createRenderable(ctx, o)
                     renderables.push(renderable)
@@ -108,7 +108,7 @@ namespace Scene {
                     return renderableMap.get(o)!
                 }
             },
-            remove: (o: RenderObject) => {
+            remove: (o: GraphicsRenderObject) => {
                 const renderable = renderableMap.get(o)
                 if (renderable) {
                     renderable.dispose()
@@ -118,7 +118,7 @@ namespace Scene {
                     boundingSphereDirty = true
                 }
             },
-            has: (o: RenderObject) => {
+            has: (o: GraphicsRenderObject) => {
                 return renderableMap.has(o)
             },
             clear: () => {
@@ -129,7 +129,7 @@ namespace Scene {
                 renderableMap.clear()
                 boundingSphereDirty = true
             },
-            forEach: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
+            forEach: (callbackFn: (value: Renderable<any>, key: GraphicsRenderObject) => void) => {
                 renderableMap.forEach(callbackFn)
             },
             get count() {

+ 0 - 6
src/mol-gl/shader-code.ts

@@ -60,12 +60,6 @@ export const MeshShaderCode = ShaderCode(
     { standardDerivatives: true, fragDepth: false }
 )
 
-export const GaussianDensityShaderCode = ShaderCode(
-    require('mol-gl/shader/gaussian-density.vert'),
-    require('mol-gl/shader/gaussian-density.frag'),
-    { standardDerivatives: false, fragDepth: false }
-)
-
 export const DirectVolumeShaderCode = ShaderCode(
     require('mol-gl/shader/direct-volume.vert'),
     require('mol-gl/shader/direct-volume.frag'),

+ 53 - 29
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author Michael Krone <michael.krone@uni-tuebingen.de>
@@ -11,17 +11,47 @@ import { Box3D } from '../../geometry'
 import { GaussianDensityGPUProps, getDelta } from '../gaussian-density'
 import { OrderedSet } from 'mol-data/int'
 import { Vec3, Tensor, Mat4 } from '../../linear-algebra'
-import { GaussianDensityValues } from 'mol-gl/renderable/gaussian-density'
 import { ValueCell } from 'mol-util'
-import { RenderableState, Renderable } from 'mol-gl/renderable'
-import { createRenderable, createRenderObject } from 'mol-gl/render-object'
+import { createComputeRenderable, ComputeRenderable } from 'mol-gl/renderable'
 import { WebGLContext } from 'mol-gl/webgl/context';
 import { createTexture, Texture } from 'mol-gl/webgl/texture';
 import { GLRenderingContext } from 'mol-gl/webgl/compat';
 import { decodeFloatRGB } from 'mol-util/float-packing';
+import { ShaderCode } from 'mol-gl/shader-code';
+import { createRenderItem } from 'mol-gl/webgl/render-item';
+import { ValueSpec, AttributeSpec, UniformSpec, TextureSpec, DefineSpec, Values } from 'mol-gl/renderable/schema';
+
+export const GaussianDensitySchema = {
+    drawCount: ValueSpec('number'),
+    instanceCount: ValueSpec('number'),
+
+    aRadius: AttributeSpec('float32', 1, 0),
+    aPosition: AttributeSpec('float32', 3, 0),
+    aGroup: AttributeSpec('float32', 1, 0),
+
+    uCurrentSlice: UniformSpec('f'),
+    uCurrentX: UniformSpec('f'),
+    uCurrentY: UniformSpec('f'),
+    uBboxMin: UniformSpec('v3'),
+    uBboxMax: UniformSpec('v3'),
+    uBboxSize: UniformSpec('v3'),
+    uGridDim: UniformSpec('v3'),
+    uGridTexDim: UniformSpec('v3'),
+    uAlpha: UniformSpec('f'),
+    tMinDistanceTex: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
+
+    dGridTexType: DefineSpec('string', ['2d', '3d']),
+    dCalcType: DefineSpec('string', ['density', 'minDistance', 'groupId']),
+}
+
+export const GaussianDensityShaderCode = ShaderCode(
+    require('mol-gl/shader/gaussian-density.vert'),
+    require('mol-gl/shader/gaussian-density.frag'),
+    { standardDerivatives: false, fragDepth: false }
+)
 
 /** name for shared framebuffer used for gpu gaussian surface operations */
-const FramebufferName = 'gaussian-density-gpu'
+const FramebufferName = 'gaussian-density'
 
 export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext): Promise<DensityData> {
     // always use texture2d when the gaussian density needs to be downloaded from the GPU,
@@ -64,13 +94,12 @@ async function GaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLContext
     const minDistanceTexture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'nearest')
     minDistanceTexture.define(texDimX, texDimY)
 
-    const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness)
-    const renderable = createRenderable(webgl, renderObject)
+    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness)
 
     //
 
     const { gl, framebufferCache } = webgl
-    const { uCurrentSlice, uCurrentX, uCurrentY } = renderObject.values
+    const { uCurrentSlice, uCurrentX, uCurrentY } = renderable.values
 
     const framebuffer = framebufferCache.get(webgl, FramebufferName).value
     framebuffer.bind()
@@ -94,7 +123,7 @@ async function GaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLContext
             ValueCell.update(uCurrentSlice, i)
             ValueCell.update(uCurrentX, currX)
             ValueCell.update(uCurrentY, currY)
-            renderable.render('draw')
+            renderable.render()
             ++currCol
             currX += dx
         }
@@ -123,13 +152,12 @@ async function GaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLContext
     const minDistanceTexture = createTexture(webgl, 'volume-uint8', 'rgba', 'ubyte', 'nearest')
     minDistanceTexture.define(dx, dy, dz)
 
-    const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness)
-    const renderable = createRenderable(webgl, renderObject)
+    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness)
 
     //
 
     const { gl, framebufferCache } = webgl
-    const { uCurrentSlice } = renderObject.values
+    const { uCurrentSlice } = renderable.values
 
     const framebuffer = framebufferCache.get(webgl, FramebufferName).value
     framebuffer.bind()
@@ -143,7 +171,7 @@ async function GaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLContext
         for (let i = 0; i < dz; ++i) {
             ValueCell.update(uCurrentSlice, i)
             fbTex.attachFramebuffer(framebuffer, 0, i)
-            renderable.render('draw')
+            renderable.render()
         }
     }
 
@@ -204,11 +232,11 @@ async function prepareGaussianDensityData(ctx: RuntimeContext, position: Positio
     return { drawCount: n, positions, radii, groups, delta, expandedBox, dim }
 }
 
-function getGaussianDensityRenderObject(webgl: WebGLContext, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, dimensions: Vec3, smoothness: number) {
+function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, dimensions: Vec3, smoothness: number) {
     const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
     const { texDimX, texDimY } = getTexture2dSize(webgl.maxTextureSize, dimensions)
 
-    const values: GaussianDensityValues = {
+    const values: Values<typeof GaussianDensitySchema> = {
         drawCount: ValueCell.create(drawCount),
         instanceCount: ValueCell.create(1),
 
@@ -230,16 +258,12 @@ function getGaussianDensityRenderObject(webgl: WebGLContext, drawCount: number,
         dGridTexType: ValueCell.create(minDistanceTexture.depth > 0 ? '3d' : '2d'),
         dCalcType: ValueCell.create('density'),
     }
-    const state: RenderableState = {
-        visible: true,
-        alphaFactor: 1,
-        pickable: false,
-        opaque: true
-    }
 
-    const renderObject = createRenderObject('gaussian-density', values, state, -1)
+    const schema = { ...GaussianDensitySchema }
+    const shaderCode = GaussianDensityShaderCode
+    const renderItem =  createRenderItem(webgl, 'points', shaderCode, schema, values, -1)
 
-    return renderObject
+    return createComputeRenderable(renderItem, values)
 }
 
 function setRenderingDefaults(gl: GLRenderingContext) {
@@ -249,30 +273,30 @@ function setRenderingDefaults(gl: GLRenderingContext) {
     gl.enable(gl.BLEND)
 }
 
-function setupMinDistanceRendering(webgl: WebGLContext, renderable: Renderable<any>) {
+function setupMinDistanceRendering(webgl: WebGLContext, renderable: ComputeRenderable<any>) {
     const { gl } = webgl
     ValueCell.update(renderable.values.dCalcType, 'minDistance')
     renderable.update()
-    renderable.getProgram('draw').use()
+    renderable.getProgram().use()
     gl.blendFunc(gl.ONE, gl.ONE)
     // the shader writes 1 - dist so we set blending to MAX
     gl.blendEquation(webgl.extensions.blendMinMax.MAX)
 }
 
-function setupDensityRendering(webgl: WebGLContext, renderable: Renderable<any>) {
+function setupDensityRendering(webgl: WebGLContext, renderable: ComputeRenderable<any>) {
     const { gl } = webgl
     ValueCell.update(renderable.values.dCalcType, 'density')
     renderable.update()
-    renderable.getProgram('draw').use()
+    renderable.getProgram().use()
     gl.blendFunc(gl.ONE, gl.ONE)
     gl.blendEquation(gl.FUNC_ADD)
 }
 
-function setupGroupIdRendering(webgl: WebGLContext, renderable: Renderable<any>) {
+function setupGroupIdRendering(webgl: WebGLContext, renderable: ComputeRenderable<any>) {
     const { gl } = webgl
     ValueCell.update(renderable.values.dCalcType, 'groupId')
     renderable.update()
-    renderable.getProgram('draw').use()
+    renderable.getProgram().use()
     // overwrite color, don't change alpha
     gl.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ZERO, gl.ONE)
     gl.blendEquation(gl.FUNC_ADD)