Alexander Rose 6 years ago
parent
commit
22416b2ffc

+ 12 - 33
src/mol-gl/shader/gaussian-density.frag

@@ -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>
  * @author Michael Krone <michael.krone@uni-tuebingen.de>
@@ -8,16 +8,11 @@
 precision highp float;
 
 varying vec3 vPosition;
-varying float vRadius;
+varying float vRadiusSqInv;
 #if defined(dCalcType_groupId)
-    #if defined(dGridTexType_2d)
-        precision mediump sampler2D;
-        uniform sampler2D tMinDistanceTex;
-        uniform vec3 uGridTexDim;
-    #elif defined(dGridTexType_3d)
-        precision highp sampler3D;
-        uniform sampler3D tMinDistanceTex;
-    #endif
+    precision highp sampler2D;
+    uniform sampler2D tMinDistanceTex;
+    uniform vec3 uGridTexDim;
     varying float vGroup;
 #endif
 
@@ -25,45 +20,29 @@ varying float vRadius;
 // #pragma glslify: encodeFloatLog = require(./utils/encode-float-log.glsl)
 // #pragma glslify: decodeFloatLog = require(./utils/decode-float-log.glsl)
 #pragma glslify: encodeFloatRGB = require(./utils/encode-float-rgb.glsl)
-#pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify
 
-uniform vec3 uBboxSize;
 uniform vec3 uGridDim;
+uniform vec2 uGridTexScale;
 uniform float uCurrentSlice;
 uniform float uCurrentX;
 uniform float uCurrentY;
 uniform float uAlpha;
