Compare commits

...

8 Commits

Author SHA1 Message Date
dsehnal
614cffda96 2.0.1 2021-03-23 15:44:24 +01:00
dsehnal
2e0379d202 npm ignore 2021-03-23 15:42:52 +01:00
dsehnal
b5cfdcd2a3 2.0.0 2021-03-23 15:31:18 +01:00
dsehnal
c00de6fde0 Merge branch 'master' of https://github.com/molstar/molstar 2021-03-23 11:16:26 +01:00
Alexander Rose
da3a8e56f3 handle negative isovalues in gpu mc 2021-03-22 22:06:49 -07:00
dsehnal
103d6fe775 alpha orbitals tryUseGpu param 2021-03-22 20:18:48 +01:00
dsehnal
5df55e6bf7 SDF delimiter bugfix + multi-molecule SDF support in mol-plugin 2021-03-22 17:21:47 +01:00
dsehnal
3b285086d4 rename files called "macro" due to Jest not being able to process them 2021-03-22 16:53:48 +01:00
17 changed files with 132 additions and 34 deletions

View File

@@ -1 +1 @@
tsconfig.commonjs.buildinfo
tsconfig.commonjs.tsbuildinfo

4
package-lock.json generated
View File

@@ -1,11 +1,11 @@
{
"name": "molstar",
"version": "2.0.0-dev.13",
"version": "2.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "2.0.0-dev.13",
"version": "2.0.1",
"license": "MIT",
"dependencies": {
"@types/argparse": "^1.0.38",

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "2.0.0-dev.13",
"version": "2.0.1",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {

View File

@@ -174,7 +174,8 @@ export class AlphaOrbitalsExample {
kind,
relativeIsovalue: this.state.value.isoValue,
pickable: false,
xrayShaded: true
xrayShaded: true,
tryUseGpu: false
};
}

View File

@@ -172,7 +172,8 @@ export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
color: PD.Color(ColorNames.blue),
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
xrayShaded: PD.Boolean(false),
pickable: PD.Boolean(true)
pickable: PD.Boolean(true),
tryUseGpu: PD.Boolean(true)
}
})({
canAutoUpdate() {
@@ -230,7 +231,7 @@ function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Da
colorParams: { value: params.color }
} : {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded },
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
color: 'uniform',
colorParams: { value: params.color }
});

View File

@@ -32,6 +32,7 @@ const IsosurfaceSchema = {
uSize: UniformSpec('f'),
uLevels: UniformSpec('f'),
uCount: UniformSpec('f'),
uInvert: UniformSpec('b'),
uGridDim: UniformSpec('v3'),
uGridTexDim: UniformSpec('v3'),
@@ -44,7 +45,7 @@ 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, 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): ComputeRenderable<IsosurfaceValues> {
if (ctx.namedComputeRenderables[IsosurfaceName]) {
const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues;
@@ -56,6 +57,7 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ValueCell.updateIfChanged(v.uSize, Math.pow(2, levels));
ValueCell.updateIfChanged(v.uLevels, levels);
ValueCell.updateIfChanged(v.uCount, count);
ValueCell.updateIfChanged(v.uInvert, invert);
ValueCell.update(v.uGridDim, gridDim);
ValueCell.update(v.uGridTexDim, gridTexDim);
@@ -66,12 +68,12 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ctx.namedComputeRenderables[IsosurfaceName].update();
} else {
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, packedGroup);
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
}
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, 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) {
// console.log('uSize', Math.pow(2, levels))
const values: IsosurfaceValues = {
...QuadValues,
@@ -85,6 +87,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text
uSize: ValueCell.create(Math.pow(2, levels)),
uLevels: ValueCell.create(levels),
uCount: ValueCell.create(count),
uInvert: ValueCell.create(invert),
uGridDim: ValueCell.create(gridDim),
uGridTexDim: ValueCell.create(gridTexDim),
@@ -112,7 +115,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, 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, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
const { gl, resources, extensions } = ctx;
const { pyramidTex, height, levels, scale, count } = histogramPyramid;
const width = pyramidTex.getWidth();
@@ -167,7 +170,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, packedGroup);
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
ctx.state.currentRenderItemId = -1;
const { drawBuffers } = ctx.extensions;
@@ -201,7 +204,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, 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, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync();
@@ -213,7 +216,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, packedGroup, vertexTexture, groupTexture, normalTexture);
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, vertexTexture, groupTexture, normalTexture);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers');

View File

