From 430348a3cd59c286bd36ccdd657633ea043eff11 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Wed, 3 May 2023 10:23:40 -0700 Subject: [PATCH] support points & lines in glTF export (#810) --- CHANGELOG.md | 1 + src/extensions/geo-export/glb-exporter.ts | 63 ++++++++++++--------- src/extensions/geo-export/mesh-exporter.ts | 65 ++++++++++++++++++---- src/extensions/geo-export/obj-exporter.ts | 21 +++---- src/extensions/geo-export/stl-exporter.ts | 5 +- src/extensions/geo-export/usdz-exporter.ts | 21 +++---- 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 846fc40c2..cc24e7253 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] - Add a uniform color theme for NtC tube that still paints residue and segment dividers in a different color +- Support points & lines in glTF export - Fix bond assignments `struct_conn` records referencing waters - Add StructConn extension providing functions for inspecting struct_conns - Fix `PluginState.setSnapshot` triggering unnecessary state updates diff --git a/src/extensions/geo-export/glb-exporter.ts b/src/extensions/geo-export/glb-exporter.ts index 38734833e..6e3c69fe8 100644 --- a/src/extensions/geo-export/glb-exporter.ts +++ b/src/extensions/geo-export/glb-exporter.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -13,7 +13,7 @@ import { PLUGIN_VERSION } from '../../mol-plugin/version'; import { RuntimeContext } from '../../mol-task'; import { Color } from '../../mol-util/color/color'; import { fillSerial } from '../../mol-util/array'; -import { NumberArray } from '../../mol-util/type-helpers'; +import { NumberArray, assertUnreachable } from '../../mol-util/type-helpers'; import { MeshExporter, AddMeshInput, MeshGeoData } from './mesh-exporter'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) @@ -35,6 +35,15 @@ const BIN_CHUNK_TYPE = 0x004E4942; const JSON_PAD_CHAR = 0x20; const BIN_PAD_CHAR = 0x00; +function getPrimitiveMode(mode: 'points' | 'lines' | 'triangles'): number { + switch (mode) { + case 'points': return 0; + case 'lines': return 1; + case 'triangles': return 4; + default: assertUnreachable(mode); + } +} + export type GlbData = { glb: Uint8Array } @@ -89,12 +98,12 @@ export class GlbExporter extends MeshExporter<GlbData> { return accessorOffset; } - private addGeometryBuffers(vertices: Float32Array, normals: Float32Array, indices: Uint32Array | undefined, vertexCount: number, drawCount: number, isGeoTexture: boolean) { + private addGeometryBuffers(vertices: Float32Array, normals: Float32Array | undefined, 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 normalArray: Float32Array | undefined; let indexArray: Uint32Array | undefined; // position @@ -104,32 +113,35 @@ export class GlbExporter extends MeshExporter<GlbData> { } // normal - for (let i = 0; i < vertexCount; ++i) { - v3fromArray(tmpV, normals, i * stride); - v3normalize(tmpV, tmpV); - v3toArray(tmpV, normalArray, i * 3); + if (normals) { + normalArray = new Float32Array(vertexCount * 3); + 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); + if (!isGeoTexture && indices) { + 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; + let normalBuffer = normalArray?.buffer; + let indexBuffer = (isGeoTexture || !indexArray) ? undefined : indexArray.buffer; if (!IsNativeEndianLittle) { vertexBuffer = flipByteOrder(new Uint8Array(vertexBuffer), 4); - normalBuffer = flipByteOrder(new Uint8Array(normalBuffer), 4); + if (normalBuffer) 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) + normalAccessorIndex: normalBuffer ? this.addBuffer(normalBuffer, FLOAT, 'VEC3', vertexCount, ARRAY_BUFFER) : undefined, + indexAccessorIndex: (isGeoTexture || !indexBuffer) ? undefined : this.addBuffer(indexBuffer, UNSIGNED_INT, 'SCALAR', drawCount, ELEMENT_ARRAY_BUFFER) }; } @@ -174,7 +186,7 @@ export class GlbExporter extends MeshExporter<GlbData> { } protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, values, isGeoTexture, webgl, ctx } = input; + const { mesh, values, isGeoTexture, mode, webgl, ctx } = input; const t = Mat4(); @@ -190,28 +202,28 @@ export class GlbExporter extends MeshExporter<GlbData> { const material = this.addMaterial(metalness, roughness); let interpolatedColors: Uint8Array | undefined; - if (colorType === 'volume' || colorType === 'volumeInstance') { + if (webgl && mesh && (colorType === 'volume' || colorType === 'volumeInstance')) { const stride = isGeoTexture ? 4 : 3; - interpolatedColors = GlbExporter.getInterpolatedColors(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType }); + interpolatedColors = GlbExporter.getInterpolatedColors(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType }); } let interpolatedOverpaint: Uint8Array | undefined; - if (overpaintType === 'volumeInstance') { + if (webgl && mesh && overpaintType === 'volumeInstance') { const stride = isGeoTexture ? 4 : 3; - interpolatedOverpaint = GlbExporter.getInterpolatedOverpaint(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: overpaintType }); + interpolatedOverpaint = GlbExporter.getInterpolatedOverpaint(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: overpaintType }); } let interpolatedTransparency: Uint8Array | undefined; - if (transparencyType === 'volumeInstance') { + if (webgl && mesh && transparencyType === 'volumeInstance') { const stride = isGeoTexture ? 4 : 3; - interpolatedTransparency = GlbExporter.getInterpolatedTransparency(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: transparencyType }); + interpolatedTransparency = GlbExporter.getInterpolatedTransparency(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: transparencyType }); } // instancing const sameGeometryBuffers = mesh !== undefined; const sameColorBuffer = sameGeometryBuffers && colorType !== 'instance' && !colorType.endsWith('Instance') && !dTransparency; let vertexAccessorIndex: number; - let normalAccessorIndex: number; + let normalAccessorIndex: number | undefined; let indexAccessorIndex: number | undefined; let colorAccessorIndex: number; let meshIndex: number; @@ -235,7 +247,7 @@ export class GlbExporter extends MeshExporter<GlbData> { // create a color buffer if needed if (instanceIndex === 0 || !sameColorBuffer) { - colorAccessorIndex = this.addColorBuffer({ values, groups, vertexCount, instanceIndex, isGeoTexture }, interpolatedColors, interpolatedOverpaint, interpolatedTransparency); + colorAccessorIndex = this.addColorBuffer({ values, groups, vertexCount, instanceIndex, isGeoTexture, mode }, interpolatedColors, interpolatedOverpaint, interpolatedTransparency); } // glTF mesh @@ -248,7 +260,8 @@ export class GlbExporter extends MeshExporter<GlbData> { COLOR_0: colorAccessorIndex! }, indices: indexAccessorIndex, - material + material, + mode: getPrimitiveMode(mode), }] }); } diff --git a/src/extensions/geo-export/mesh-exporter.ts b/src/extensions/geo-export/mesh-exporter.ts index 2bcd32ffa..9e6a95c8b 100644 --- a/src/extensions/geo-export/mesh-exporter.ts +++ b/src/extensions/geo-export/mesh-exporter.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -34,10 +34,12 @@ const GeoExportName = 'geo-export'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3fromArray = Vec3.fromArray; +type MeshMode = 'points' | 'lines' | 'triangles' + export interface AddMeshInput { mesh: { vertices: Float32Array - normals: Float32Array + normals: Float32Array | undefined indices: Uint32Array | undefined groups: Float32Array | Uint8Array vertexCount: number @@ -46,6 +48,7 @@ export interface AddMeshInput { meshes: Mesh[] | undefined values: BaseValues isGeoTexture: boolean + mode: MeshMode webgl: WebGLContext | undefined ctx: RuntimeContext } @@ -55,7 +58,8 @@ export type MeshGeoData = { groups: Float32Array | Uint8Array, vertexCount: number, instanceIndex: number, - isGeoTexture: boolean + isGeoTexture: boolean, + mode: MeshMode } export abstract class MeshExporter<D extends RenderObjectExportData> implements RenderObjectExporter<D> { @@ -222,7 +226,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements } protected static getColor(vertexIndex: number, geoData: MeshGeoData, interpolatedColors?: Uint8Array, interpolatedOverpaint?: Uint8Array): Color { - const { values, instanceIndex, isGeoTexture, groups, vertexCount } = geoData; + const { values, instanceIndex, isGeoTexture, mode, groups } = geoData; const groupCount = values.uGroupCount.ref.value; const colorType = values.dColorType.ref.value; const uColor = values.uColor.ref.value; @@ -231,6 +235,12 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements const dOverpaint = values.dOverpaint.ref.value; const tOverpaint = values.tOverpaint.ref.value.array; + let vertexCount = geoData.vertexCount; + if (mode === 'lines') { + vertexIndex *= 2; + vertexCount *= 2; + } + let color: Color; switch (colorType) { case 'uniform': @@ -298,12 +308,18 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements } protected static getTransparency(vertexIndex: number, geoData: MeshGeoData, interpolatedTransparency?: Uint8Array): number { - const { values, instanceIndex, isGeoTexture, groups, vertexCount } = geoData; + const { values, instanceIndex, isGeoTexture, mode, groups } = geoData; const groupCount = values.uGroupCount.ref.value; const dTransparency = values.dTransparency.ref.value; const tTransparency = values.tTransparency.ref.value.array; const transparencyType = values.dTransparencyType.ref.value; + let vertexCount = geoData.vertexCount; + if (mode === 'lines') { + vertexIndex *= 2; + vertexCount *= 2; + } + let transparency: number = 0; if (dTransparency) { switch (transparencyType) { @@ -329,7 +345,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements return transparency; } - protected abstract addMeshWithColors(input: AddMeshInput): void; + protected abstract addMeshWithColors(input: AddMeshInput): Promise<void>; private async addMesh(values: MeshValues, webgl: WebGLContext, ctx: RuntimeContext) { const aPosition = values.aPosition.ref.value; @@ -349,15 +365,38 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements drawCount = values.drawCount.ref.value; } - await this.addMeshWithColors({ mesh: { vertices: aPosition, normals: aNormal, indices, groups: aGroup, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: false, webgl, ctx }); + await this.addMeshWithColors({ mesh: { vertices: aPosition, normals: aNormal, indices, groups: aGroup, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: false, mode: 'triangles', webgl, ctx }); } private async addLines(values: LinesValues, webgl: WebGLContext, ctx: RuntimeContext) { - // TODO + const aStart = values.aStart.ref.value; + const aEnd = values.aEnd.ref.value; + const aGroup = values.aGroup.ref.value; + const vertexCount = (values.uVertexCount.ref.value / 4) * 2; + const drawCount = values.drawCount.ref.value / (2 * 3); + + const n = (vertexCount / 2); + const vertices = new Float32Array(n * 2 * 3); + for (let i = 0; i < n; ++i) { + vertices[i * 6] = aStart[i * 4 * 3]; + vertices[i * 6 + 1] = aStart[i * 4 * 3 + 1]; + vertices[i * 6 + 2] = aStart[i * 4 * 3 + 2]; + + vertices[i * 6 + 3] = aEnd[i * 4 * 3]; + vertices[i * 6 + 4] = aEnd[i * 4 * 3 + 1]; + vertices[i * 6 + 5] = aEnd[i * 4 * 3 + 2]; + } + + await this.addMeshWithColors({ mesh: { vertices, normals: undefined, indices: undefined, groups: aGroup, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: false, mode: 'lines', webgl, ctx }); } private async addPoints(values: PointsValues, webgl: WebGLContext, ctx: RuntimeContext) { - // TODO + const aPosition = values.aPosition.ref.value; + const aGroup = values.aGroup.ref.value; + const vertexCount = values.uVertexCount.ref.value; + const drawCount = values.drawCount.ref.value; + + await this.addMeshWithColors({ mesh: { vertices: aPosition, normals: undefined, indices: undefined, groups: aGroup, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: false, mode: 'points', webgl, ctx }); } private async addSpheres(values: SpheresValues, webgl: WebGLContext, ctx: RuntimeContext) { @@ -390,7 +429,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements meshes.push(MeshBuilder.getMesh(state)); } - await this.addMeshWithColors({ mesh: undefined, meshes, values, isGeoTexture: false, webgl, ctx }); + await this.addMeshWithColors({ mesh: undefined, meshes, values, isGeoTexture: false, mode: 'triangles', webgl, ctx }); } private async addCylinders(values: CylindersValues, webgl: WebGLContext, ctx: RuntimeContext) { @@ -432,7 +471,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements meshes.push(MeshBuilder.getMesh(state)); } - await this.addMeshWithColors({ mesh: undefined, meshes, values, isGeoTexture: false, webgl, ctx }); + await this.addMeshWithColors({ mesh: undefined, meshes, values, isGeoTexture: false, mode: 'triangles', webgl, ctx }); } private async addTextureMesh(values: TextureMeshValues, webgl: WebGLContext, ctx: RuntimeContext) { @@ -457,11 +496,13 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements const vertexCount = values.uVertexCount.ref.value; const drawCount = values.drawCount.ref.value; - await this.addMeshWithColors({ mesh: { vertices, normals, indices: undefined, groups, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: true, webgl, ctx }); + await this.addMeshWithColors({ mesh: { vertices, normals, indices: undefined, groups, vertexCount, drawCount }, meshes: undefined, values, isGeoTexture: true, mode: 'triangles', webgl, ctx }); } add(renderObject: GraphicsRenderObject, webgl: WebGLContext, ctx: RuntimeContext) { if (!renderObject.state.visible) return; + if (renderObject.values.drawCount.ref.value === 0) return; + if (renderObject.values.instanceCount.ref.value === 0) return; switch (renderObject.type) { case 'mesh': diff --git a/src/extensions/geo-export/obj-exporter.ts b/src/extensions/geo-export/obj-exporter.ts index 63f13a252..7d829192f 100644 --- a/src/extensions/geo-export/obj-exporter.ts +++ b/src/extensions/geo-export/obj-exporter.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -70,7 +70,8 @@ export class ObjExporter extends MeshExporter<ObjData> { } protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, values, isGeoTexture, webgl, ctx } = input; + const { mesh, values, isGeoTexture, mode, webgl, ctx } = input; + if (mode !== 'triangles') return; const obj = this.obj; const t = Mat4(); @@ -86,19 +87,19 @@ export class ObjExporter extends MeshExporter<ObjData> { const instanceCount = values.uInstanceCount.ref.value; let interpolatedColors: Uint8Array | undefined; - if (colorType === 'volume' || colorType === 'volumeInstance') { - interpolatedColors = ObjExporter.getInterpolatedColors(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType }); + if (webgl && mesh && (colorType === 'volume' || colorType === 'volumeInstance')) { + interpolatedColors = ObjExporter.getInterpolatedColors(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType }); } let interpolatedOverpaint: Uint8Array | undefined; - if (overpaintType === 'volumeInstance') { - interpolatedOverpaint = ObjExporter.getInterpolatedOverpaint(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: overpaintType }); + if (webgl && mesh && overpaintType === 'volumeInstance') { + interpolatedOverpaint = ObjExporter.getInterpolatedOverpaint(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: overpaintType }); } let interpolatedTransparency: Uint8Array | undefined; - if (transparencyType === 'volumeInstance') { + if (webgl && mesh && transparencyType === 'volumeInstance') { const stride = isGeoTexture ? 4 : 3; - interpolatedTransparency = ObjExporter.getInterpolatedTransparency(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: transparencyType }); + interpolatedTransparency = ObjExporter.getInterpolatedTransparency(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: transparencyType }); } await ctx.update({ isIndeterminate: false, current: 0, max: instanceCount }); @@ -126,7 +127,7 @@ export class ObjExporter extends MeshExporter<ObjData> { // normal for (let i = 0; i < vertexCount; ++i) { - v3transformMat3(tmpV, v3fromArray(tmpV, normals, i * stride), n); + v3transformMat3(tmpV, v3fromArray(tmpV, normals!, i * stride), n); StringBuilder.writeSafe(obj, 'vn '); StringBuilder.writeFloat(obj, tmpV[0], 100); StringBuilder.whitespace1(obj); @@ -136,7 +137,7 @@ export class ObjExporter extends MeshExporter<ObjData> { StringBuilder.newline(obj); } - const geoData = { values, groups, vertexCount, instanceIndex, isGeoTexture }; + const geoData = { values, groups, vertexCount, instanceIndex, isGeoTexture, mode }; // color const quantizedColors = new Uint8Array(drawCount * 3); diff --git a/src/extensions/geo-export/stl-exporter.ts b/src/extensions/geo-export/stl-exporter.ts index 35812cbe4..82b325f62 100644 --- a/src/extensions/geo-export/stl-exporter.ts +++ b/src/extensions/geo-export/stl-exporter.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> */ @@ -30,7 +30,8 @@ export class StlExporter extends MeshExporter<StlData> { private centerTransform: Mat4; protected async addMeshWithColors(input: AddMeshInput) { - const { values, isGeoTexture, ctx } = input; + const { values, isGeoTexture, mode, ctx } = input; + if (mode !== 'triangles') return; const t = Mat4(); const tmpV = Vec3(); diff --git a/src/extensions/geo-export/usdz-exporter.ts b/src/extensions/geo-export/usdz-exporter.ts index 7ff3935f4..7f6184288 100644 --- a/src/extensions/geo-export/usdz-exporter.ts +++ b/src/extensions/geo-export/usdz-exporter.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -61,7 +61,8 @@ def Material "material${materialKey}" } protected async addMeshWithColors(input: AddMeshInput) { - const { mesh, values, isGeoTexture, webgl, ctx } = input; + const { mesh, values, isGeoTexture, mode, webgl, ctx } = input; + if (mode !== 'triangles') return; const t = Mat4(); const n = Mat3(); @@ -78,20 +79,20 @@ def Material "material${materialKey}" const roughness = values.uRoughness.ref.value; let interpolatedColors: Uint8Array | undefined; - if (colorType === 'volume' || colorType === 'volumeInstance') { - interpolatedColors = UsdzExporter.getInterpolatedColors(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType }); + if (webgl && mesh && (colorType === 'volume' || colorType === 'volumeInstance')) { + interpolatedColors = UsdzExporter.getInterpolatedColors(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType }); } let interpolatedOverpaint: Uint8Array | undefined; - if (overpaintType === 'volumeInstance') { + if (webgl && mesh && overpaintType === 'volumeInstance') { const stride = isGeoTexture ? 4 : 3; - interpolatedOverpaint = UsdzExporter.getInterpolatedOverpaint(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: overpaintType }); + interpolatedOverpaint = UsdzExporter.getInterpolatedOverpaint(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: overpaintType }); } let interpolatedTransparency: Uint8Array | undefined; - if (transparencyType === 'volumeInstance') { + if (webgl && mesh && transparencyType === 'volumeInstance') { const stride = isGeoTexture ? 4 : 3; - interpolatedTransparency = UsdzExporter.getInterpolatedTransparency(webgl!, { vertices: mesh!.vertices, vertexCount: mesh!.vertexCount, values, stride, colorType: transparencyType }); + interpolatedTransparency = UsdzExporter.getInterpolatedTransparency(webgl, { vertices: mesh.vertices, vertexCount: mesh.vertexCount, values, stride, colorType: transparencyType }); } await ctx.update({ isIndeterminate: false, current: 0, max: instanceCount }); @@ -123,7 +124,7 @@ def Material "material${materialKey}" // normal for (let i = 0; i < vertexCount; ++i) { - v3transformMat3(tmpV, v3fromArray(tmpV, normals, i * stride), n); + v3transformMat3(tmpV, v3fromArray(tmpV, normals!, i * stride), n); StringBuilder.writeSafe(normalBuilder, (i === 0) ? '(' : ',('); StringBuilder.writeFloat(normalBuilder, tmpV[0], 100); StringBuilder.writeSafe(normalBuilder, ','); @@ -133,7 +134,7 @@ def Material "material${materialKey}" StringBuilder.writeSafe(normalBuilder, ')'); } - const geoData = { values, groups, vertexCount, instanceIndex, isGeoTexture }; + const geoData = { values, groups, vertexCount, instanceIndex, isGeoTexture, mode }; // face for (let i = 0; i < drawCount; ++i) { -- GitLab