diff --git a/src/mol-gl/compute/marching-cubes/isosurface.ts b/src/mol-gl/compute/marching-cubes/isosurface.ts index 93263e22713b409f2e343f85bd84d648e5e20085..3c628b25554fbd79c14f59fee00d2fbf236c3c7c 100644 --- a/src/mol-gl/compute/marching-cubes/isosurface.ts +++ b/src/mol-gl/compute/marching-cubes/isosurface.ts @@ -42,12 +42,13 @@ const IsosurfaceSchema = { dPackedGroup: DefineSpec('boolean'), dAxisOrder: DefineSpec('string', ['012', '021', '102', '120', '201', '210']), + dConstantGroup: DefineSpec('boolean'), }; type IsosurfaceValues = Values<typeof IsosurfaceSchema> const IsosurfaceName = 'isosurface'; -function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3): ComputeRenderable<IsosurfaceValues> { +function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean): ComputeRenderable<IsosurfaceValues> { if (ctx.namedComputeRenderables[IsosurfaceName]) { const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues; @@ -66,17 +67,18 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture ValueCell.update(v.uGridTransform, transform); ValueCell.update(v.uScale, scale); - ValueCell.update(v.dPackedGroup, packedGroup); + ValueCell.updateIfChanged(v.dPackedGroup, packedGroup); ValueCell.updateIfChanged(v.dAxisOrder, axisOrder.join('')); + ValueCell.updateIfChanged(v.dConstantGroup, constantGroup); ctx.namedComputeRenderables[IsosurfaceName].update(); } else { - ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder); + ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup); } return ctx.namedComputeRenderables[IsosurfaceName]; } -function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3) { +function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean) { // console.log('uSize', Math.pow(2, levels)) const values: IsosurfaceValues = { ...QuadValues, @@ -99,6 +101,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text dPackedGroup: ValueCell.create(packedGroup), dAxisOrder: ValueCell.create(axisOrder.join('')), + dConstantGroup: ValueCell.create(constantGroup), }; const schema = { ...IsosurfaceSchema }; @@ -119,7 +122,7 @@ function setRenderingDefaults(ctx: WebGLContext) { state.clearColor(0, 0, 0, 0); } -export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { +export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { const { drawBuffers } = ctx.extensions; if (!drawBuffers) throw new Error('need WebGL draw buffers'); @@ -178,7 +181,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex groupTexture.attachFramebuffer(framebuffer, 1); normalTexture.attachFramebuffer(framebuffer, 2); - const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder); + const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup); ctx.state.currentRenderItemId = -1; framebuffer.bind(); @@ -210,11 +213,11 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex * * Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/ */ -export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { +export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { if (isTimingMode) ctx.timer.mark('extractIsosurface'); const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale); const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim); - const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, vertexTexture, groupTexture, normalTexture); + const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, constantGroup, vertexTexture, groupTexture, normalTexture); if (isTimingMode) ctx.timer.markEnd('extractIsosurface'); return gv; diff --git a/src/mol-gl/shader/marching-cubes/isosurface.frag.ts b/src/mol-gl/shader/marching-cubes/isosurface.frag.ts index ac7f0cf3d8fc48321804bb1a4d99ea23eb4a46b7..964bfdf1753935172219deb41d2593b7479d5c00 100644 --- a/src/mol-gl/shader/marching-cubes/isosurface.frag.ts +++ b/src/mol-gl/shader/marching-cubes/isosurface.frag.ts @@ -268,9 +268,9 @@ void main(void) { gl_FragData[0].xyz = (uGridTransform * vec4(b0 + t * (b0 - b1), 1.0)).xyz; // group id - #if __VERSION__ == 100 + #if __VERSION__ == 100 || defined(dConstantGroup) // webgl1 does not support 'flat' interpolation (i.e. no interpolation) - // so we ensure a constant group id per triangle here + // ensure a constant group id per triangle as needed #ifdef dPackedGroup gl_FragData[1] = vec4(voxel(coord3d).rgb, 1.0); #else diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index bab8237045584a84fed67bc85801e8f9e8062831..85da9b6064cf3e6d59dd19a88ccc118a92fbb152 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -240,7 +240,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, const axisOrder = Vec3.create(0, 1, 2); const buffer = textureMesh?.doubleBuffer.get(); - const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal); + const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, true, buffer?.vertex, buffer?.group, buffer?.normal); if (isTimingMode) ctx.webgl.timer.markEnd('createGaussianSurfaceTextureMesh'); const groupCount = unit.elements.length; @@ -248,8 +248,6 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); (surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution; - ValueCell.updateIfChanged(surface.varyingGroup, ctx.webgl.isWebGL2); - return surface; } @@ -316,7 +314,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str const axisOrder = Vec3.create(0, 1, 2); const buffer = textureMesh?.doubleBuffer.get(); - const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal); + const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, true, buffer?.vertex, buffer?.group, buffer?.normal); if (isTimingMode) ctx.webgl.timer.markEnd('createStructureGaussianSurfaceTextureMesh'); const groupCount = structure.elementCount; @@ -324,8 +322,6 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); (surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution; - ValueCell.updateIfChanged(surface.varyingGroup, ctx.webgl.isWebGL2); - return surface; } diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index f6d6b9304c4606f9d670b9db33044687c2a40fb3..d7b1f068e1cb1cb5f96cfd68726188f7a769fca0 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -189,13 +189,11 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol const axisOrder = volume.grid.cells.space.axisOrderSlowToFast as Vec3; const buffer = textureMesh?.doubleBuffer.get(); - const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal); + const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, axisOrder, true, buffer?.vertex, buffer?.group, buffer?.normal); const groupCount = volume.grid.cells.data.length; const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh); - ValueCell.updateIfChanged(surface.varyingGroup, ctx.webgl.isWebGL2); - return surface; } diff --git a/src/tests/browser/marching-cubes.ts b/src/tests/browser/marching-cubes.ts index 8c501aa700eaf6213f255cb5cb71cf5780f1c49d..5f585b77984a400c5b3ceaa0979db8dbe1ec8a52 100644 --- a/src/tests/browser/marching-cubes.ts +++ b/src/tests/browser/marching-cubes.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -73,7 +73,7 @@ async function init() { console.timeEnd('gpu mc pyramid2'); console.time('gpu mc vert2'); - createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, true, Vec3.create(0, 1, 2)); + createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, true, Vec3.create(0, 1, 2), true); webgl.waitForGpuCommandsCompleteSync(); console.timeEnd('gpu mc vert2'); console.timeEnd('gpu mc2'); @@ -96,7 +96,7 @@ async function init() { console.timeEnd('gpu mc pyramid'); console.time('gpu mc vert'); - const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true, Vec3.create(0, 1, 2)); + const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true, Vec3.create(0, 1, 2), true); webgl.waitForGpuCommandsCompleteSync(); console.timeEnd('gpu mc vert'); console.timeEnd('gpu mc');