@@ -18,6 +18,7 @@ uniform float uIsoValue;
uniform float uLevels;
uniform float uSize;
uniform float uCount;
uniform bool uInvert;
uniform vec3 uGridDim;
uniform vec3 uGridTexDim;
@@ -163,6 +164,13 @@ void main(void) {
// current vertex for the up to 15 MC cases
int currentVertex = vI - idot4(m, starts);
// ensure winding-order is the same for negative and positive iso-levels
if (uInvert) {
int v = imod(currentVertex + 1, 3);
if (v == 1) currentVertex += 2;
else if (v == 0) currentVertex -= 2;
}
// get index into triIndices table
int mcIndex = 16 * int(edgeIndex) + currentVertex;
vec4 mcData = texture2D(tTriIndices, vec2(imod(mcIndex, 64), mcIndex / 64) / 64.);
@@ -273,11 +281,18 @@ void main(void) {
voxelPadded(b1 - c3).a - voxelPadded(b1 + c3).a,
voxelPadded(b1 - c4).a - voxelPadded(b1 + c4).a
));
mat3 normalMatrix = transpose3(inverse3(mat3(uGridTransform)));
gl_FragData[2].xyz = normalMatrix * -vec3(
gl_FragData[2].xyz = -vec3(
n0.x + t * (n0.x - n1.x),
n0.y + t * (n0.y - n1.y),
n0.z + t * (n0.z - n1.z)
);
// ensure normal-direction is the same for negative and positive iso-levels
if (uInvert) {
gl_FragData[2].xyz *= -1.0;
}
// apply normal matrix
gl_FragData[2].xyz *= transpose3(inverse3(mat3(uGridTransform)));
}
`;

View File

@@ -112,7 +112,22 @@ Phosphate ion
> <SYNONYMS>
Orthophosphate; Phosphate
$$$$`;
$$$$
Comp 2
5 4 0 0 0 0 999 V2000
0.0000 0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
-0.8250 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
0.0000 -0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
0.0000 0.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
0.8250 0.0000 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
4 1 1 0 0 0 0
4 2 2 0 0 0 0
4 3 1 0 0 0 0
4 5 1 0 0 0 0
M CHG 3 1 -1 3 -1 5 -1
M END`;
describe('sdf reader', () => {
it('basic', async () => {
@@ -120,14 +135,20 @@ describe('sdf reader', () => {
if (parsed.isError) {
throw new Error(parsed.message);
}
const compound = parsed.result.compounds[0];
const { molFile, dataItems } = compound;
const compound1 = parsed.result.compounds[0];
const compound2 = parsed.result.compounds[1];
const { molFile, dataItems } = compound1;
const { atoms, bonds } = molFile;
expect(parsed.result.compounds.length).toBe(2);
// number of structures
expect(atoms.count).toBe(5);
expect(bonds.count).toBe(4);
expect(compound2.molFile.atoms.count).toBe(5);
expect(compound2.molFile.bonds.count).toBe(4);
expect(atoms.x.value(0)).toBeCloseTo(0, 0.001);
expect(atoms.y.value(0)).toBeCloseTo(0.8250, 0.0001);
expect(atoms.z.value(0)).toBeCloseTo(0, 0.0001);

View File

@@ -22,6 +22,7 @@ export interface SdfFile {
}[]
}
const delimiter = '$$$$';
function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, data: Column<string> } {
const dataHeader = TokenBuilder.create(tokenizer.data, 32);
const data = TokenBuilder.create(tokenizer.data, 32);
@@ -29,6 +30,7 @@ function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, da
let sawHeaderToken = false;
while (tokenizer.position < tokenizer.length) {
const line = Tokenizer.readLine(tokenizer);
if (line.startsWith(delimiter)) break;
if (!!line) {
if (line.startsWith('> <')) {
TokenBuilder.add(dataHeader, tokenizer.tokenStart + 3, tokenizer.tokenEnd - 1);
@@ -49,9 +51,7 @@ function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, da
};
}
function handleMolFile(data: string) {
const tokenizer = Tokenizer(data);
function handleMolFile(tokenizer: Tokenizer) {
const title = Tokenizer.readLine(tokenizer).trim();
const program = Tokenizer.readLine(tokenizer).trim();
const comment = Tokenizer.readLine(tokenizer).trim();
@@ -60,6 +60,15 @@ function handleMolFile(data: string) {
const atomCount = +counts.substr(0, 3), bondCount = +counts.substr(3, 3);
if (Number.isNaN(atomCount) || Number.isNaN(bondCount)) {
// try to skip to next molecule
while (tokenizer.position < tokenizer.length) {
const line = Tokenizer.readLine(tokenizer);
if (line.startsWith(delimiter)) break;
}
return;
}
const atoms = handleAtoms(tokenizer, atomCount);
const bonds = handleBonds(tokenizer, bondCount);
const dataItems = handleDataItems(tokenizer);
@@ -70,10 +79,16 @@ function handleMolFile(data: string) {
};
}
const delimiter = '$$$$';
function parseInternal(data: string): Result<SdfFile> {
const result: SdfFile = { compounds: data.split(delimiter).map(d => handleMolFile(d)) };
return Result.success(result);
const tokenizer = Tokenizer(data);
const compounds: SdfFile['compounds'] = [];
while (tokenizer.position < tokenizer.length) {
const c = handleMolFile(tokenizer);
if (c) compounds.push(c);
}
return Result.success({ compounds });
}
export function parseSdf(data: string) {

View File

@@ -123,14 +123,23 @@ export const GroProvider: TrajectoryFormatProvider = {
};
export const MolProvider: TrajectoryFormatProvider = {
label: 'MOL/SDF',
description: 'MOL/SDF',
label: 'MOL',
description: 'MOL',
category: TrajectoryFormatCategory,
stringExtensions: ['mol', 'sdf', 'sd'],
stringExtensions: ['mol'],
parse: directTrajectory(StateTransforms.Model.TrajectoryFromMOL),
visuals: defaultVisuals
};
export const SdfProvider: TrajectoryFormatProvider = {
label: 'SDF',
description: 'SDF',
category: TrajectoryFormatCategory,
stringExtensions: ['sdf', 'sd'],
parse: directTrajectory(StateTransforms.Model.TrajectoryFromSDF),
visuals: defaultVisuals
};
export const Mol2Provider: TrajectoryFormatProvider = {
label: 'MOL2',
description: 'MOL2',
@@ -148,6 +157,7 @@ export const BuiltInTrajectoryFormats = [
['gro', GroProvider] as const,
['xyz', XyzProvider] as const,
['mol', MolProvider] as const,
['sdf', SdfProvider] as const,
['mol2', Mol2Provider] as const,
] as const;

View File

@@ -39,6 +39,7 @@ import { parseXtc } from '../../mol-io/reader/xtc/parser';
import { coordinatesFromXtc } from '../../mol-model-formats/structure/xtc';
import { parseXyz } from '../../mol-io/reader/xyz/parser';
import { trajectoryFromXyz } from '../../mol-model-formats/structure/xyz';
import { parseSdf } from '../../mol-io/reader/sdf/parser';
export { CoordinatesFromDcd };
export { CoordinatesFromXtc };
@@ -50,6 +51,7 @@ export { TrajectoryFromPDB };
export { TrajectoryFromGRO };
export { TrajectoryFromXYZ };
export { TrajectoryFromMOL };
export { TrajectoryFromSDF };
export { TrajectoryFromMOL2 };
export { TrajectoryFromCube };
export { TrajectoryFromCifCore };
@@ -292,6 +294,36 @@ const TrajectoryFromMOL = PluginStateTransform.BuiltIn({
}
});
type TrajectoryFromSDF = typeof TrajectoryFromSDF
const TrajectoryFromSDF = PluginStateTransform.BuiltIn({
name: 'trajectory-from-sdf',
display: { name: 'Parse SDF', description: 'Parse SDF string and create trajectory.' },
from: [SO.Data.String],
to: SO.Molecule.Trajectory
})({
apply({ a }) {
return Task.create('Parse SDF', async ctx => {
const parsed = await parseSdf(a.data).runInContext(ctx);
if (parsed.isError) throw new Error(parsed.message);
const models: Model[] = [];
for (const { molFile } of parsed.result.compounds) {
const traj = await trajectoryFromMol(molFile).runInContext(ctx);
for (let i = 0; i < traj.frameCount; i++) {
models.push(await Task.resolveInContext(traj.getFrameAtIndex(i), ctx));
}
}
const traj = new ArrayTrajectory(models);
const props = trajectoryProps(traj);
return new SO.Molecule.Trajectory(traj, props);
});
}
});
type TrajectoryFromMOL2 = typeof TrajectoryFromMOL
const TrajectoryFromMOL2 = PluginStateTransform.BuiltIn({
name: 'trajectory-from-mol2',

View File

@@ -182,7 +182,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, 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, 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);
@@ -241,7 +241,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, 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, 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);

View File

@@ -176,7 +176,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, buffer?.vertex, buffer?.group, buffer?.normal);
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, buffer?.vertex, buffer?.group, buffer?.normal);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);

View File

@@ -11,7 +11,7 @@ import { MolScriptSymbolTable as MolScript } from '../../language/symbol-table';
import { Type } from '../../language/type';
import { Types as StructureQueryTypes } from '../../language/symbol-table/structure-query';
import { MolScriptBuilder as B } from '../../language/builder';
import { getPositionalArgs, tryGetArg } from './macro';
import { getPositionalArgs, tryGetArg } from './script-macro';
export type MolScriptSymbol =
| { kind: 'alias', aliases: string[], symbol: MSymbol }

View File

@@ -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, true);
createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, 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, true);
const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true);
webgl.waitForGpuCommandsCompleteSync();
console.timeEnd('gpu mc vert');
console.timeEnd('gpu mc');