diff --git a/src/extensions/geo-export/glb-exporter.ts b/src/extensions/geo-export/glb-exporter.ts index 14e79e21648facb831881cc40e905c94453694f0..6b43f028810b0595833a8dd74a5a3b4b70f71545 100644 --- a/src/extensions/geo-export/glb-exporter.ts +++ b/src/extensions/geo-export/glb-exporter.ts @@ -4,42 +4,48 @@ * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> */ +import { BaseValues } from '../../mol-gl/renderable/schema'; import { asciiWrite } from '../../mol-io/common/ascii'; import { IsNativeEndianLittle, flipByteOrder } from '../../mol-io/common/binary'; -import { Vec3, Mat3, Mat4 } from '../../mol-math/linear-algebra'; +import { Vec3, Mat4 } from '../../mol-math/linear-algebra'; +import { PLUGIN_VERSION } from '../../mol-plugin/version'; import { RuntimeContext } from '../../mol-task'; import { Color } from '../../mol-util/color/color'; -import { arrayMinMax, fillSerial } from '../../mol-util/array'; +import { fillSerial } from '../../mol-util/array'; import { NumberArray } from '../../mol-util/type-helpers'; import { MeshExporter, AddMeshInput } from './mesh-exporter'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3fromArray = Vec3.fromArray; -const v3transformMat4 = Vec3.transformMat4; -const v3transformMat3 = Vec3.transformMat3; const v3normalize = Vec3.normalize; const v3toArray = Vec3.toArray; -const mat3directionTransform = Mat3.directionTransform; // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 +const UNSIGNED_BYTE = 5121; +const UNSIGNED_INT = 5125; +const FLOAT = 5126; +const ARRAY_BUFFER = 34962; +const ELEMENT_ARRAY_BUFFER = 34963; + export type GlbData = { glb: Uint8Array } export class GlbExporter extends MeshExporter<GlbData> { readonly fileExtension = 'glb'; - private primitives: Record<string, any>[] = []; + private nodes: Record<string, any>[] = []; + private meshes: Record<string, any>[] = []; private accessors: Record<string, any>[] = []; private bufferViews: Record<string, any>[] = []; private binaryBuffer: ArrayBuffer[] = []; private byteOffset = 0; - private static vecMinMax(a: NumberArray, length: number) { - const min: number[] = (new Array(length)).fill(Infinity); - const max: number[] = (new Array(length)).fill(-Infinity); - for (let i = 0, il = a.length; i < il; i += length) { - for (let j = 0; j < length; ++j) { + private static vec3MinMax(a: NumberArray) { + const min: number[] = [Infinity, Infinity, Infinity]; + const max: number[] = [-Infinity, -Infinity, -Infinity]; + for (let i = 0, il = a.length; i < il; i += 3) { + for (let j = 0; j < 3; ++j) { min[j] = Math.min(a[i + j], min[j]); max[j] = Math.max(a[i + j], max[j]); } @@ -47,234 +53,210 @@ export class GlbExporter extends MeshExporter<GlbData> { return [ min, max ]; } - protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, meshes, values, isGeoTexture, webgl, ctx } = input; + private addBuffer(buffer: ArrayBuffer, componentType: number, type: string, count: number, target: number, min?: any, max?: any, normalized?: boolean) { + this.binaryBuffer.push(buffer); + + const bufferViewOffset = this.bufferViews.length; + this.bufferViews.push({ + buffer: 0, + byteOffset: this.byteOffset, + byteLength: buffer.byteLength, + target + }); + this.byteOffset += buffer.byteLength; + + const accessorOffset = this.accessors.length; + this.accessors.push({ + bufferView: bufferViewOffset, + byteOffset: 0, + componentType, + count, + type, + min, + max, + normalized + }); + return accessorOffset; + } - const t = Mat4(); - const n = Mat3(); + private addGeometryBuffers(vertices: Float32Array, normals: Float32Array, indices: Uint32Array | undefined, vertexCount: number, drawCount: number, isGeoTexture: boolean) { const tmpV = Vec3(); const stride = isGeoTexture ? 4 : 3; + const vertexArray = new Float32Array(vertexCount * 3); + const normalArray = new Float32Array(vertexCount * 3); + let indexArray: Uint32Array | undefined; + + // position + for (let i = 0; i < vertexCount; ++i) { + v3fromArray(tmpV, vertices, i * stride); + v3toArray(tmpV, vertexArray, i * 3); + } + + // normal + for (let i = 0; i < vertexCount; ++i) { + v3fromArray(tmpV, normals, i * stride); + v3normalize(tmpV, tmpV); + v3toArray(tmpV, normalArray, i * 3); + } + + // face + if (!isGeoTexture) { + indexArray = indices!.slice(0, drawCount); + } + + const [ vertexMin, vertexMax ] = GlbExporter.vec3MinMax(vertexArray); + + let vertexBuffer = vertexArray.buffer; + let normalBuffer = normalArray.buffer; + let indexBuffer = isGeoTexture ? undefined : indexArray!.buffer; + if (!IsNativeEndianLittle) { + vertexBuffer = flipByteOrder(new Uint8Array(vertexBuffer), 4); + normalBuffer = flipByteOrder(new Uint8Array(normalBuffer), 4); + if (!isGeoTexture) indexBuffer = flipByteOrder(new Uint8Array(indexBuffer!), 4); + } + + return { + vertexAccessorIndex: this.addBuffer(vertexBuffer, FLOAT, 'VEC3', vertexCount, ARRAY_BUFFER, vertexMin, vertexMax), + normalAccessorIndex: this.addBuffer(normalBuffer, FLOAT, 'VEC3', vertexCount, ARRAY_BUFFER), + indexAccessorIndex: isGeoTexture ? undefined : this.addBuffer(indexBuffer!, UNSIGNED_INT, 'SCALAR', drawCount, ELEMENT_ARRAY_BUFFER) + }; + } + + private addColorBuffer(values: BaseValues, groups: Float32Array | Uint8Array, vertexCount: number, instanceIndex: number, isGeoTexture: boolean, interpolatedColors: Uint8Array) { const groupCount = values.uGroupCount.ref.value; const colorType = values.dColorType.ref.value; + const uColor = values.uColor.ref.value; const tColor = values.tColor.ref.value.array; const uAlpha = values.uAlpha.ref.value; const dTransparency = values.dTransparency.ref.value; const tTransparency = values.tTransparency.ref.value; + + const colorArray = new Uint8Array(vertexCount * 4); + + for (let i = 0; i < vertexCount; ++i) { + let color: Color; + switch (colorType) { + case 'uniform': + color = Color.fromNormalizedArray(uColor, 0); + break; + case 'instance': + color = Color.fromArray(tColor, instanceIndex * 3); + break; + case 'group': { + const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; + color = Color.fromArray(tColor, group * 3); + break; + } + case 'groupInstance': { + const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; + color = Color.fromArray(tColor, (instanceIndex * groupCount + group) * 3); + break; + } + case 'vertex': + color = Color.fromArray(tColor, i * 3); + break; + case 'vertexInstance': + color = Color.fromArray(tColor, (instanceIndex * vertexCount + i) * 3); + break; + case 'volume': + color = Color.fromArray(interpolatedColors!, i * 3); + break; + case 'volumeInstance': + color = Color.fromArray(interpolatedColors!, (instanceIndex * vertexCount + i) * 3); + break; + default: throw new Error('Unsupported color type.'); + } + + let alpha = uAlpha; + if (dTransparency) { + const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; + const transparency = tTransparency.array[instanceIndex * groupCount + group] / 255; + alpha *= 1 - transparency; + } + + color = Color.sRGBToLinear(color); + Color.toArray(color, colorArray, i * 4); + colorArray[i * 4 + 3] = Math.round(alpha * 255); + } + + let colorBuffer = colorArray.buffer; + if (!IsNativeEndianLittle) { + colorBuffer = flipByteOrder(new Uint8Array(colorBuffer), 4); + } + + return this.addBuffer(colorBuffer, UNSIGNED_BYTE, 'VEC4', vertexCount, ARRAY_BUFFER, undefined, undefined, true); + } + + protected async addMeshWithColors(input: AddMeshInput) { + const { mesh, values, isGeoTexture, webgl, ctx } = input; + + const t = Mat4(); + + const colorType = values.dColorType.ref.value; + const dTransparency = values.dTransparency.ref.value; const aTransform = values.aTransform.ref.value; const instanceCount = values.uInstanceCount.ref.value; let interpolatedColors: Uint8Array; if (colorType === 'volume' || colorType === 'volumeInstance') { + const stride = isGeoTexture ? 4 : 3; interpolatedColors = GlbExporter.getInterpolatedColors(mesh!.vertices, mesh!.vertexCount, values, stride, colorType, webgl!); } + // instancing + const sameGeometryBuffers = mesh !== undefined; + const sameColorBuffer = sameGeometryBuffers && colorType !== 'instance' && !colorType.endsWith('Instance') && !dTransparency; + let vertexAccessorIndex: number; + let normalAccessorIndex: number; + let indexAccessorIndex: number | undefined; + let colorAccessorIndex: number; + let meshIndex: number; + await ctx.update({ isIndeterminate: false, current: 0, max: instanceCount }); for (let instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex) { if (ctx.shouldUpdate) await ctx.update({ current: instanceIndex + 1 }); - let vertices: Float32Array; - let normals: Float32Array; - let indices: Uint32Array | undefined; - let groups: Float32Array | Uint8Array; - let vertexCount: number; - let drawCount: number; - if (mesh !== undefined) { - vertices = mesh.vertices; - normals = mesh.normals; - indices = mesh.indices; - groups = mesh.groups; - vertexCount = mesh.vertexCount; - drawCount = mesh.drawCount; - } else { - const mesh = meshes![instanceIndex]; - vertices = mesh.vertexBuffer.ref.value; - normals = mesh.normalBuffer.ref.value; - indices = mesh.indexBuffer.ref.value; - groups = mesh.groupBuffer.ref.value; - vertexCount = mesh.vertexCount; - drawCount = mesh.triangleCount * 3; - } + // create a glTF mesh if needed + if (instanceIndex === 0 || !sameGeometryBuffers || !sameColorBuffer) { + const { vertices, normals, indices, groups, vertexCount, drawCount } = GlbExporter.getInstance(input, instanceIndex); - Mat4.fromArray(t, aTransform, instanceIndex * 16); - mat3directionTransform(n, t); - - const vertexArray = new Float32Array(vertexCount * 3); - const normalArray = new Float32Array(vertexCount * 3); - const colorArray = new Float32Array(vertexCount * 4); - let indexArray: Uint32Array; - - // position - for (let i = 0; i < vertexCount; ++i) { - v3transformMat4(tmpV, v3fromArray(tmpV, vertices, i * stride), t); - v3toArray(tmpV, vertexArray, i * 3); - } - - // normal - for (let i = 0; i < vertexCount; ++i) { - v3fromArray(tmpV, normals, i * stride); - v3transformMat3(tmpV, v3normalize(tmpV, tmpV), n); - v3toArray(tmpV, normalArray, i * 3); - } - - // color - for (let i = 0; i < vertexCount; ++i) { - let color: Color; - switch (colorType) { - case 'uniform': - color = Color.fromNormalizedArray(values.uColor.ref.value, 0); - break; - case 'instance': - color = Color.fromArray(tColor, instanceIndex * 3); - break; - case 'group': { - const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; - color = Color.fromArray(tColor, group * 3); - break; - } - case 'groupInstance': { - const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; - color = Color.fromArray(tColor, (instanceIndex * groupCount + group) * 3); - break; - } - case 'vertex': - color = Color.fromArray(tColor, i * 3); - break; - case 'vertexInstance': - color = Color.fromArray(tColor, (instanceIndex * drawCount + i) * 3); - break; - case 'volume': - color = Color.fromArray(interpolatedColors!, i * 3); - break; - case 'volumeInstance': - color = Color.fromArray(interpolatedColors!, (instanceIndex * vertexCount + i) * 3); - break; - default: throw new Error('Unsupported color type.'); + // create geometry buffers if needed + if (instanceIndex === 0 || !sameGeometryBuffers) { + const accessorIndices = this.addGeometryBuffers(vertices, normals, indices, vertexCount, drawCount, isGeoTexture); + vertexAccessorIndex = accessorIndices.vertexAccessorIndex; + normalAccessorIndex = accessorIndices.normalAccessorIndex; + indexAccessorIndex = accessorIndices.indexAccessorIndex; } - let alpha = uAlpha; - if (dTransparency) { - const group = isGeoTexture ? GlbExporter.getGroup(groups, i) : groups[i]; - const transparency = tTransparency.array[instanceIndex * groupCount + group] / 255; - alpha *= 1 - transparency; + // create a color buffer if needed + if (instanceIndex === 0 || !sameColorBuffer) { + colorAccessorIndex = this.addColorBuffer(values, groups, vertexCount, instanceIndex, isGeoTexture, interpolatedColors!); } - color = Color.sRGBToLinear(color); - Color.toArrayNormalized(color, colorArray, i * 4); - colorArray[i * 4 + 3] = alpha; + // glTF mesh + meshIndex = this.meshes.length; + this.meshes.push({ + primitives: [{ + attributes: { + POSITION: vertexAccessorIndex!, + NORMAL: normalAccessorIndex!, + COLOR_0: colorAccessorIndex! + }, + indices: indexAccessorIndex, + material: 0 + }] + }); } - // face - if (isGeoTexture) { - indexArray = new Uint32Array(drawCount); - fillSerial(indexArray); - } else { - indexArray = indices!.slice(0, drawCount); - } - - const [ vertexMin, vertexMax ] = GlbExporter.vecMinMax(vertexArray, 3); - const [ normalMin, normalMax ] = GlbExporter.vecMinMax(normalArray, 3); - const [ colorMin, colorMax ] = GlbExporter.vecMinMax(colorArray, 4); - const [ indexMin, indexMax ] = arrayMinMax(indexArray); - - // binary buffer - let vertexBuffer = vertexArray.buffer; - let normalBuffer = normalArray.buffer; - let colorBuffer = colorArray.buffer; - let indexBuffer = indexArray.buffer; - if (!IsNativeEndianLittle) { - vertexBuffer = flipByteOrder(new Uint8Array(vertexBuffer), 4); - normalBuffer = flipByteOrder(new Uint8Array(normalBuffer), 4); - colorBuffer = flipByteOrder(new Uint8Array(colorBuffer), 4); - indexBuffer = flipByteOrder(new Uint8Array(indexBuffer), 4); - } - this.binaryBuffer.push(vertexBuffer, normalBuffer, colorBuffer, indexBuffer); - - // buffer views - const bufferViewOffset = this.bufferViews.length; - - this.bufferViews.push({ - buffer: 0, - byteOffset: this.byteOffset, - byteLength: vertexBuffer.byteLength, - target: 34962 // ARRAY_BUFFER - }); - this.byteOffset += vertexBuffer.byteLength; - - this.bufferViews.push({ - buffer: 0, - byteOffset: this.byteOffset, - byteLength: normalBuffer.byteLength, - target: 34962 // ARRAY_BUFFER - }); - this.byteOffset += normalBuffer.byteLength; - - this.bufferViews.push({ - buffer: 0, - byteOffset: this.byteOffset, - byteLength: colorBuffer.byteLength, - target: 34962 // ARRAY_BUFFER - }); - this.byteOffset += colorBuffer.byteLength; - - this.bufferViews.push({ - buffer: 0, - byteOffset: this.byteOffset, - byteLength: indexBuffer.byteLength, - target: 34963 // ELEMENT_ARRAY_BUFFER - }); - this.byteOffset += indexBuffer.byteLength; - - // accessors - const accessorOffset = this.accessors.length; - this.accessors.push({ - bufferView: bufferViewOffset, - byteOffset: 0, - componentType: 5126, // FLOAT - count: vertexCount, - type: 'VEC3', - max: vertexMax, - min: vertexMin - }); - this.accessors.push({ - bufferView: bufferViewOffset + 1, - byteOffset: 0, - componentType: 5126, // FLOAT - count: vertexCount, - type: 'VEC3', - max: normalMax, - min: normalMin - }); - this.accessors.push({ - bufferView: bufferViewOffset + 2, - byteOffset: 0, - componentType: 5126, // FLOAT - count: vertexCount, - type: 'VEC4', - max: colorMax, - min: colorMin - }); - this.accessors.push({ - bufferView: bufferViewOffset + 3, - byteOffset: 0, - componentType: 5125, // UNSIGNED_INT - count: drawCount, - type: 'SCALAR', - max: [ indexMax ], - min: [ indexMin ] - }); - - // primitive - this.primitives.push({ - attributes: { - POSITION: accessorOffset, - NORMAL: accessorOffset + 1, - COLOR_0: accessorOffset + 2, - }, - indices: accessorOffset + 3, - material: 0 - }); + // node + const node: Record<string, any> = { + mesh: meshIndex! + }; + Mat4.fromArray(t, aTransform, instanceIndex * 16); + if (!Mat4.isIdentity(t)) node.matrix = t.slice(); + this.nodes.push(node); } } @@ -283,17 +265,14 @@ export class GlbExporter extends MeshExporter<GlbData> { const gltf = { asset: { - version: '2.0' + version: '2.0', + generator: `Mol* ${PLUGIN_VERSION}` }, scenes: [{ - nodes: [ 0 ] - }], - nodes: [{ - mesh: 0 - }], - meshes: [{ - primitives: this.primitives + nodes: fillSerial(new Array(this.nodes.length) as number[]) }], + nodes: this.nodes, + meshes: this.meshes, buffers: [{ byteLength: binaryBufferLength, }], diff --git a/src/extensions/geo-export/mesh-exporter.ts b/src/extensions/geo-export/mesh-exporter.ts index af8fba7ae1b34a7a69038a1fd95e51de9885f99f..09b1f731cb00b2d27a6f7ebcf8e0391b515bacfb 100644 --- a/src/extensions/geo-export/mesh-exporter.ts +++ b/src/extensions/geo-export/mesh-exporter.ts @@ -100,7 +100,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements } const framebuffer = webgl.namedFramebuffers[GeoExportName]; - const [ width, height ] = values.uColorTexDim.ref.value; + const [ width, height ] = colorTexDim; const colorGrid = new Uint8Array(width * height * 4); framebuffer.bind(); @@ -111,7 +111,24 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements return interpolated.array; } - protected abstract addMeshWithColors(inpit: AddMeshInput): void; + protected static getInstance(input: AddMeshInput, instanceIndex: number) { + const { mesh, meshes } = input; + if (mesh !== undefined) { + return mesh; + } else { + const mesh = meshes![instanceIndex]; + return { + vertices: mesh.vertexBuffer.ref.value, + normals: mesh.normalBuffer.ref.value, + indices: mesh.indexBuffer.ref.value, + groups: mesh.groupBuffer.ref.value, + vertexCount: mesh.vertexCount, + drawCount: mesh.triangleCount * 3 + }; + } + } + + protected abstract addMeshWithColors(input: AddMeshInput): void; private async addMesh(values: MeshValues, webgl: WebGLContext, ctx: RuntimeContext) { const aPosition = values.aPosition.ref.value; diff --git a/src/extensions/geo-export/obj-exporter.ts b/src/extensions/geo-export/obj-exporter.ts index 570294a31554fab8420e714790dcb66a3fb4e9f1..5e99c0aa05c066cd418b22349933ffa62a2a77cc 100644 --- a/src/extensions/geo-export/obj-exporter.ts +++ b/src/extensions/geo-export/obj-exporter.ts @@ -132,7 +132,7 @@ export class ObjExporter extends MeshExporter<ObjData> { } protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, meshes, values, isGeoTexture, webgl, ctx } = input; + const { mesh, values, isGeoTexture, webgl, ctx } = input; const obj = this.obj; const t = Mat4(); @@ -160,28 +160,7 @@ export class ObjExporter extends MeshExporter<ObjData> { for (let instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex) { if (ctx.shouldUpdate) await ctx.update({ current: instanceIndex + 1 }); - let vertices: Float32Array; - let normals: Float32Array; - let indices: Uint32Array | undefined; - let groups: Float32Array | Uint8Array; - let vertexCount: number; - let drawCount: number; - if (mesh !== undefined) { - vertices = mesh.vertices; - normals = mesh.normals; - indices = mesh.indices; - groups = mesh.groups; - vertexCount = mesh.vertexCount; - drawCount = mesh.drawCount; - } else { - const mesh = meshes![instanceIndex]; - vertices = mesh.vertexBuffer.ref.value; - normals = mesh.normalBuffer.ref.value; - indices = mesh.indexBuffer.ref.value; - groups = mesh.groupBuffer.ref.value; - vertexCount = mesh.vertexCount; - drawCount = mesh.triangleCount * 3; - } + const { vertices, normals, indices, groups, vertexCount, drawCount } = ObjExporter.getInstance(input, instanceIndex); Mat4.fromArray(t, aTransform, instanceIndex * 16); mat3directionTransform(n, t); @@ -234,7 +213,7 @@ export class ObjExporter extends MeshExporter<ObjData> { color = Color.fromArray(tColor, indices![i] * 3); break; case 'vertexInstance': - color = Color.fromArray(tColor, (instanceIndex * drawCount + indices![i]) * 3); + color = Color.fromArray(tColor, (instanceIndex * vertexCount + indices![i]) * 3); break; case 'volume': color = Color.fromArray(interpolatedColors!, (isGeoTexture ? i : indices![i]) * 3); diff --git a/src/extensions/geo-export/stl-exporter.ts b/src/extensions/geo-export/stl-exporter.ts index 75e0cdf4da8d03f9a914b52e61ece6da8e677c6c..9a6707bf30821af04d11e70f6fa8842dd217280a 100644 --- a/src/extensions/geo-export/stl-exporter.ts +++ b/src/extensions/geo-export/stl-exporter.ts @@ -28,7 +28,7 @@ export class StlExporter extends MeshExporter<StlData> { private triangleCount = 0; protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, meshes, values, isGeoTexture, ctx } = input; + const { values, isGeoTexture, ctx } = input; const t = Mat4(); const tmpV = Vec3(); @@ -37,29 +37,14 @@ export class StlExporter extends MeshExporter<StlData> { const v3 = Vec3(); const stride = isGeoTexture ? 4 : 3; + const aTransform = values.aTransform.ref.value; const instanceCount = values.uInstanceCount.ref.value; for (let instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex) { if (ctx.shouldUpdate) await ctx.update({ current: instanceIndex + 1 }); - let vertices: Float32Array; - let indices: Uint32Array | undefined; - let vertexCount: number; - let drawCount: number; - if (mesh !== undefined) { - vertices = mesh.vertices; - indices = mesh.indices; - vertexCount = mesh.vertexCount; - drawCount = mesh.drawCount; - } else { - const mesh = meshes![instanceIndex]; - vertices = mesh.vertexBuffer.ref.value; - indices = mesh.indexBuffer.ref.value; - vertexCount = mesh.vertexCount; - drawCount = mesh.triangleCount * 3; - } + const { vertices, indices, vertexCount, drawCount } = StlExporter.getInstance(input, instanceIndex); - const aTransform = values.aTransform.ref.value; Mat4.fromArray(t, aTransform, instanceIndex * 16); // position diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index 11428426c5a278523498347b330e831ba1f48129..cb8d3f14dff65740313cec2e6aa5dad343b4b84b 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -96,7 +96,7 @@ async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structu (surface.meta as GaussianSurfaceMeta) = { resolution }; Mesh.transform(surface, transform); - if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface); + if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface, false); const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getUnitExtraRadius(unit)); surface.setBoundingSphere(sphere); @@ -157,7 +157,7 @@ async function createStructureGaussianSurfaceMesh(ctx: VisualContext, structure: (surface.meta as GaussianSurfaceMeta) = { resolution }; Mesh.transform(surface, transform); - if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface); + if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface, false); const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure)); surface.setBoundingSphere(sphere); diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts index 4711a0821be5782fafa80d0eeb85fb1a9e8927e6..76f8c0d10a5be3cb612249dc179cd89b55545d69 100644 --- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts +++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts @@ -48,7 +48,7 @@ async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, struct const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime); Mesh.transform(surface, transform); - if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface); + if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface, false); const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.probeRadius + getUnitExtraRadius(unit)); surface.setBoundingSphere(sphere);