Alexander Rose 6 years ago
parent
commit
65c7c2f432

+ 15 - 31
src/mol-gl/compute/histogram-pyramid/reduction.ts

@@ -11,15 +11,17 @@ import { Values, TextureSpec, UniformSpec } from '../../renderable/schema';
 import { Texture, createTexture } from 'mol-gl/webgl/texture';
 import { ShaderCode } from 'mol-gl/shader-code';
 import { ValueCell } from 'mol-util';
-import { QuadSchema, QuadValues, printTexture } from '../util';
+import { QuadSchema, QuadValues } from '../util';
 import { Vec2 } from 'mol-math/linear-algebra';
 import { getHistopyramidSum } from './sum';
 import { Framebuffer, createFramebuffer } from 'mol-gl/webgl/framebuffer';
+import { isPowerOfTwo } from 'mol-math/misc';
 
 const HistopyramidReductionSchema = {
     ...QuadSchema,
     tPreviousLevel: TextureSpec('texture', 'rgba', 'float', 'nearest'),
     uSize: UniformSpec('f'),
+    uTexSize: UniformSpec('f'),
 }
 
 let HistopyramidReductionRenderable: ComputeRenderable<Values<typeof HistopyramidReductionSchema>>
@@ -33,6 +35,7 @@ function getHistopyramidReductionRenderable(ctx: WebGLContext, initialTexture: T
             ...QuadValues,
             tPreviousLevel: ValueCell.create(initialTexture),
             uSize: ValueCell.create(0),
+            uTexSize: ValueCell.create(0),
         }
 
         const schema = { ...HistopyramidReductionSchema }
@@ -47,21 +50,6 @@ function getHistopyramidReductionRenderable(ctx: WebGLContext, initialTexture: T
     }
 }
 
-/** name for shared framebuffer used for histogram-pyramid operations */
-const FramebufferName = 'histogram-pyramid-reduction'
-
-const LevelTextures: Texture[] = []
-function getLevelTexture(ctx: WebGLContext, level: number) {
-    let tex = LevelTextures[level]
-    const size = Math.pow(2, level)
-    if (tex === undefined) {
-        tex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
-        LevelTextures[level] = tex
-    }
-    tex.define(size, size) // always call to set size AND clear
-    return tex
-}
-
 type TextureFramebuffer = { texture: Texture, framebuffer: Framebuffer }
 const LevelTexturesFramebuffers: TextureFramebuffer[] = []
 function getLevelTextureFramebuffer(ctx: WebGLContext, level: number) {
@@ -97,31 +85,26 @@ export interface HistogramPyramid {
     scale: Vec2
 }
 
-export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture): HistogramPyramid {
-    const { gl, framebufferCache } = ctx
+export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture, scale: Vec2): HistogramPyramid {
+    const { gl } = ctx
 
-    printTexture(ctx, inputTexture, 2)
-    const inputTextureMaxDim = Math.max(inputTexture.width, inputTexture.height)
+    // printTexture(ctx, inputTexture, 2)
+    if (inputTexture.width !== inputTexture.height || !isPowerOfTwo(inputTexture.width)) {
+        throw new Error('inputTexture must be of square power-of-two size')
+    }
 
     // This part set the levels
-    const levels = Math.ceil(Math.log(inputTextureMaxDim) / Math.log(2))
+    const levels = Math.ceil(Math.log(inputTexture.width) / Math.log(2))
     const maxSize = Math.pow(2, levels)
     // console.log('levels', levels, 'maxSize', maxSize)
 
-    const initialTexture = getLevelTexture(ctx, levels)
-
-    const framebuffer = framebufferCache.get(FramebufferName).value
-    inputTexture.attachFramebuffer(framebuffer, 0)
-    // TODO need to initialize texSubImage2D to make Firefox happy
-    gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, inputTexture.width, inputTexture.height);
-
     const pyramidTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
     pyramidTexture.define(maxSize, maxSize)
 
     const levelTexturesFramebuffers: TextureFramebuffer[] = []
     for (let i = 0; i < levels; ++i) levelTexturesFramebuffers.push(getLevelTextureFramebuffer(ctx, i))
 
