diff --git a/src/extensions/geo-export/controls.ts b/src/extensions/geo-export/controls.ts index 793929702a7ff70d1a83e7bddfbf300ec0f5825b..0fe4c61a3e7fcb879c5502a1c21b9a45dc495d13 100644 --- a/src/extensions/geo-export/controls.ts +++ b/src/extensions/geo-export/controls.ts @@ -5,6 +5,7 @@ */ import { getStyle } from '../../mol-gl/renderer'; +import { Box3D } from '../../mol-math/geometry'; import { PluginComponent } from '../../mol-plugin-state/component'; import { PluginContext } from '../../mol-plugin/context'; import { Task } from '../../mol-task'; @@ -43,17 +44,18 @@ export class GeometryControls extends PluginComponent { const renderObjects = this.plugin.canvas3d?.getRenderObjects()!; const filename = this.getFilename(); - let renderObjectExporter: ObjExporter | GlbExporter | StlExporter; + const boundingBox = Box3D.fromSphere3D(Box3D(), this.plugin.canvas3d?.boundingSphereVisible!); + let renderObjectExporter: GlbExporter | ObjExporter | StlExporter; switch (this.behaviors.params.value.format) { - case 'obj': - renderObjectExporter = new ObjExporter(filename); - break; case 'glb': const style = getStyle(this.plugin.canvas3d?.props.renderer.style!); - renderObjectExporter = new GlbExporter(style); + renderObjectExporter = new GlbExporter(style, boundingBox); + break; + case 'obj': + renderObjectExporter = new ObjExporter(filename, boundingBox); break; case 'stl': - renderObjectExporter = new StlExporter(); + renderObjectExporter = new StlExporter(boundingBox); break; default: throw new Error('Unsupported format.'); } diff --git a/src/extensions/geo-export/glb-exporter.ts b/src/extensions/geo-export/glb-exporter.ts index a2d8944a256744482c3b0d9c274133c455ea67c4..c915a1e4508de82db6dce6be1263079e123b36c1 100644 --- a/src/extensions/geo-export/glb-exporter.ts +++ b/src/extensions/geo-export/glb-exporter.ts @@ -8,6 +8,7 @@ import { BaseValues } from '../../mol-gl/renderable/schema'; import { Style } from '../../mol-gl/renderer'; import { asciiWrite } from '../../mol-io/common/ascii'; import { IsNativeEndianLittle, flipByteOrder } from '../../mol-io/common/binary'; +import { Box3D } from '../../mol-math/geometry'; import { Vec3, Mat4 } from '../../mol-math/linear-algebra'; import { PLUGIN_VERSION } from '../../mol-plugin/version'; import { RuntimeContext } from '../../mol-task'; @@ -41,6 +42,7 @@ export class GlbExporter extends MeshExporter<GlbData> { private bufferViews: Record<string, any>[] = []; private binaryBuffer: ArrayBuffer[] = []; private byteOffset = 0; + private centerTransform: Mat4; private static vec3MinMax(a: NumberArray) { const min: number[] = [Infinity, Infinity, Infinity]; @@ -252,11 +254,12 @@ export class GlbExporter extends MeshExporter<GlbData> { } // node + Mat4.fromArray(t, aTransform, instanceIndex * 16); + Mat4.mul(t, this.centerTransform, t); const node: Record<string, any> = { - mesh: meshIndex! + mesh: meshIndex!, + matrix: t.slice() }; - Mat4.fromArray(t, aTransform, instanceIndex * 16); - if (!Mat4.isIdentity(t)) node.matrix = t.slice(); this.nodes.push(node); } } @@ -334,7 +337,11 @@ export class GlbExporter extends MeshExporter<GlbData> { return new Blob([this.getData().glb], { type: 'model/gltf-binary' }); } - constructor(private style: Style) { + constructor(private style: Style, boundingBox: Box3D) { super(); + const tmpV = Vec3(); + Vec3.add(tmpV, boundingBox.min, boundingBox.max); + Vec3.scale(tmpV, tmpV, -0.5); + this.centerTransform = Mat4.fromTranslation(Mat4(), tmpV); } } \ No newline at end of file diff --git a/src/extensions/geo-export/obj-exporter.ts b/src/extensions/geo-export/obj-exporter.ts index 5e99c0aa05c066cd418b22349933ffa62a2a77cc..6d5d716f859214a8ce67938c92829036b418dbbf 100644 --- a/src/extensions/geo-export/obj-exporter.ts +++ b/src/extensions/geo-export/obj-exporter.ts @@ -6,6 +6,7 @@ import { sort, arraySwap } from '../../mol-data/util'; import { asciiWrite } from '../../mol-io/common/ascii'; +import { Box3D } from '../../mol-math/geometry'; import { Vec3, Mat3, Mat4 } from '../../mol-math/linear-algebra'; import { RuntimeContext } from '../../mol-task'; import { StringBuilder } from '../../mol-util'; @@ -35,6 +36,7 @@ export class ObjExporter extends MeshExporter<ObjData> { private currentColor: Color | undefined; private currentAlpha: number | undefined; private materialSet = new Set<string>(); + private centerTransform: Mat4; private updateMaterial(color: Color, alpha: number) { if (this.currentColor === color && this.currentAlpha === alpha) return; @@ -163,6 +165,7 @@ export class ObjExporter extends MeshExporter<ObjData> { const { vertices, normals, indices, groups, vertexCount, drawCount } = ObjExporter.getInstance(input, instanceIndex); Mat4.fromArray(t, aTransform, instanceIndex * 16); + Mat4.mul(t, this.centerTransform, t); mat3directionTransform(n, t); // position @@ -273,8 +276,12 @@ export class ObjExporter extends MeshExporter<ObjData> { return new Blob([await zip(ctx, zipDataObj)], { type: 'application/zip' }); } - constructor(private filename: string) { + constructor(private filename: string, boundingBox: Box3D) { super(); StringBuilder.writeSafe(this.obj, `mtllib ${filename}.mtl\n`); + const tmpV = Vec3(); + Vec3.add(tmpV, boundingBox.min, boundingBox.max); + Vec3.scale(tmpV, tmpV, -0.5); + this.centerTransform = Mat4.fromTranslation(Mat4(), tmpV); } } \ No newline at end of file diff --git a/src/extensions/geo-export/stl-exporter.ts b/src/extensions/geo-export/stl-exporter.ts index 9a6707bf30821af04d11e70f6fa8842dd217280a..22b00e2a37cae2511da139becdd14400cfab3ce6 100644 --- a/src/extensions/geo-export/stl-exporter.ts +++ b/src/extensions/geo-export/stl-exporter.ts @@ -5,6 +5,7 @@ */ import { asciiWrite } from '../../mol-io/common/ascii'; +import { Box3D } from '../../mol-math/geometry'; import { Vec3, Mat4 } from '../../mol-math/linear-algebra'; import { PLUGIN_VERSION } from '../../mol-plugin/version'; import { RuntimeContext } from '../../mol-task'; @@ -26,6 +27,7 @@ export class StlExporter extends MeshExporter<StlData> { readonly fileExtension = 'stl'; private triangleBuffers: ArrayBuffer[] = []; private triangleCount = 0; + private centerTransform: Mat4; protected async addMeshWithColors(input: AddMeshInput) { const { values, isGeoTexture, ctx } = input; @@ -46,6 +48,7 @@ export class StlExporter extends MeshExporter<StlData> { const { vertices, indices, vertexCount, drawCount } = StlExporter.getInstance(input, instanceIndex); Mat4.fromArray(t, aTransform, instanceIndex * 16); + Mat4.mul(t, this.centerTransform, t); // position const vertexArray = new Float32Array(vertexCount * 3); @@ -105,4 +108,12 @@ export class StlExporter extends MeshExporter<StlData> { async getBlob(ctx: RuntimeContext) { return new Blob([this.getData().stl], { type: 'model/stl' }); } + + constructor(boundingBox: Box3D) { + super(); + const tmpV = Vec3(); + Vec3.add(tmpV, boundingBox.min, boundingBox.max); + Vec3.scale(tmpV, tmpV, -0.5); + this.centerTransform = Mat4.fromTranslation(Mat4(), tmpV); + } } \ No newline at end of file diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 5fc23dd3d76e0c97894d377f51b61cc2401bf1c8..25c262e289d07ac73d68f796f0e3be316ecf2e2a 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -242,6 +242,7 @@ interface Canvas3D { requestCameraReset(options?: { durationMs?: number, snapshot?: Camera.SnapshotProvider }): void readonly camera: Camera readonly boundingSphere: Readonly<Sphere3D> + readonly boundingSphereVisible: Readonly<Sphere3D> setProps(props: PartialCanvas3DProps | ((old: Canvas3DProps) => Partial<Canvas3DProps> | void), doNotRequestDraw?: boolean /* = false */): void getImagePass(props: Partial<ImageProps>): ImagePass getRenderObjects(): GraphicsRenderObject[] @@ -717,6 +718,7 @@ namespace Canvas3D { }, camera, boundingSphere: scene.boundingSphere, + boundingSphereVisible: scene.boundingSphereVisible, get notifyDidDraw() { return notifyDidDraw; }, set notifyDidDraw(v: boolean) { notifyDidDraw = v; }, didDraw,