Browse Source

wip, marchin cubes

Alexander Rose 6 years ago
parent
commit
8feaacd492

+ 6 - 4
src/mol-gl/shader/gaussian-density.frag

@@ -22,8 +22,8 @@ varying float vRadius;
 #endif
 
 #pragma glslify: import('./chunks/common.glsl')
-#pragma glslify: encodeFloatLog = require(./utils/encode-float-log.glsl)
-#pragma glslify: decodeFloatLog = require(./utils/decode-float-log.glsl)
+// #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
 
@@ -58,9 +58,11 @@ void main() {
         float density = exp(-uAlpha * ((dist * dist) / radiusSq));
         gl_FragColor = vec4(density);
     #elif defined(dCalcType_minDistance)
-        gl_FragColor.a = 1.0 - encodeFloatLog(dist);
+        gl_FragColor.a = 10000.0 - dist;
+        // gl_FragColor.a = 1.0 - encodeFloatLog(dist);
     #elif defined(dCalcType_groupId)
-        float minDistance = decodeFloatLog(1.0 - textureMinDist(fragPos).a);
+        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)

+ 7 - 6
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -115,7 +115,7 @@ async function calcGaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLCon
     framebuffer.bind()
     setRenderingDefaults(gl)
 
-    if (!texture) texture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'linear')
+    if (!texture) texture = createTexture(webgl, 'image-float32', 'rgba', 'float', 'nearest')
     texture.define(texDimX, texDimY)
 
     function render(fbTex: Texture) {
@@ -173,7 +173,7 @@ async function calcGaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLCon
     setRenderingDefaults(gl)
     gl.viewport(0, 0, dx, dy)
 
-    if (!texture) texture = createTexture(webgl, 'volume-uint8', 'rgba', 'ubyte', 'linear')
+    if (!texture) texture = createTexture(webgl, 'volume-float32', 'rgba', 'float', 'nearest')
     texture.define(dx, dy, dz)
 
     function render(fbTex: Texture) {
@@ -330,7 +330,7 @@ function getTexture2dSize(gridDim: Vec3) {
     return { texDimX, texDimY, texRows, texCols }
 }
 
-async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3) {
+export async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3) {
     // console.time('fieldFromTexture2d')
     const { framebufferCache } = ctx
     const [ dx, dy, dz ] = dim
@@ -343,7 +343,8 @@ async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3
     const idData = space.create()
     const idField = Tensor.create(space, idData)
 
-    const image = new Uint8Array(width * height * 4)
+    // const image = new Uint8Array(width * height * 4)
+    const image = new Float32Array(width * height * 4)
 
     const framebuffer = framebufferCache.get(FramebufferName).value
     framebuffer.bind()
@@ -365,8 +366,8 @@ async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3
         for (let iy = 0; iy < dy; ++iy) {
             for (let ix = 0; ix < dx; ++ix) {
                 const idx = 4 * (tmpCol * dx + (iy + tmpRow) * width + ix)
-                data[j] = image[idx + 3] / 255
-                idData[j] = decodeFloatRGB(image[idx], image[idx + 1], image[idx + 2])
+                data[j] = image[idx + 3] // / 255
+                idData[j] = decodeFloatRGB(image[idx] * 255, image[idx + 1] * 255, image[idx + 2] * 255)
                 j++
             }
         }

+ 151 - 0
src/tests/browser/marching-cubes.ts

@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import './index.html'
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
+import { Representation } from 'mol-repr/representation';
+import { Color } from 'mol-util/color';
+import { createRenderObject } from 'mol-gl/render-object';
+import { computeGaussianDensity, computeGaussianDensityTexture2d } from 'mol-math/geometry/gaussian-density';
+import { PositionData, Box3D, Sphere3D } from 'mol-math/geometry';
+import { OrderedSet } from 'mol-data/int';
+import { Vec3 } from 'mol-math/linear-algebra';
+import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm';
+import { Mesh } from 'mol-geo/geometry/mesh/mesh';
+import { ColorNames } from 'mol-util/color/tables';
+import { Isosurface } from 'mol-geo/geometry/isosurface/isosurface';
+import { calcActiveVoxels } from 'mol-gl/compute/marching-cubes/active-voxels';
+import { createHistogramPyramid } from 'mol-gl/compute/histogram-pyramid/reduction';
+import { createIsosurfaceBuffers } from 'mol-gl/compute/marching-cubes/isosurface';
+
+const parent = document.getElementById('app')!
+parent.style.width = '100%'
+parent.style.height = '100%'
+
+const canvas = document.createElement('canvas')
+canvas.style.width = '100%'
+canvas.style.height = '100%'
+parent.appendChild(canvas)
+
+const canvas3d = Canvas3D.create(canvas, parent, {
+    backgroundColor: ColorNames.white,
+    cameraMode: 'orthographic'
+})
+canvas3d.animate()
+
+async function init() {
+    const { webgl } = canvas3d
+
+    const position: PositionData = {
+        x: [0, 2],
+        y: [0, 2],
+        z: [0, 2],
+        indices: OrderedSet.ofSortedArray([0, 1]),
+    }
+    const box = Box3D.create(Vec3.create(-1, -1, -1), Vec3.create(3, 3, 3))
+    // const position: PositionData = {
+    //     x: [0],
+    //     y: [0],
+    //     z: [0],
+    //     indices: OrderedSet.ofSortedArray([0]),
+    // }
+    // const box = Box3D.create(Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1))
+    const radius = () => 1.6
+    const props = {
+        resolution: 0.1,
+        radiusOffset: 0,
+        smoothness: 1.5
+    }
+    const isoValue = Math.exp(-props.smoothness)
+
+    // console.log('bbox', densityTextureData.bbox)
+
+    // console.time('gpu gaussian2')
+    // const densityTextureData2 = await computeGaussianDensityTexture2d(position, box, radius, props, webgl).run()
+    // webgl.waitForGpuCommandsCompleteSync()
+    // console.timeEnd('gpu gaussian2')
+
+    // console.time('gpu mc2')
+    // console.time('gpu mc active2')
+    // const activeVoxelsTex2 = calcActiveVoxels(webgl, densityTextureData2.texture, densityTextureData2.gridDimension, isoValue)
+    // webgl.waitForGpuCommandsCompleteSync()
+    // console.timeEnd('gpu mc active2')
+
+    // console.time('gpu mc pyramid2')
+    // const compacted2 = createHistogramPyramid(webgl, activeVoxelsTex2)
+    // webgl.waitForGpuCommandsCompleteSync()
+    // console.timeEnd('gpu mc pyramid2')
+
+    // console.time('gpu mc vert2')
+    // const gv2 = createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDimension, densityTextureData2.transform, isoValue)
+    // webgl.waitForGpuCommandsCompleteSync()
+    // console.timeEnd('gpu mc vert2')
+    // console.timeEnd('gpu mc2')
+
+    console.time('gpu gaussian')
+    const densityTextureData = await computeGaussianDensityTexture2d(position, box, radius, props, webgl).run()
+    webgl.waitForGpuCommandsCompleteSync()
+    console.timeEnd('gpu gaussian')
+
+    console.time('gpu mc')
+    console.time('gpu mc active')
+    const activeVoxelsTex = calcActiveVoxels(webgl, densityTextureData.texture, densityTextureData.gridDimension, isoValue)
+    webgl.waitForGpuCommandsCompleteSync()
+    console.timeEnd('gpu mc active')
+
+    console.time('gpu mc pyramid')
+    const compacted = createHistogramPyramid(webgl, activeVoxelsTex)
+    webgl.waitForGpuCommandsCompleteSync()
+    console.timeEnd('gpu mc pyramid')
+
+    console.time('gpu mc vert')
+    const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDimension, densityTextureData.transform, isoValue)
+    webgl.waitForGpuCommandsCompleteSync()
+    console.timeEnd('gpu mc vert')
+    console.timeEnd('gpu mc')
+
+    console.log({ ...webgl.stats, programCount: webgl.programCache.count, shaderCount: webgl.shaderCache.count })
+
+    const mcIsosurface = Isosurface.create(gv.vertexCount, 1, gv.vertexTexture, gv.normalBuffer, gv.groupBuffer, Sphere3D.fromBox3D(Sphere3D.zero(), densityTextureData.bbox))
+    const mcIsoSurfaceProps = { doubleSided: true, flatShaded: true, alpha: 1.0 }
+    const mcIsoSurfaceValues = Isosurface.Utils.createValuesSimple(mcIsosurface, mcIsoSurfaceProps, Color(0x112299), 1)
+    // console.log('mcIsoSurfaceValues', mcIsoSurfaceValues)
+    const mcIsoSurfaceState = Isosurface.Utils.createRenderableState(mcIsoSurfaceProps)
+    const mcIsoSurfaceRenderObject = createRenderObject('isosurface', mcIsoSurfaceValues, mcIsoSurfaceState, -1)
+    const mcIsoSurfaceRepr = Representation.fromRenderObject('isosurface', mcIsoSurfaceRenderObject)
+
+    canvas3d.add(mcIsoSurfaceRepr)
+    canvas3d.resetCamera()
+
+    //
+
+    console.time('cpu gaussian')
+    const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: false }, webgl).run()
+    console.timeEnd('cpu gaussian')
+    // console.log({ densityData })
+
+    const params = {
+        isoLevel: isoValue,
+        scalarField: densityData.field,
+        idField: densityData.idField
+    }
+
+    console.time('cpu mc')
+    const surface = await computeMarchingCubesMesh(params).run()
+    console.timeEnd('cpu mc')
+    // console.log('surface', surface)
+    Mesh.computeNormalsImmediate(surface)
+    const meshProps = { doubleSided: true, flatShaded: true, alpha: 1.0 }
+    const meshValues = Mesh.Utils.createValuesSimple(surface, meshProps, Color(0x995511), 1)
+    const meshState = Mesh.Utils.createRenderableState(meshProps)
+    const meshRenderObject = createRenderObject('mesh', meshValues, meshState, -1)
+    const meshRepr = Representation.fromRenderObject('mesh', meshRenderObject)
+
+    canvas3d.add(meshRepr)
+    canvas3d.resetCamera()
+}
+
+init()

+ 1 - 0
webpack.config.js

@@ -102,6 +102,7 @@ module.exports = [
     createApp('model-server-query'),
 
     createBrowserTest('font-atlas'),
+    createBrowserTest('marching-cubes'),
     createBrowserTest('render-lines'),
     createBrowserTest('render-mesh'),
     createBrowserTest('render-shape'),