-    const renderable = getHistopyramidReductionRenderable(ctx, initialTexture)
+    const renderable = getHistopyramidReductionRenderable(ctx, inputTexture)
     ctx.state.currentRenderItemId = -1
     setRenderingDefaults(ctx)
 
@@ -138,6 +121,7 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture)
         gl.viewport(0, 0, size, size)
 
         ValueCell.update(renderable.values.uSize, Math.pow(2, i + 1) / maxSize)
+        ValueCell.update(renderable.values.uTexSize, size)
         if (i > 0) {
             ValueCell.update(renderable.values.tPreviousLevel, levelTexturesFramebuffers[levels - i].texture)
             renderable.update()
@@ -172,8 +156,8 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture)
 
     const finalCount = getHistopyramidSum(ctx, levelTexturesFramebuffers[0].texture)
     const height = Math.ceil(finalCount / Math.pow(2, levels))
-    const scale = Vec2.create(maxSize / inputTexture.width, maxSize / inputTexture.height)
-    console.log('height', height, 'finalCount', finalCount, 'scale', scale)
+    // const scale = Vec2.create(maxSize / inputTexture.width, maxSize / inputTexture.height)
+    // console.log('height', height, 'finalCount', finalCount, 'scale', scale)
 
 
     return {

+ 6 - 4
src/mol-gl/compute/marching-cubes/active-voxels.ts

@@ -34,6 +34,7 @@ const ActiveVoxelsSchema = {
 function getActiveVoxelsRenderable(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, scale: Vec2) {
     const values: Values<typeof ActiveVoxelsSchema> = {
         ...QuadValues,
+        uQuadScale: ValueCell.create(scale),
 
         tTriCount: ValueCell.create(getTriCount()),
         tVolumeData: ValueCell.create(volumeData),
@@ -66,9 +67,9 @@ function setRenderingDefaults(ctx: WebGLContext) {
     state.clearColor(0, 0, 0, 0)
 }
 
-export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, gridScale: Vec2) {
+export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, gridScale: Vec2) {
     const { gl, framebufferCache } = ctx
-    const { width, height } = cornerTex
+    const { width, height } = volumeData
 
     const framebuffer = framebufferCache.get(FramebufferName).value
     framebuffer.bind()
@@ -76,7 +77,7 @@ export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDim:
     const activeVoxelsTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
     activeVoxelsTex.define(width, height)
 
-    const renderable = getActiveVoxelsRenderable(ctx, cornerTex, gridDim, gridTexDim, isoValue, gridScale)
+    const renderable = getActiveVoxelsRenderable(ctx, volumeData, gridDim, gridTexDim, isoValue, gridScale)
     ctx.state.currentRenderItemId = -1
 
     activeVoxelsTex.attachFramebuffer(framebuffer, 0)
@@ -84,7 +85,8 @@ export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDim:
     gl.viewport(0, 0, width, height)
     renderable.render()
 
-    console.log('gridScale', gridScale)
+    // console.log('gridScale', gridScale, 'gridTexDim', gridTexDim, 'gridDim', gridDim)
+    // console.log('volumeData', volumeData)
     // console.log('at', readTexture(ctx, activeVoxelsTex))
 
     gl.finish()

+ 11 - 9
src/mol-gl/compute/marching-cubes/isosurface.ts

@@ -39,10 +39,11 @@ const IsosurfaceSchema = {
     uScale: UniformSpec('v2'),
 }
 
-function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDimensions: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number) {
+function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, height: number) {
     // console.log('uSize', Math.pow(2, levels))
     const values: Values<typeof IsosurfaceSchema> = {
         ...QuadValues,
+        uQuadScale: ValueCell.create(Vec2.create(1, height / Math.pow(2, levels))),
 
         tTriIndices: ValueCell.create(getTriIndices()),
         tActiveVoxelsPyramid: ValueCell.create(activeVoxelsPyramid),
@@ -54,8 +55,8 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
         uLevels: ValueCell.create(levels),
         uCount: ValueCell.create(count),
 
-        uGridDim: ValueCell.create(gridDimensions),
-        uGridTexDim: ValueCell.create(Vec3.create(volumeData.width, volumeData.height, 0)),
+        uGridDim: ValueCell.create(gridDim),
+        uGridTexDim: ValueCell.create(gridTexDim),
         uGridTransform: ValueCell.create(transform),
 
         uScale: ValueCell.create(scale),
@@ -77,16 +78,19 @@ function setRenderingDefaults(ctx: WebGLContext) {
     state.disable(gl.CULL_FACE)
     state.disable(gl.BLEND)
     state.disable(gl.DEPTH_TEST)
-    state.enable(gl.SCISSOR_TEST)
+    state.disable(gl.SCISSOR_TEST)
     state.depthMask(false)
     state.colorMask(true, true, true, true)
     state.clearColor(0, 0, 0, 0)
 }
 
-export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDimensions: Vec3, transform: Mat4, isoValue: number, vertexGroupTexture?: Texture, normalTexture?: Texture) {
-    const { gl, framebufferCache, state } = ctx
+export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, vertexGroupTexture?: Texture, normalTexture?: Texture) {
+    const { gl, framebufferCache } = ctx
     const { pyramidTex, height, levels, scale, count } = histogramPyramid
 
+    // console.log('iso', 'gridDim', gridDim, 'scale', scale, 'gridTexDim', gridTexDim)
+    // console.log('iso volumeData', volumeData)
+
     const framebuffer = framebufferCache.get(FramebufferName).value
 
     let needsClear = false
@@ -124,7 +128,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
     // const indexTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
     // indexTex.define(pyramidTex.width, pyramidTex.height)
 
-    const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDimensions, transform, isoValue, levels, scale, count)
+    const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, height)
     ctx.state.currentRenderItemId = -1
 
     vertexGroupTexture.attachFramebuffer(framebuffer, 0)
@@ -149,10 +153,8 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
 
     setRenderingDefaults(ctx)
     gl.viewport(0, 0, pyramidTex.width, pyramidTex.height)
-    gl.scissor(0, 0, pyramidTex.width, height)
     if (needsClear) gl.clear(gl.COLOR_BUFFER_BIT)
     renderable.render()
-    state.disable(gl.SCISSOR_TEST)
 
     gl.finish()
 

+ 4 - 4
src/mol-gl/compute/util.ts

@@ -8,7 +8,7 @@ import { WebGLContext } from 'mol-gl/webgl/context';
 import { Texture } from 'mol-gl/webgl/texture';
 import { printTextureImage } from 'mol-gl/renderable/util';
 import { defaults, ValueCell } from 'mol-util';
-import { ValueSpec, AttributeSpec, UniformSpec } from 'mol-gl/renderable/schema';
+import { ValueSpec, AttributeSpec, UniformSpec, Values } from 'mol-gl/renderable/schema';
 import { Vec2 } from 'mol-math/linear-algebra';
 
 export const QuadPositions = new Float32Array([
@@ -20,14 +20,14 @@ export const QuadSchema = {
     drawCount: ValueSpec('number'),
     instanceCount: ValueSpec('number'),
     aPosition: AttributeSpec('float32', 2, 0),
-    uScale: UniformSpec('v2'),
+    uQuadScale: UniformSpec('v2'),
 }
 
-export const QuadValues = {
+export const QuadValues: Values<typeof QuadSchema> = {
     drawCount: ValueCell.create(6),
     instanceCount: ValueCell.create(1),
     aPosition: ValueCell.create(QuadPositions),
-    uScale: ValueCell.create(Vec2.create(1, 1)),
+    uQuadScale: ValueCell.create(Vec2.create(1, 1)),
 }
 
 //

+ 3 - 4
src/mol-gl/shader/histogram-pyramid/reduction.frag

@@ -6,13 +6,12 @@ uniform sampler2D tPreviousLevel;
 
 // 1/size of the previous level texture.
 uniform float uSize;
-
-varying vec2 vCoordinate;
+uniform float uTexSize;
 
 void main(void) {
     float k = 0.5 * uSize;
-    vec2 position = floor(vCoordinate / uSize) * uSize;
-    float a = texture2D(tPreviousLevel, position + vec2(0., 0.)).r;
+    vec2 position = floor((gl_FragCoord.xy / uTexSize) / uSize) * uSize;
+    float a = texture2D(tPreviousLevel, position).r;
     float b = texture2D(tPreviousLevel, position + vec2(k, 0.)).r;
     float c = texture2D(tPreviousLevel, position + vec2(0., k)).r;
     float d = texture2D(tPreviousLevel, position + vec2(k, k)).r;

+ 1 - 4
src/mol-gl/shader/histogram-pyramid/sum.frag

@@ -9,11 +9,8 @@ precision highp sampler2D;
 
 uniform sampler2D tTexture;
 
-// uv coordinate of each fragment obtained from vertex shader.
-varying vec2 vCoordinate;
-
 #pragma glslify: encodeFloatRGB = require(../utils/encode-float-rgb.glsl)
 
 void main(void) {
-    gl_FragColor = vec4(encodeFloatRGB(texture2D(tTexture, vCoordinate).r), 1.0);
+    gl_FragColor = vec4(encodeFloatRGB(texture2D(tTexture, vec2(0.5)).r), 1.0);
 }

+ 11 - 4
src/mol-gl/shader/marching-cubes/active-voxels.frag

@@ -7,8 +7,7 @@ uniform sampler2D tVolumeData;
 uniform float uIsoValue;
 uniform vec3 uGridDim;
 uniform vec3 uGridTexDim;
-
-varying vec2 vCoordinate;
+uniform vec2 uScale;
 
 // cube corners
 const vec3 c0 = vec3(0., 0., 0.);
@@ -36,7 +35,7 @@ vec4 texture3dFrom2dNearest(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim)
     float zSlice = floor(pos.z * gridDim.z + 0.5); // round to nearest z-slice
     float column = intMod(zSlice * gridDim.x, texDim.x) / gridDim.x;
     float row = floor(intDiv(zSlice * gridDim.x, texDim.x));
-    vec2 coord = (vec2(column * gridDim.x, row * gridDim.y) + (pos.xy * gridDim.xy)) / texDim;
+    vec2 coord = (vec2(column * gridDim.x, row * gridDim.y) + (pos.xy * gridDim.xy)) / (texDim / uScale);
     // return texture2D(tex, coord + 0.5 / texDim);
     return texture2D(tex, coord);
 }
@@ -46,7 +45,8 @@ vec4 voxel(vec3 pos) {
 }
 
 void main(void) {
-    vec3 posXYZ = index3dFrom2d(vCoordinate);
+    vec2 uv = gl_FragCoord.xy / uGridTexDim.xy;
+    vec3 posXYZ = index3dFrom2d(uv);
 
     // get MC case as the sum of corners that are below the given iso level
     float c = step(voxel(posXYZ).a, uIsoValue)
@@ -63,6 +63,13 @@ void main(void) {
     float totalTrianglesToGenerate = texture2D(tTriCount, vec2(intMod(c, 16.), floor(c / 16.)) / 16.).a;
     gl_FragColor = vec4(vec3(floor(totalTrianglesToGenerate * 255.0 + 0.5) * 3.0), c);
 
+    // gl_FragColor = vec4(255.0, 0.0, 0.0, voxel(posXYZ + c4 / uGridDim).a * 255.0);
+    // gl_FragColor = vec4(255.0, 0.0, 0.0, voxel(posXYZ).a * 255.0);
+
+    // vec2 uv = vCoordinate;
+    // uv = gl_FragCoord.xy / uGridTexDim.xy;
+
+    // if (uv.y < 0.91) discard;
     // gl_FragColor = vec4(vCoordinate * 255.0, 0.0, 255.0);
     // gl_FragColor = vec4(250.0, 0.0, 0.0, 255.0);
 }

+ 7 - 6
src/mol-gl/shader/marching-cubes/isosurface.frag

@@ -18,7 +18,7 @@ uniform mat4 uGridTransform;
 // scale to volume data coord
 uniform vec2 uScale;
 
-varying vec2 vCoordinate;
+// varying vec2 vCoordinate;
 
 #pragma glslify: import('../chunks/common.glsl')
 #pragma glslify: decodeFloatRGB = require(../utils/decode-float-rgb.glsl)
@@ -48,8 +48,9 @@ vec4 texture3dFrom2dNearest(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim)
     float zSlice = floor(pos.z * gridDim.z + 0.5); // round to nearest z-slice
     float column = intMod(zSlice * gridDim.x, texDim.x) / gridDim.x;
     float row = floor(intDiv(zSlice * gridDim.x, texDim.x));
-    vec2 coord = (vec2(column * gridDim.x, row * gridDim.y) + (pos.xy * gridDim.xy)) / texDim;
-    return texture2D(tex, coord + 0.5 / texDim);
+    vec2 coord = (vec2(column * gridDim.x, row * gridDim.y) + (pos.xy * gridDim.xy)) / (texDim / uScale);
+    return texture2D(tex, coord + 0.5 / (texDim / uScale));
+    // return texture2D(tex, coord);
 }
 
 vec4 voxel(vec3 pos) {
@@ -58,7 +59,7 @@ vec4 voxel(vec3 pos) {
 
 void main(void) {
     // get 1D index
-    float vI = dot(floor(uSize * vCoordinate), vec2(1.0, uSize));
+    float vI = dot(floor(uSize * (gl_FragCoord.xy / uSize)), vec2(1.0, uSize));
 
     // ignore 1D indices outside of the grid
     if(vI >= uCount) discard;
@@ -99,10 +100,10 @@ void main(void) {
     m = vec4(greaterThanEqual(vI4, starts)) * vec4(lessThan(vI4, ends));
     position += m.y * vec2(k, 0.) + m.z * vec2(0., k) + m.w * vec2(k, k);
 
-    vec2 coord2d = position * uScale;
+    vec2 coord2d = position / uScale;
     vec3 coord3d = floor(index3dFrom2d(coord2d) + 0.5);
 
-    float edgeIndex = floor(texture2D(tActiveVoxelsBase, position * uScale).a + 0.5);
+    float edgeIndex = floor(texture2D(tActiveVoxelsBase, position).a + 0.5);
 
     // current vertex for the up to 15 MC cases
     float currentVertex = vI - dot(m, starts);

+ 2 - 10
src/mol-gl/shader/quad.vert

@@ -7,17 +7,9 @@
 precision highp float;
 
 attribute vec2 aPosition;
-
-// the output UV coordinate for each fragment
-varying vec2 vCoordinate;
-
-uniform vec2 uScale;
-
-const vec2 scale = vec2(0.5, 0.5);
+uniform vec2 uQuadScale;
 
 void main(void) {
-    vec2 s = scale * uScale;
-    vec2 position = aPosition * uScale - vec2(1.0, 1.0) + uScale;
-    vCoordinate = position * s + s; // scale vertex attribute to [0,1] range
+    vec2 position = aPosition * uQuadScale - vec2(1.0, 1.0) + uQuadScale;
     gl_Position = vec4(position, 0.0, 1.0);
 }

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

@@ -104,7 +104,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
     const { drawCount, positions, radii, groups, delta, 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 })
+    // console.log({ texDimX, texDimY, texCols, powerOfTwoSize })
     // const gridTexDim = Vec3.create(powerOfTwoSize, powerOfTwoSize, 0)
     const gridTexDim = Vec3.create(texDimX, texDimY, 0)
     const gridTexScale = Vec2.create(texDimX / powerOfTwoSize, texDimY / powerOfTwoSize)

+ 2 - 2
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -82,10 +82,10 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
     const activeVoxelsTex = calcActiveVoxels(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, isoLevel, densityTextureData.gridTexScale)
     // ctx.webgl.waitForGpuCommandsCompleteSync()
 
-    const compacted = createHistogramPyramid(ctx.webgl, activeVoxelsTex)
+    const compacted = createHistogramPyramid(ctx.webgl, activeVoxelsTex, densityTextureData.gridTexScale)
     // ctx.webgl.waitForGpuCommandsCompleteSync()
 
-    const gv = createIsosurfaceBuffers(ctx.webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.transform, isoLevel, textureMesh ? textureMesh.vertexGroupTexture.ref.value : undefined, textureMesh ? textureMesh.normalTexture.ref.value : undefined)
+    const gv = createIsosurfaceBuffers(ctx.webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoLevel, textureMesh ? textureMesh.vertexGroupTexture.ref.value : undefined, textureMesh ? textureMesh.normalTexture.ref.value : undefined)
     // ctx.webgl.waitForGpuCommandsCompleteSync()
 
     // const boundingSphere = Sphere3D.zero()

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

@@ -56,7 +56,7 @@ async function init() {
     }
     const isoValue = Math.exp(-props.smoothness)
 
-    if (false) {
+    if (true) {
         console.time('gpu gaussian2')
         const densityTextureData2 = await computeGaussianDensityTexture2d(position, box, radius, props, webgl).run()
         webgl.waitForGpuCommandsCompleteSync()
@@ -69,12 +69,12 @@ async function init() {
         console.timeEnd('gpu mc active2')
 
         console.time('gpu mc pyramid2')
-        const compacted2 = createHistogramPyramid(webgl, activeVoxelsTex2)
+        const compacted2 = createHistogramPyramid(webgl, activeVoxelsTex2, densityTextureData2.gridTexScale)
         webgl.waitForGpuCommandsCompleteSync()
         console.timeEnd('gpu mc pyramid2')
 
         console.time('gpu mc vert2')
-        createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.transform, isoValue)
+        createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue)
         webgl.waitForGpuCommandsCompleteSync()
         console.timeEnd('gpu mc vert2')
         console.timeEnd('gpu mc2')
@@ -92,12 +92,12 @@ async function init() {
     console.timeEnd('gpu mc active')
 
     console.time('gpu mc pyramid')
-    const compacted = createHistogramPyramid(webgl, activeVoxelsTex)
+    const compacted = createHistogramPyramid(webgl, activeVoxelsTex, densityTextureData.gridTexScale)
     webgl.waitForGpuCommandsCompleteSync()
     console.timeEnd('gpu mc pyramid')
 
     console.time('gpu mc vert')
-    const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.transform, isoValue)
+    const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue)
     webgl.waitForGpuCommandsCompleteSync()
     console.timeEnd('gpu mc vert')
     console.timeEnd('gpu mc')
@@ -106,7 +106,7 @@ async function init() {
 
     const mcBoundingSphere = Sphere3D.fromBox3D(Sphere3D(), densityTextureData.bbox)
     const mcIsosurface = TextureMesh.create(gv.vertexCount, 1, gv.vertexGroupTexture, gv.normalTexture, mcBoundingSphere)
-    const mcIsoSurfaceProps = { doubleSided: true, flatShaded: false, alpha: 1.0 }
+    const mcIsoSurfaceProps = { doubleSided: true, flatShaded: true, alpha: 1.0 }
     const mcIsoSurfaceValues = TextureMesh.Utils.createValuesSimple(mcIsosurface, mcIsoSurfaceProps, Color(0x112299), 1)
     // console.log('mcIsoSurfaceValues', mcIsoSurfaceValues)
     const mcIsoSurfaceState = TextureMesh.Utils.createRenderableState(mcIsoSurfaceProps)
@@ -132,7 +132,7 @@ async function init() {
     console.time('cpu mc')
     const surface = await computeMarchingCubesMesh(params).run()
     console.timeEnd('cpu mc')
-    // console.log('surface', surface)
+    console.log('surface', surface)
     Mesh.transformImmediate(surface, densityData.transform)
     const meshProps = { doubleSided: true, flatShaded: false, alpha: 1.0 }
     const meshValues = Mesh.Utils.createValuesSimple(surface, meshProps, Color(0x995511), 1)