-
-#if defined(dCalcType_groupId)
-    #if defined(dGridTexType_2d)
-        vec4 textureMinDist(vec3 pos) {
-            return texture3dFrom2dNearest(tMinDistanceTex, pos, uGridDim, uGridTexDim.xy);
-        }
-    #elif defined(dGridTexType_3d)
-        vec4 textureMinDist(vec3 pos) {
-            return texture(tMinDistanceTex, pos);
-        }
-    #endif
-#endif
+uniform float uResolution;
 
 void main() {
     vec2 v = gl_FragCoord.xy - vec2(uCurrentX, uCurrentY) - 0.5;
-    vec3 fragPos = vec3(v.x, v.y, uCurrentSlice) / uGridDim;
-    float dist = distance(fragPos * uBboxSize, vPosition * uBboxSize);
+    vec3 fragPos = vec3(v.x, v.y, uCurrentSlice);
+    float dist = distance(fragPos, vPosition) * uResolution;
 
     #if defined(dCalcType_density)
-        float radiusSq = vRadius * vRadius;
-        float density = exp(-uAlpha * ((dist * dist) / radiusSq));
+        float density = exp(-uAlpha * ((dist * dist) * vRadiusSqInv));
         gl_FragColor.a = density;
     #elif defined(dCalcType_minDistance)
         gl_FragColor.a = 10000.0 - dist;
         // gl_FragColor.a = 1.0 - encodeFloatLog(dist);
     #elif defined(dCalcType_groupId)
-        float minDistance = 10000.0 - textureMinDist(fragPos).a;
-        // float minDistance = decodeFloatLog(1.0 - textureMinDist(fragPos).a);
-        // TODO verify `length(uBboxSize / uGridDim) * 2.0`
-        //      on some machines `* 2.0` is needed while on others `* 0.5` works
-        if (dist > minDistance + length(uBboxSize / uGridDim) * 0.5)
+        float minDistance = 10000.0 - texture2D(tMinDistanceTex, (gl_FragCoord.xy) / (uGridTexDim.xy / uGridTexScale)).a;
+        if (dist > minDistance + uResolution * 0.05)
             discard;
         gl_FragColor.rgb = encodeFloatRGB(vGroup);
     #endif

+ 7 - 8
src/mol-gl/shader/gaussian-density.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>
  * @author Michael Krone <michael.krone@uni-tuebingen.de>
@@ -11,7 +11,7 @@ attribute vec3 aPosition;
 attribute float aRadius;
 
 varying vec3 vPosition;
-varying float vRadius;
+varying float vRadiusSqInv;
 
 #if defined(dCalcType_groupId)
     attribute float aGroup;
@@ -20,16 +20,15 @@ varying float vRadius;
 
 uniform vec3 uBboxSize;
 uniform vec3 uBboxMin;
-uniform vec3 uGridDim;
 uniform float uCurrentSlice;
+uniform float uResolution;
 
 void main() {
-    vRadius = aRadius;
+    vRadiusSqInv = 1.0 / (aRadius * aRadius);
     #if defined(dCalcType_groupId)
         vGroup = aGroup;
     #endif
-    float scale = max(uBboxSize.x, uBboxSize.y);
-    gl_PointSize = (vRadius / scale) * max(uGridDim.x, uGridDim.y) * 6.0;
-    vPosition = (aPosition - uBboxMin) / uBboxSize;
-    gl_Position = vec4(vPosition * 2.0 - 1.0, 1.0);
+    gl_PointSize = floor(((aRadius * 4.0) / uResolution) + 0.5);
+    vPosition = (aPosition - uBboxMin) / uResolution;
+    gl_Position = vec4(((aPosition - uBboxMin) / uBboxSize) * 2.0 - 1.0, 1.0);
 }

+ 35 - 25
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -34,7 +34,9 @@ export const GaussianDensitySchema = {
     uBboxSize: UniformSpec('v3', true),
     uGridDim: UniformSpec('v3', true),
     uGridTexDim: UniformSpec('v3', true),
+    uGridTexScale: UniformSpec('v2', true),
     uAlpha: UniformSpec('f', true),
+    uResolution: UniformSpec('f', true),
     tMinDistanceTex: TextureSpec('texture', 'rgba', 'float', 'nearest'),
 
     dGridTexType: DefineSpec('string', ['2d', '3d']),
@@ -54,10 +56,10 @@ export function GaussianDensityGPU(position: PositionData, box: Box3D, radius: (
     // always use texture2d when the gaussian density needs to be downloaded from the GPU,
     // it's faster than texture3d
     // console.time('GaussianDensityTexture2d')
-    const { scale, bbox, texture, gridDim: dim } = calcGaussianDensityTexture2d(webgl, position, box, radius, props)
+    const { scale, bbox, texture, gridDim, gridTexDim } = calcGaussianDensityTexture2d(webgl, position, box, radius, props)
     // webgl.waitForGpuCommandsCompleteSync()
     // console.timeEnd('GaussianDensityTexture2d')
-    const { field, idField } = fieldFromTexture2d(webgl, texture, dim)
+    const { field, idField } = fieldFromTexture2d(webgl, texture, gridDim, gridTexDim)
 
     return { field, idField, transform: getTransform(scale, bbox) }
 }
@@ -101,18 +103,17 @@ type GaussianDensityTextureData = {
 function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, texture?: Texture): GaussianDensityTextureData {
     const { smoothness } = props
 
-    const { drawCount, positions, radii, groups, delta, expandedBox, dim } = prepareGaussianDensityData(position, box, radius, props)
+    const { drawCount, positions, radii, groups, scale, expandedBox, dim } = prepareGaussianDensityData(position, box, radius, props)
     const [ dx, dy, dz ] = dim
     const { texDimX, texDimY, texCols, powerOfTwoSize } = getTexture2dSize(dim)
-    // console.log({ texDimX, texDimY, texCols, powerOfTwoSize })
-    // const gridTexDim = Vec3.create(powerOfTwoSize, powerOfTwoSize, 0)
+    // console.log({ texDimX, texDimY, texCols, powerOfTwoSize, dim })
     const gridTexDim = Vec3.create(texDimX, texDimY, 0)
     const gridTexScale = Vec2.create(texDimX / powerOfTwoSize, texDimY / powerOfTwoSize)
 
     const minDistanceTexture = createTexture(webgl, 'image-float32', 'rgba', 'float', 'nearest')
     minDistanceTexture.define(powerOfTwoSize, powerOfTwoSize)
 
-    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, gridTexDim, smoothness)
+    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, gridTexDim, gridTexScale, smoothness, props.resolution)
 
     //
 
@@ -123,8 +124,12 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
     framebuffer.bind()
     setRenderingDefaults(webgl)
 
-    if (!texture) texture = createTexture(webgl, 'image-float32', 'rgba', 'float', 'nearest')
-    texture.define(powerOfTwoSize, powerOfTwoSize)
+    if (!texture) {
+        texture = createTexture(webgl, 'image-float32', 'rgba', 'float', 'nearest')
+        texture.define(powerOfTwoSize, powerOfTwoSize)
+    } else if (texture.width !== powerOfTwoSize || texture.height !== powerOfTwoSize) {
+        texture.define(powerOfTwoSize, powerOfTwoSize)
+    }
 
     // console.log(renderable)
 
@@ -150,6 +155,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
             ++currCol
             currX += dx
         }
+        gl.finish()
     }
 
     setupDensityRendering(webgl, renderable)
@@ -157,27 +163,26 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
 
     setupMinDistanceRendering(webgl, renderable)
     render(minDistanceTexture, true)
-    gl.finish()
 
     setupGroupIdRendering(webgl, renderable)
     render(texture, false)
 
     // printTexture(webgl, texture, 1)
 
