diff --git a/src/mol-gl/compute/marching-cubes/isosurface.ts b/src/mol-gl/compute/marching-cubes/isosurface.ts index 95cec571c9a40a7f21e0bbe178e94fe0682c0130..d3f11466b5dc1a8eb11fa24f5500afdd8d586fb5 100644 --- a/src/mol-gl/compute/marching-cubes/isosurface.ts +++ b/src/mol-gl/compute/marching-cubes/isosurface.ts @@ -39,13 +39,14 @@ const IsosurfaceSchema = { uGridTransform: UniformSpec('m4'), uScale: UniformSpec('v2'), - dPackedGroup: DefineSpec('boolean') + dPackedGroup: DefineSpec('boolean'), + dAxisOrder: DefineSpec('string', ['012', '021', '102', '120', '201', '210']), }; 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): 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): ComputeRenderable<IsosurfaceValues> { if (ctx.namedComputeRenderables[IsosurfaceName]) { const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues; @@ -65,15 +66,16 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture ValueCell.update(v.uScale, scale); ValueCell.update(v.dPackedGroup, packedGroup); + ValueCell.updateIfChanged(v.dAxisOrder, axisOrder.join('')); ctx.namedComputeRenderables[IsosurfaceName].update(); } else { - ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup); + ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder); } 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) { +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) { // console.log('uSize', Math.pow(2, levels)) const values: IsosurfaceValues = { ...QuadValues, @@ -94,7 +96,8 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text uGridTransform: ValueCell.create(transform), uScale: ValueCell.create(scale), - dPackedGroup: ValueCell.create(packedGroup) + dPackedGroup: ValueCell.create(packedGroup), + dAxisOrder: ValueCell.create(axisOrder.join('')), }; const schema = { ...IsosurfaceSchema }; @@ -115,7 +118,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, 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, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { const { drawBuffers } = ctx.extensions; if (!drawBuffers) throw new Error('need WebGL draw buffers'); @@ -173,7 +176,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); + const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder); ctx.state.currentRenderItemId = -1; framebuffer.bind(); @@ -204,7 +207,7 @@ 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, 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, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { // console.time('calcActiveVoxels'); const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale); // ctx.waitForGpuCommandsCompleteSync(); @@ -216,7 +219,7 @@ export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDi // console.timeEnd('createHistogramPyramid'); // console.time('createIsosurfaceBuffers'); - const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, vertexTexture, groupTexture, normalTexture); + const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, vertexTexture, groupTexture, normalTexture); // ctx.waitForGpuCommandsCompleteSync(); // console.timeEnd('createIsosurfaceBuffers'); diff --git a/src/mol-gl/shader/marching-cubes/isosurface.frag.ts b/src/mol-gl/shader/marching-cubes/isosurface.frag.ts index 0f5e373ab4b323ff239d85e3bedde7765001500b..30368d2710ce4bb1d733ed6c64cc1733dd81b356 100644 --- a/src/mol-gl/shader/marching-cubes/isosurface.frag.ts +++ b/src/mol-gl/shader/marching-cubes/isosurface.frag.ts @@ -256,7 +256,20 @@ void main(void) { gl_FragData[1] = vec4(voxel(coord3d).rgb, 1.0); #else vec3 gridDim = uGridDim - vec3(1.0, 1.0, 0.0); // remove xy padding - float group = coord3d.z + coord3d.y * gridDim.z + coord3d.x * gridDim.z * gridDim.y; + // note that we swap x and z because the texture is flipped around y + #if defined(dAxisOrder_012) + float group = coord3d.z + coord3d.y * gridDim.z + coord3d.x * gridDim.z * gridDim.y; // 210 + #elif defined(dAxisOrder_021) + float group = coord3d.y + coord3d.z * gridDim.y + coord3d.x * gridDim.y * gridDim.z; // 120 + #elif defined(dAxisOrder_102) + float group = coord3d.z + coord3d.x * gridDim.z + coord3d.y * gridDim.z * gridDim.x; // 201 + #elif defined(dAxisOrder_120) + float group = coord3d.x + coord3d.z * gridDim.x + coord3d.y * gridDim.x * gridDim.z; // 021 + #elif defined(dAxisOrder_201) + float group = coord3d.y + coord3d.x * gridDim.y + coord3d.z * gridDim.y * gridDim.x; // 102 + #elif defined(dAxisOrder_210) + float group = coord3d.x + coord3d.y * gridDim.x + coord3d.z * gridDim.x * gridDim.y; // 012 + #endif gl_FragData[1] = vec4(group > 16777215.5 ? vec3(1.0) : encodeFloatRGB(group), 1.0); #endif #else @@ -265,7 +278,20 @@ void main(void) { #else vec3 b = t < 0.5 ? b0 : b1; vec3 gridDim = uGridDim - vec3(1.0, 1.0, 0.0); // remove xy padding - float group = b.z + b.y * gridDim.z + b.x * gridDim.z * gridDim.y; + // note that we swap x and z because the texture is flipped around y + #if defined(dAxisOrder_012) + float group = b.z + b.y * gridDim.z + b.x * gridDim.z * gridDim.y; // 210 + #elif defined(dAxisOrder_021) + float group = b.y + b.z * gridDim.y + b.x * gridDim.y * gridDim.z; // 120 + #elif defined(dAxisOrder_102) + float group = b.z + b.x * gridDim.z + b.y * gridDim.z * gridDim.x; // 201 + #elif defined(dAxisOrder_120) + float group = b.x + b.z * gridDim.x + b.y * gridDim.x * gridDim.z; // 021 + #elif defined(dAxisOrder_201) + float group = b.y + b.x * gridDim.y + b.z * gridDim.y * gridDim.x; // 102 + #elif defined(dAxisOrder_210) + float group = b.x + b.y * gridDim.x + b.z * gridDim.x * gridDim.y; // 012 + #endif gl_FragData[1] = vec4(group > 16777215.5 ? vec3(1.0) : encodeFloatRGB(group), 1.0); #endif #endif diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index b1a5e967365e08cab106a9ced25bac164156d55e..0e0004d0bce63f339fb5b5b5a23e7d3935abb7dd 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -26,6 +26,7 @@ import { Texture } from '../../../mol-gl/webgl/texture'; import { applyMeshColorSmoothing } from '../../../mol-geo/geometry/mesh/color-smoothing'; import { applyTextureMeshColorSmoothing } from '../../../mol-geo/geometry/texture-mesh/color-smoothing'; import { ColorSmoothingParams, getColorSmoothingProps } from '../../../mol-geo/geometry/base'; +import { Vec3 } from '../../../mol-math/linear-algebra'; const SharedParams = { ...GaussianDensityParams, @@ -230,8 +231,9 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor; + 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, 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, buffer?.vertex, buffer?.group, buffer?.normal); const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure)); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); @@ -306,8 +308,9 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor; + 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, 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, buffer?.vertex, buffer?.group, buffer?.normal); const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure)); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index 0e568289373d3a20561d46bacbd4b64cd3d854be..5cdce7c30b607d5e5deeea2e1e0f07c3e5327c5e 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -183,8 +183,9 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl); + 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, buffer?.vertex, buffer?.group, buffer?.normal); + const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh); diff --git a/src/tests/browser/marching-cubes.ts b/src/tests/browser/marching-cubes.ts index 117efefe4513aa45b964f90c306024edc4eb5e4d..8c501aa700eaf6213f255cb5cb71cf5780f1c49d 100644 --- a/src/tests/browser/marching-cubes.ts +++ b/src/tests/browser/marching-cubes.ts @@ -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); + createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, true, Vec3.create(0, 1, 2)); 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); + const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true, Vec3.create(0, 1, 2)); webgl.waitForGpuCommandsCompleteSync(); console.timeEnd('gpu mc vert'); console.timeEnd('gpu mc');