-    gl.finish()
-
-    return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale }
+    return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale }
 }
 
 function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, texture?: Texture): GaussianDensityTextureData {
     const { smoothness } = props
 
-    const { drawCount, positions, radii, groups, delta, expandedBox, dim } = prepareGaussianDensityData(position, box, radius, props)
+    const { drawCount, positions, radii, groups, scale, expandedBox, dim } = prepareGaussianDensityData(position, box, radius, props)
     const [ dx, dy, dz ] = dim
     const minDistanceTexture = createTexture(webgl, 'volume-float32', 'rgba', 'float', 'nearest')
     minDistanceTexture.define(dx, dy, dz)
 
-    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, dim, smoothness)
+    const gridTexScale = Vec2.create(1, 1)
+
+    const renderable = getGaussianDensityRenderable(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, dim, gridTexScale, smoothness, props.resolution)
 
     //
 
@@ -209,13 +214,14 @@ function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionDat
     setupGroupIdRendering(webgl, renderable)
     render(texture)
 
-    return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridTexScale: Vec2() }
+    return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridTexScale }
 }
 
 //
 
 function prepareGaussianDensityData(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps) {
     const { resolution, radiusOffset } = props
+    const scaleFactor = 1 / resolution
 
     const { indices, x, y, z } = position
     const n = OrderedSet.size(indices)
@@ -238,19 +244,18 @@ function prepareGaussianDensityData(position: PositionData, box: Box3D, radius:
         groups[i] = i
     }
 
-    const pad = maxRadius * 2 + resolution
+    const pad = maxRadius * 2 + resolution * 4
     const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
-    const expandedDim = Box3D.size(Vec3(), expandedBox)
-
-    const scaledBox = Box3D.scale(Box3D(), expandedBox, 1 / resolution)
+    const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor)
     const dim = Box3D.size(Vec3(), scaledBox)
     Vec3.ceil(dim, dim)
-    const delta = Vec3.div(Vec3(), dim, expandedDim)
 
-    return { drawCount: n, positions, radii, groups, delta, expandedBox, dim }
+    const scale = Vec3.create(resolution, resolution, resolution)
+
+    return { drawCount: n, positions, radii, groups, scale, expandedBox, dim }
 }
 
-function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, gridDim: Vec3, gridTexDim: Vec3, smoothness: number) {
+function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, smoothness: number, resolution: number) {
     const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
 
     const values: Values<typeof GaussianDensitySchema> = {
@@ -268,7 +273,9 @@ function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, po
         uBboxSize: ValueCell.create(extent),
         uGridDim: ValueCell.create(gridDim),
         uGridTexDim: ValueCell.create(gridTexDim),
+        uGridTexScale: ValueCell.create(gridTexScale),
         uAlpha: ValueCell.create(smoothness),
+        uResolution: ValueCell.create(resolution),
         tMinDistanceTex: ValueCell.create(minDistanceTexture),
 
         dGridTexType: ValueCell.create(minDistanceTexture.depth > 0 ? '3d' : '2d'),
@@ -308,6 +315,8 @@ function setupDensityRendering(webgl: WebGLContext, renderable: ComputeRenderabl
     renderable.update()
     state.colorMask(false, false, false, true)
     state.blendFunc(gl.ONE, gl.ONE)
+    // state.colorMask(true, true, true, true)
+    // state.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ONE, gl.ONE)
     state.blendEquation(gl.FUNC_ADD)
 }
 
@@ -338,14 +347,15 @@ function getTexture2dSize(gridDim: Vec3) {
     } else {
         texDimX = gridDim[0] * gridDim[2]
     }
-    return { texDimX, texDimY, texRows, texCols, powerOfTwoSize }
+    return { texDimX, texDimY, texRows, texCols, powerOfTwoSize: texDimY < powerOfTwoSize ? powerOfTwoSize : powerOfTwoSize * 2 }
 }
 
-export function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3) {
+export function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3, texDim: Vec3) {
     // console.time('fieldFromTexture2d')
     const { framebufferCache } = ctx
     const [ dx, dy, dz ] = dim
-    const { width, height } = texture
+    // const { width, height } = texture
+    const [ width, height ] = texDim
     const fboTexCols = Math.floor(width / dx)
 
     const space = Tensor.Space(dim, [2, 1, 0], Float32Array)

+ 3 - 3
src/tests/browser/marching-cubes.ts

@@ -50,7 +50,7 @@ async function init() {
     const box = Box3D.create(Vec3.create(0, 0, 0), Vec3.create(2, 2, 2))
     const radius = () => 1.8
     const props = {
-        resolution: 0.3,
+        resolution: 0.1,
         radiusOffset: 0,
         smoothness: 1.5
     }
@@ -119,9 +119,9 @@ async function init() {
     //
 
     console.time('cpu gaussian')
-    const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: true }, webgl).run()
+    const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: false }, webgl).run()
     console.timeEnd('cpu gaussian')
-    // console.log({ densityData })
+    console.log({ densityData })
 
     const params = {
         isoLevel: isoValue,