diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts index 413496347d19a00df562ea3642d1287c0412c34f..917eb5a21ed372932abb5f485dc66aec433ea573 100644 --- a/src/mol-geo/geometry/direct-volume/direct-volume.ts +++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts @@ -18,7 +18,7 @@ import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; import { GeometryUtils } from '../geometry'; import { transformPositionArray } from '../../../mol-geo/util'; -import { calculateBoundingSphere } from '../../../mol-gl/renderable/util'; +import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { Theme } from '../../../mol-theme/theme'; import { RenderableState } from '../../../mol-gl/renderable'; import { ColorListOptions, ColorListName } from '../../../mol-util/color/lists'; @@ -26,12 +26,14 @@ import { Color } from '../../../mol-util/color'; import { BaseGeometry } from '../base'; import { createEmptyOverpaint } from '../overpaint-data'; import { createEmptyTransparency } from '../transparency-data'; +import { hashFnv32a } from '../../../mol-data/util'; const VolumeBox = Box() const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][] export interface DirectVolume { readonly kind: 'direct-volume', + readonly gridTexture: ValueCell<Texture>, readonly gridTextureDim: ValueCell<Vec3>, readonly gridDimension: ValueCell<Vec3>, @@ -41,34 +43,66 @@ export interface DirectVolume { readonly transform: ValueCell<Mat4> /** Bounding sphere of the volume */ - boundingSphere?: Sphere3D + boundingSphere: Sphere3D } export namespace DirectVolume { export function create(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture, directVolume?: DirectVolume): DirectVolume { + return directVolume ? + update(bbox, gridDimension, transform, texture, directVolume) : + fromData(bbox, gridDimension, transform, texture) + } + + function hashCode(directVolume: DirectVolume) { + return hashFnv32a([ + directVolume.bboxSize.ref.version, directVolume.gridDimension.ref.version, + directVolume.gridTexture.ref.version, directVolume.transform.ref.version, + ]) + } + + function fromData(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture): DirectVolume { + const boundingSphere = Sphere3D() + let currentHash = -1 + const width = texture.getWidth() const height = texture.getHeight() const depth = texture.getDepth() - if (directVolume) { - ValueCell.update(directVolume.gridDimension, gridDimension) - ValueCell.update(directVolume.gridTextureDim, Vec3.set(directVolume.gridTextureDim.ref.value, width, height, depth)) - ValueCell.update(directVolume.bboxMin, bbox.min) - ValueCell.update(directVolume.bboxMax, bbox.max) - ValueCell.update(directVolume.bboxSize, Vec3.sub(directVolume.bboxSize.ref.value, bbox.max, bbox.min)) - ValueCell.update(directVolume.transform, transform) - return directVolume - } else { - return { - kind: 'direct-volume', - gridDimension: ValueCell.create(gridDimension), - gridTexture: ValueCell.create(texture), - gridTextureDim: ValueCell.create(Vec3.create(width, height, depth)), - bboxMin: ValueCell.create(bbox.min), - bboxMax: ValueCell.create(bbox.max), - bboxSize: ValueCell.create(Vec3.sub(Vec3.zero(), bbox.max, bbox.min)), - transform: ValueCell.create(transform), - } + + const directVolume = { + kind: 'direct-volume' as const, + gridDimension: ValueCell.create(gridDimension), + gridTexture: ValueCell.create(texture), + gridTextureDim: ValueCell.create(Vec3.create(width, height, depth)), + bboxMin: ValueCell.create(bbox.min), + bboxMax: ValueCell.create(bbox.max), + bboxSize: ValueCell.create(Vec3.sub(Vec3.zero(), bbox.max, bbox.min)), + transform: ValueCell.create(transform), + get boundingSphere() { + const newHash = hashCode(directVolume) + if (newHash !== currentHash) { + const b = getBoundingSphere(directVolume.gridDimension.ref.value, directVolume.transform.ref.value) + Sphere3D.copy(boundingSphere, b) + currentHash = newHash + } + return boundingSphere + }, } + return directVolume + } + + function update(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture, directVolume: DirectVolume): DirectVolume { + const width = texture.getWidth() + const height = texture.getHeight() + const depth = texture.getDepth() + + ValueCell.update(directVolume.gridDimension, gridDimension) + ValueCell.update(directVolume.gridTexture, texture) + ValueCell.update(directVolume.gridTextureDim, Vec3.set(directVolume.gridTextureDim.ref.value, width, height, depth)) + ValueCell.update(directVolume.bboxMin, bbox.min) + ValueCell.update(directVolume.bboxMax, bbox.max) + ValueCell.update(directVolume.bboxSize, Vec3.sub(directVolume.bboxSize.ref.value, bbox.max, bbox.min)) + ValueCell.update(directVolume.transform, transform) + return directVolume } export function createEmpty(directVolume?: DirectVolume): DirectVolume { @@ -110,7 +144,8 @@ export namespace DirectVolume { const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount } - const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(gridDimension.ref.value, gridTransform.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value) + const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) const controlPoints = getControlPointsFromVec2Array(props.controlPoints) const transferTex = createTransferFunctionTexture(controlPoints, props.list) @@ -162,7 +197,9 @@ export namespace DirectVolume { } function updateBoundingSphere(values: DirectVolumeValues, directVolume: DirectVolume) { - const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(values.uGridDim.ref.value, values.uTransform.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value) + const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } @@ -189,11 +226,12 @@ const mTmp = Mat4.identity() const mTmp2 = Mat4.identity() const vHalfUnit = Vec3.create(0.5, 0.5, 0.5) const tmpVertices = new Float32Array(VolumeBox.vertices.length) -function getBoundingSphere(gridDimension: Vec3, gridTransform: Mat4, transform: Float32Array, transformCount: number) { +function getBoundingSphere(gridDimension: Vec3, gridTransform: Mat4) { tmpVertices.set(VolumeBox.vertices) Mat4.fromTranslation(mTmp, vHalfUnit) Mat4.mul(mTmp, Mat4.fromScaling(mTmp2, gridDimension), mTmp) Mat4.mul(mTmp, gridTransform, mTmp) transformPositionArray(mTmp, tmpVertices, 0, tmpVertices.length / 3) - return calculateBoundingSphere(tmpVertices, tmpVertices.length / 3, transform, transformCount) + return calculateInvariantBoundingSphere(tmpVertices, tmpVertices.length / 3, 1) + // return calculateBoundingSphere(tmpVertices, tmpVertices.length / 3, transform, transformCount) } \ No newline at end of file diff --git a/src/mol-geo/geometry/geometry.ts b/src/mol-geo/geometry/geometry.ts index b6e0b15f05c67d0bfe099cbf94987401d0383c57..71c29ed937aaf844b5998b9512830fa9fd67e855 100644 --- a/src/mol-geo/geometry/geometry.ts +++ b/src/mol-geo/geometry/geometry.ts @@ -64,7 +64,7 @@ export namespace Geometry { case 'text': return geometry.charCount * 2 * 3 case 'lines': return geometry.lineCount * 2 * 3 case 'direct-volume': return 12 * 3 - case 'texture-mesh': return geometry.vertexCount.ref.value + case 'texture-mesh': return geometry.vertexCount } } @@ -79,7 +79,7 @@ export namespace Geometry { case 'direct-volume': return 1 case 'texture-mesh': - return geometry.groupCount.ref.value + return geometry.groupCount } } diff --git a/src/mol-geo/geometry/lines/lines-builder.ts b/src/mol-geo/geometry/lines/lines-builder.ts index 7fe39748261c15b35b6ec46500d9b4d2c40e4ce4..3b512c7e5fd431b3fbd8db5d32e0fd35d28fd919 100644 --- a/src/mol-geo/geometry/lines/lines-builder.ts +++ b/src/mol-geo/geometry/lines/lines-builder.ts @@ -1,10 +1,9 @@ /** - * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from '../../../mol-util/value-cell' import { ChunkedArray } from '../../../mol-data/util'; import { Lines } from './lines'; import { Mat4, Vec3 } from '../../../mol-math/linear-algebra'; @@ -84,15 +83,7 @@ export namespace LinesBuilder { const gb = ChunkedArray.compact(groups, true) as Float32Array const sb = ChunkedArray.compact(starts, true) as Float32Array const eb = ChunkedArray.compact(ends, true) as Float32Array - return { - kind: 'lines', - lineCount: indices.elementCount / 2, - mappingBuffer: lines ? ValueCell.update(lines.mappingBuffer, mb) : ValueCell.create(mb), - indexBuffer: lines ? ValueCell.update(lines.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: lines ? ValueCell.update(lines.groupBuffer, gb) : ValueCell.create(gb), - startBuffer: lines ? ValueCell.update(lines.startBuffer, sb) : ValueCell.create(sb), - endBuffer: lines ? ValueCell.update(lines.endBuffer, eb) : ValueCell.create(eb), - } + return Lines.create(mb, ib, gb, sb, eb, indices.elementCount / 2) } } } diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts index 9c1e5e359c83c604ca78e1504f43b26a51683624..71b9a7228c53e0a4f1830ecdce399054d13029b3 100644 --- a/src/mol-geo/geometry/lines/lines.ts +++ b/src/mol-geo/geometry/lines/lines.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -17,19 +17,22 @@ import { LinesValues } from '../../../mol-gl/renderable/lines'; import { Mesh } from '../mesh/mesh'; import { LinesBuilder } from './lines-builder'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { calculateBoundingSphere } from '../../../mol-gl/renderable/util'; +import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { Sphere3D } from '../../../mol-math/geometry'; import { Theme } from '../../../mol-theme/theme'; import { Color } from '../../../mol-util/color'; import { BaseGeometry } from '../base'; import { createEmptyOverpaint } from '../overpaint-data'; import { createEmptyTransparency } from '../transparency-data'; +import { hashFnv32a } from '../../../mol-data/util'; /** Wide line */ export interface Lines { readonly kind: 'lines', + /** Number of lines */ lineCount: number, + /** Mapping buffer as array of xy values wrapped in a value cell */ readonly mappingBuffer: ValueCell<Float32Array>, /** Index buffer as array of vertex index triplets wrapped in a value cell */ @@ -40,24 +43,25 @@ export interface Lines { readonly startBuffer: ValueCell<Float32Array>, /** Line end buffer as array of xyz values wrapped in a value cell */ readonly endBuffer: ValueCell<Float32Array>, + + /** Bounding sphere of the lines */ + readonly boundingSphere: Sphere3D } export namespace Lines { + export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number, lines?: Lines): Lines { + return lines ? + update(mappings, indices, groups, starts, ends, lineCount, lines) : + fromArrays(mappings, indices, groups, starts, ends, lineCount) + } + export function createEmpty(lines?: Lines): Lines { const mb = lines ? lines.mappingBuffer.ref.value : new Float32Array(0) const ib = lines ? lines.indexBuffer.ref.value : new Uint32Array(0) const gb = lines ? lines.groupBuffer.ref.value : new Float32Array(0) const sb = lines ? lines.startBuffer.ref.value : new Float32Array(0) const eb = lines ? lines.endBuffer.ref.value : new Float32Array(0) - return { - kind: 'lines', - lineCount: 0, - mappingBuffer: lines ? ValueCell.update(lines.mappingBuffer, mb) : ValueCell.create(mb), - indexBuffer: lines ? ValueCell.update(lines.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: lines ? ValueCell.update(lines.groupBuffer, gb) : ValueCell.create(gb), - startBuffer: lines ? ValueCell.update(lines.startBuffer, sb) : ValueCell.create(sb), - endBuffer: lines ? ValueCell.update(lines.endBuffer, eb) : ValueCell.create(eb), - } + return create(mb, ib, gb, sb, eb, 0, lines) } export function fromMesh(mesh: Mesh, lines?: Lines) { @@ -81,16 +85,57 @@ export namespace Lines { return builder.getLines(); } - export function transformImmediate(line: Lines, t: Mat4) { - transformRangeImmediate(line, t, 0, line.lineCount) + function hashCode(lines: Lines) { + return hashFnv32a([ + lines.lineCount, lines.mappingBuffer.ref.version, lines.indexBuffer.ref.version, + lines.groupBuffer.ref.version, lines.startBuffer.ref.version, lines.startBuffer.ref.version + ]) + } + + function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number): Lines { + + const boundingSphere = Sphere3D() + let currentHash = -1 + + const lines = { + kind: 'lines' as const, + lineCount, + mappingBuffer: ValueCell.create(mappings), + indexBuffer: ValueCell.create(indices), + groupBuffer: ValueCell.create(groups), + startBuffer: ValueCell.create(starts), + endBuffer: ValueCell.create(ends), + get boundingSphere() { + const newHash = hashCode(lines) + if (newHash !== currentHash) { + const s = calculateInvariantBoundingSphere(lines.startBuffer.ref.value, lines.lineCount * 4, 4) + const e = calculateInvariantBoundingSphere(lines.endBuffer.ref.value, lines.lineCount * 4, 4) + + Sphere3D.copy(boundingSphere, Sphere3D.expandBySphere(s, e)) + currentHash = newHash + } + return boundingSphere + }, + } + return lines + } + + function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number, lines: Lines) { + lines.lineCount = lineCount + ValueCell.update(lines.mappingBuffer, mappings) + ValueCell.update(lines.indexBuffer, indices) + ValueCell.update(lines.groupBuffer, groups) + ValueCell.update(lines.startBuffer, starts) + ValueCell.update(lines.endBuffer, ends) + return lines } - export function transformRangeImmediate(lines: Lines, t: Mat4, offset: number, count: number) { + export function transform(lines: Lines, t: Mat4) { const start = lines.startBuffer.ref.value - transformPositionArray(t, start, offset, count * 4) + transformPositionArray(t, start, 0, lines.lineCount * 4) ValueCell.update(lines.startBuffer, start); const end = lines.endBuffer.ref.value - transformPositionArray(t, end, offset, count * 4) + transformPositionArray(t, end, 0, lines.lineCount * 4) ValueCell.update(lines.endBuffer, end); } @@ -124,8 +169,8 @@ export namespace Lines { const counts = { drawCount: lines.lineCount * 2 * 3, groupCount, instanceCount } - const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(lines.startBuffer.ref.value, lines.endBuffer.ref.value, lines.lineCount, - transform.aTransform.ref.value, transform.instanceCount.ref.value) + const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) return { aMapping: lines.mappingBuffer, @@ -163,10 +208,9 @@ export namespace Lines { } function updateBoundingSphere(values: LinesValues, lines: Lines) { - const { boundingSphere, invariantBoundingSphere } = getBoundingSphere( - values.aStart.ref.value, values.aEnd.ref.value, lines.lineCount, - values.aTransform.ref.value, values.instanceCount.ref.value - ) + const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } @@ -174,13 +218,4 @@ export namespace Lines { ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere) } } -} - -function getBoundingSphere(lineStart: Float32Array, lineEnd: Float32Array, lineCount: number, transform: Float32Array, transformCount: number) { - const start = calculateBoundingSphere(lineStart, lineCount * 4, transform, transformCount, 0, 4) - const end = calculateBoundingSphere(lineEnd, lineCount * 4, transform, transformCount, 0, 4) - return { - boundingSphere: Sphere3D.expandBySphere(start.boundingSphere, end.boundingSphere), - invariantBoundingSphere: Sphere3D.expandBySphere(start.invariantBoundingSphere, end.invariantBoundingSphere) - } } \ No newline at end of file diff --git a/src/mol-geo/geometry/mesh/laplacian-smoothing.ts b/src/mol-geo/geometry/mesh/laplacian-smoothing.ts new file mode 100644 index 0000000000000000000000000000000000000000..3509512c0bd9e8b49e6ddf34ec00f5c03af841cf --- /dev/null +++ b/src/mol-geo/geometry/mesh/laplacian-smoothing.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +// TODO + +// function addVertex(src: Float32Array, i: number, dst: Float32Array, j: number) { +// dst[3 * j] += src[3 * i]; +// dst[3 * j + 1] += src[3 * i + 1]; +// dst[3 * j + 2] += src[3 * i + 2]; +// } + +// function laplacianSmoothIter(surface: Surface, vertexCounts: Int32Array, vs: Float32Array, vertexWeight: number) { +// const triCount = surface.triangleIndices.length, +// src = surface.vertices; + +// const triangleIndices = surface.triangleIndices; + +// for (let i = 0; i < triCount; i += 3) { +// const a = triangleIndices[i], +// b = triangleIndices[i + 1], +// c = triangleIndices[i + 2]; + +// addVertex(src, b, vs, a); +// addVertex(src, c, vs, a); + +// addVertex(src, a, vs, b); +// addVertex(src, c, vs, b); + +// addVertex(src, a, vs, c); +// addVertex(src, b, vs, c); +// } + +// const vw = 2 * vertexWeight; +// for (let i = 0, _b = surface.vertexCount; i < _b; i++) { +// const n = vertexCounts[i] + vw; +// vs[3 * i] = (vs[3 * i] + vw * src[3 * i]) / n; +// vs[3 * i + 1] = (vs[3 * i + 1] + vw * src[3 * i + 1]) / n; +// vs[3 * i + 2] = (vs[3 * i + 2] + vw * src[3 * i + 2]) / n; +// } +// } + +// async function laplacianSmoothComputation(ctx: Computation.Context, surface: Surface, iterCount: number, vertexWeight: number) { +// await ctx.updateProgress('Smoothing surface...', true); + +// const vertexCounts = new Int32Array(surface.vertexCount), +// triCount = surface.triangleIndices.length; + +// const tris = surface.triangleIndices; +// for (let i = 0; i < triCount; i++) { +// // in a triangle 2 edges touch each vertex, hence the constant. +// vertexCounts[tris[i]] += 2; +// } + +// let vs = new Float32Array(surface.vertices.length); +// let started = Utils.PerformanceMonitor.currentTime(); +// await ctx.updateProgress('Smoothing surface...', true); +// for (let i = 0; i < iterCount; i++) { +// if (i > 0) { +// for (let j = 0, _b = vs.length; j < _b; j++) vs[j] = 0; +// } +// surface.normals = void 0; +// laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight); +// const t = surface.vertices; +// surface.vertices = <any>vs; +// vs = <any>t; + +// const time = Utils.PerformanceMonitor.currentTime(); +// if (time - started > Computation.UpdateProgressDelta) { +// started = time; +// await ctx.updateProgress('Smoothing surface...', true, i + 1, iterCount); +// } +// } +// return surface; +// } + +// /* +// * Smooths the vertices by averaging the neighborhood. +// * +// * Resets normals. Might replace vertex array. +// */ +// export function laplacianSmooth(surface: Surface, iterCount: number = 1, vertexWeight: number = 1): Computation<Surface> { + +// if (iterCount < 1) iterCount = 0; +// if (iterCount === 0) return Computation.resolve(surface); + +// return computation(async ctx => await laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1)); +// } \ No newline at end of file diff --git a/src/mol-geo/geometry/mesh/mesh-builder.ts b/src/mol-geo/geometry/mesh/mesh-builder.ts index 0ab2a60778a76dfdb054112e0d84b734cf07e7b3..5c810888f809cdb92dfa6abf043e5982bfb94f58 100644 --- a/src/mol-geo/geometry/mesh/mesh-builder.ts +++ b/src/mol-geo/geometry/mesh/mesh-builder.ts @@ -1,10 +1,9 @@ /** - * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from '../../../mol-util/value-cell' import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra'; import { ChunkedArray } from '../../../mol-data/util'; import { Mesh } from './mesh'; @@ -141,15 +140,6 @@ export namespace MeshBuilder { const ib = ChunkedArray.compact(indices, true) as Uint32Array const nb = ChunkedArray.compact(normals, true) as Float32Array const gb = ChunkedArray.compact(groups, true) as Float32Array - return { - kind: 'mesh', - vertexCount: state.vertices.elementCount, - triangleCount: state.indices.elementCount, - vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), - indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), - normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), - groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb), - normalsComputed: true, - } + return Mesh.create(vb, ib, nb, gb, state.vertices.elementCount, state.indices.elementCount, mesh) } } \ No newline at end of file diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts index 8948499235d97fd9cce6ef603a2c176cf0370e35..f8af4dcd178d0d0179cb12628e9c8dddfeb7fe3d 100644 --- a/src/mol-geo/geometry/mesh/mesh.ts +++ b/src/mol-geo/geometry/mesh/mesh.ts @@ -1,22 +1,23 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * + * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> */ -import { Task } from '../../../mol-task' import { ValueCell } from '../../../mol-util' -import { Vec3, Mat4 } from '../../../mol-math/linear-algebra' +import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra' import { Sphere3D } from '../../../mol-math/geometry' -import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; +import { transformPositionArray,/* , transformDirectionArray, getNormalMatrix */ +transformDirectionArray} from '../../util'; import { GeometryUtils } from '../geometry'; import { createMarkers } from '../marker-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; import { createColors } from '../color-data'; -import { ChunkedArray } from '../../../mol-data/util'; +import { ChunkedArray, hashFnv32a } from '../../../mol-data/util'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { calculateBoundingSphere } from '../../../mol-gl/renderable/util'; +import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { Theme } from '../../../mol-theme/theme'; import { MeshValues } from '../../../mol-gl/renderable/mesh'; import { Color } from '../../../mol-util/color'; @@ -41,47 +42,70 @@ export interface Mesh { /** Group buffer as array of group ids for each vertex wrapped in a value cell */ readonly groupBuffer: ValueCell<Float32Array>, - /** Flag indicating if normals are computed for the current set of vertices */ - normalsComputed: boolean, - /** Bounding sphere of the mesh */ - boundingSphere?: Sphere3D + readonly boundingSphere: Sphere3D } export namespace Mesh { + export function create(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, mesh?: Mesh): Mesh { + return mesh ? + update(vertices, indices, normals, groups, vertexCount, triangleCount, mesh) : + fromArrays(vertices, indices, normals, groups, vertexCount, triangleCount) + } + export function createEmpty(mesh?: Mesh): Mesh { const vb = mesh ? mesh.vertexBuffer.ref.value : new Float32Array(0) const ib = mesh ? mesh.indexBuffer.ref.value : new Uint32Array(0) const nb = mesh ? mesh.normalBuffer.ref.value : new Float32Array(0) const gb = mesh ? mesh.groupBuffer.ref.value : new Float32Array(0) - return { - kind: 'mesh', - vertexCount: 0, - triangleCount: 0, - vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), - indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), - normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), - groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb), - normalsComputed: true, - } + return create(vb, ib, nb, gb, 0, 0, mesh) } - export function fromArrays(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, normalsComputed: boolean): Mesh { - return { - kind: 'mesh', + function hashCode(mesh: Mesh) { + return hashFnv32a([ + mesh.vertexCount, mesh.triangleCount, + mesh.vertexBuffer.ref.version, mesh.indexBuffer.ref.version, + mesh.normalBuffer.ref.version, mesh.groupBuffer.ref.version + ]) + } + + function fromArrays(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number): Mesh { + + const boundingSphere = Sphere3D() + let currentHash = -1 + + const mesh = { + kind: 'mesh' as const, vertexCount, triangleCount, vertexBuffer: ValueCell.create(vertices), indexBuffer: ValueCell.create(indices), normalBuffer: ValueCell.create(normals), groupBuffer: ValueCell.create(groups), - normalsComputed, + get boundingSphere() { + const newHash = hashCode(mesh) + if (newHash !== currentHash) { + const b = calculateInvariantBoundingSphere(mesh.vertexBuffer.ref.value, mesh.vertexCount, 1) + Sphere3D.copy(boundingSphere, b) + currentHash = newHash + } + return boundingSphere + }, } + return mesh } - export function computeNormalsImmediate(mesh: Mesh) { - if (mesh.normalsComputed) return; + function update(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, mesh: Mesh) { + mesh.vertexCount = vertexCount + mesh.triangleCount = triangleCount + ValueCell.update(mesh.vertexBuffer, vertices) + ValueCell.update(mesh.indexBuffer, indices) + ValueCell.update(mesh.normalBuffer, normals) + ValueCell.update(mesh.groupBuffer, groups) + return mesh + } + export function computeNormals(mesh: Mesh) { const normals = mesh.normalBuffer.ref.value.length >= mesh.vertexCount * 3 ? mesh.normalBuffer.ref.value : new Float32Array(mesh.vertexBuffer.ref.value.length); @@ -115,11 +139,8 @@ export namespace Mesh { const nz = normals[i + 2]; const f = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz); normals[i] *= f; normals[i + 1] *= f; normals[i + 2] *= f; - - // console.log([normals[i], normals[i + 1], normals[i + 2]], [v[i], v[i + 1], v[i + 2]]) } ValueCell.update(mesh.normalBuffer, normals); - mesh.normalsComputed = true; } export function checkForDuplicateVertices(mesh: Mesh, fractionDigits = 3) { @@ -144,63 +165,15 @@ export namespace Mesh { return duplicates } - export function computeNormals(surface: Mesh): Task<Mesh> { - return Task.create<Mesh>('Surface (Compute Normals)', async ctx => { - if (surface.normalsComputed) return surface; - - await ctx.update('Computing normals...'); - computeNormalsImmediate(surface); - return surface; - }); - } - - export function transformImmediate(mesh: Mesh, t: Mat4) { - transformRangeImmediate(mesh, t, 0, mesh.vertexCount) - } - - export function transformRangeImmediate(mesh: Mesh, t: Mat4, offset: number, count: number) { + const tmpMat3 = Mat3.zero() + export function transform(mesh: Mesh, t: Mat4) { const v = mesh.vertexBuffer.ref.value - transformPositionArray(t, v, offset, count) - // TODO normals transformation does not work for an unknown reason, ASR - // if (mesh.normalBuffer.ref.value) { - // const n = getNormalMatrix(Mat3.zero(), t) - // transformDirectionArray(n, mesh.normalBuffer.ref.value, offset, count) - // mesh.normalsComputed = true; - // } + transformPositionArray(t, v, 0, mesh.vertexCount) + if (!Mat4.isTranslationAndUniformScaling(t)) { + const n = Mat3.directionTransform(tmpMat3, t) + transformDirectionArray(n, mesh.normalBuffer.ref.value, 0, mesh.vertexCount) + } ValueCell.update(mesh.vertexBuffer, v); - mesh.normalsComputed = false; - } - - export function computeBoundingSphere(mesh: Mesh): Task<Mesh> { - return Task.create<Mesh>('Mesh (Compute Bounding Sphere)', async ctx => { - if (mesh.boundingSphere) { - return mesh; - } - await ctx.update('Computing bounding sphere...'); - - const vertices = mesh.vertexBuffer.ref.value; - let x = 0, y = 0, z = 0; - for (let i = 0, _c = vertices.length; i < _c; i += 3) { - x += vertices[i]; - y += vertices[i + 1]; - z += vertices[i + 2]; - } - x /= mesh.vertexCount; - y /= mesh.vertexCount; - z /= mesh.vertexCount; - let r = 0; - for (let i = 0, _c = vertices.length; i < _c; i += 3) { - const dx = x - vertices[i]; - const dy = y - vertices[i + 1]; - const dz = z - vertices[i + 2]; - r = Math.max(r, dx * dx + dy * dy + dz * dz); - } - mesh.boundingSphere = { - center: Vec3.create(x, y, z), - radius: Math.sqrt(r) - } - return mesh; - }); } /** @@ -389,10 +362,8 @@ export namespace Mesh { const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount } - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - mesh.vertexBuffer.ref.value, mesh.vertexCount, - transform.aTransform.ref.value, instanceCount - ) + const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) return { aPosition: mesh.vertexBuffer, @@ -430,10 +401,9 @@ export namespace Mesh { } function updateBoundingSphere(values: MeshValues, mesh: Mesh) { - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - values.aPosition.ref.value, mesh.vertexCount, - values.aTransform.ref.value, values.instanceCount.ref.value - ) + const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } @@ -442,86 +412,3 @@ export namespace Mesh { } } } - -// function addVertex(src: Float32Array, i: number, dst: Float32Array, j: number) { -// dst[3 * j] += src[3 * i]; -// dst[3 * j + 1] += src[3 * i + 1]; -// dst[3 * j + 2] += src[3 * i + 2]; -// } - -// function laplacianSmoothIter(surface: Surface, vertexCounts: Int32Array, vs: Float32Array, vertexWeight: number) { -// const triCount = surface.triangleIndices.length, -// src = surface.vertices; - -// const triangleIndices = surface.triangleIndices; - -// for (let i = 0; i < triCount; i += 3) { -// const a = triangleIndices[i], -// b = triangleIndices[i + 1], -// c = triangleIndices[i + 2]; - -// addVertex(src, b, vs, a); -// addVertex(src, c, vs, a); - -// addVertex(src, a, vs, b); -// addVertex(src, c, vs, b); - -// addVertex(src, a, vs, c); -// addVertex(src, b, vs, c); -// } - -// const vw = 2 * vertexWeight; -// for (let i = 0, _b = surface.vertexCount; i < _b; i++) { -// const n = vertexCounts[i] + vw; -// vs[3 * i] = (vs[3 * i] + vw * src[3 * i]) / n; -// vs[3 * i + 1] = (vs[3 * i + 1] + vw * src[3 * i + 1]) / n; -// vs[3 * i + 2] = (vs[3 * i + 2] + vw * src[3 * i + 2]) / n; -// } -// } - -// async function laplacianSmoothComputation(ctx: Computation.Context, surface: Surface, iterCount: number, vertexWeight: number) { -// await ctx.updateProgress('Smoothing surface...', true); - -// const vertexCounts = new Int32Array(surface.vertexCount), -// triCount = surface.triangleIndices.length; - -// const tris = surface.triangleIndices; -// for (let i = 0; i < triCount; i++) { -// // in a triangle 2 edges touch each vertex, hence the constant. -// vertexCounts[tris[i]] += 2; -// } - -// let vs = new Float32Array(surface.vertices.length); -// let started = Utils.PerformanceMonitor.currentTime(); -// await ctx.updateProgress('Smoothing surface...', true); -// for (let i = 0; i < iterCount; i++) { -// if (i > 0) { -// for (let j = 0, _b = vs.length; j < _b; j++) vs[j] = 0; -// } -// surface.normals = void 0; -// laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight); -// const t = surface.vertices; -// surface.vertices = <any>vs; -// vs = <any>t; - -// const time = Utils.PerformanceMonitor.currentTime(); -// if (time - started > Computation.UpdateProgressDelta) { -// started = time; -// await ctx.updateProgress('Smoothing surface...', true, i + 1, iterCount); -// } -// } -// return surface; -// } - -// /* -// * Smooths the vertices by averaging the neighborhood. -// * -// * Resets normals. Might replace vertex array. -// */ -// export function laplacianSmooth(surface: Surface, iterCount: number = 1, vertexWeight: number = 1): Computation<Surface> { - -// if (iterCount < 1) iterCount = 0; -// if (iterCount === 0) return Computation.resolve(surface); - -// return computation(async ctx => await laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1)); -// } \ No newline at end of file diff --git a/src/mol-geo/geometry/points/points-builder.ts b/src/mol-geo/geometry/points/points-builder.ts index b798b88efe5ff4ceba36d99e05305b869e5a3d62..08c784c63d27e3a36dff6f6c3be8ac1326482bcf 100644 --- a/src/mol-geo/geometry/points/points-builder.ts +++ b/src/mol-geo/geometry/points/points-builder.ts @@ -1,10 +1,9 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from '../../../mol-util/value-cell' import { ChunkedArray } from '../../../mol-data/util'; import { Points } from './points'; @@ -26,12 +25,7 @@ export namespace PointsBuilder { getPoints: () => { const cb = ChunkedArray.compact(centers, true) as Float32Array const gb = ChunkedArray.compact(groups, true) as Float32Array - return { - kind: 'points', - pointCount: centers.elementCount, - centerBuffer: points ? ValueCell.update(points.centerBuffer, cb) : ValueCell.create(cb), - groupBuffer: points ? ValueCell.update(points.groupBuffer, gb) : ValueCell.create(gb), - } + return Points.create(cb, gb, centers.elementCount, points) } } } diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts index 924ed1ccda36a479c4c99919140b025d2e137da0..ae5c6f73af7181ec3c1d4ccf94feeeb736277171 100644 --- a/src/mol-geo/geometry/points/points.ts +++ b/src/mol-geo/geometry/points/points.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -14,7 +14,7 @@ import { createSizes } from '../size-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { calculateBoundingSphere } from '../../../mol-gl/renderable/util'; +import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { Sphere3D } from '../../../mol-math/geometry'; import { Theme } from '../../../mol-theme/theme'; import { PointsValues } from '../../../mol-gl/renderable/points'; @@ -23,37 +23,76 @@ import { Color } from '../../../mol-util/color'; import { BaseGeometry } from '../base'; import { createEmptyOverpaint } from '../overpaint-data'; import { createEmptyTransparency } from '../transparency-data'; +import { hashFnv32a } from '../../../mol-data/util'; /** Point cloud */ export interface Points { readonly kind: 'points', + /** Number of vertices in the point cloud */ pointCount: number, + /** Center buffer as array of xyz values wrapped in a value cell */ readonly centerBuffer: ValueCell<Float32Array>, /** Group buffer as array of group ids for each vertex wrapped in a value cell */ readonly groupBuffer: ValueCell<Float32Array>, + + /** Bounding sphere of the points */ + readonly boundingSphere: Sphere3D } export namespace Points { + export function create(centers: Float32Array, groups: Float32Array, pointCount: number, points?: Points): Points { + return points ? + update(centers, groups, pointCount, points) : + fromArrays(centers, groups, pointCount) + } + export function createEmpty(points?: Points): Points { const cb = points ? points.centerBuffer.ref.value : new Float32Array(0) const gb = points ? points.groupBuffer.ref.value : new Float32Array(0) - return { - kind: 'points', - pointCount: 0, - centerBuffer: points ? ValueCell.update(points.centerBuffer, cb) : ValueCell.create(cb), - groupBuffer: points ? ValueCell.update(points.groupBuffer, gb) : ValueCell.create(gb), + return create(cb, gb, 0, points) + } + + function hashCode(points: Points) { + return hashFnv32a([ + points.pointCount, points.centerBuffer.ref.version, points.groupBuffer.ref.version, + ]) + } + + function fromArrays(centers: Float32Array, groups: Float32Array, pointCount: number): Points { + + const boundingSphere = Sphere3D() + let currentHash = -1 + + const points = { + kind: 'points' as const, + pointCount, + centerBuffer: ValueCell.create(centers), + groupBuffer: ValueCell.create(groups), + get boundingSphere() { + const newHash = hashCode(points) + if (newHash !== currentHash) { + const b = calculateInvariantBoundingSphere(points.centerBuffer.ref.value, points.pointCount, 1) + Sphere3D.copy(boundingSphere, b) + currentHash = newHash + } + return boundingSphere + }, } + return points } - export function transformImmediate(points: Points, t: Mat4) { - transformRangeImmediate(points, t, 0, points.pointCount) + function update(centers: Float32Array, groups: Float32Array, pointCount: number, points: Points) { + points.pointCount = pointCount + ValueCell.update(points.centerBuffer, centers) + ValueCell.update(points.groupBuffer, groups) + return points } - export function transformRangeImmediate(points: Points, t: Mat4, offset: number, count: number) { + export function transform(points: Points, t: Mat4) { const c = points.centerBuffer.ref.value - transformPositionArray(t, c, offset, count) + transformPositionArray(t, c, 0, points.pointCount) ValueCell.update(points.centerBuffer, c); } @@ -89,10 +128,8 @@ export namespace Points { const counts = { drawCount: points.pointCount, groupCount, instanceCount } - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - points.centerBuffer.ref.value, points.pointCount, - transform.aTransform.ref.value, transform.instanceCount.ref.value - ) + const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) return { aPosition: points.centerBuffer, @@ -129,10 +166,9 @@ export namespace Points { } function updateBoundingSphere(values: PointsValues, points: Points) { - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - values.aPosition.ref.value, points.pointCount, - values.aTransform.ref.value, values.instanceCount.ref.value - ) + const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } diff --git a/src/mol-geo/geometry/spheres/spheres-builder.ts b/src/mol-geo/geometry/spheres/spheres-builder.ts index 423c7b4db6b718bf50e7a0a2a0ece9befd066a8d..127d48754190c6e2f3f84c9fff9fb4db03be9a66 100644 --- a/src/mol-geo/geometry/spheres/spheres-builder.ts +++ b/src/mol-geo/geometry/spheres/spheres-builder.ts @@ -1,10 +1,9 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from '../../../mol-util/value-cell' import { ChunkedArray } from '../../../mol-data/util'; import { Spheres } from './spheres'; @@ -50,14 +49,7 @@ export namespace SpheresBuilder { const mb = ChunkedArray.compact(mappings, true) as Float32Array const ib = ChunkedArray.compact(indices, true) as Uint32Array const gb = ChunkedArray.compact(groups, true) as Float32Array - return { - kind: 'spheres', - sphereCount: centers.elementCount / 4, - centerBuffer: spheres ? ValueCell.update(spheres.centerBuffer, cb) : ValueCell.create(cb), - mappingBuffer: spheres ? ValueCell.update(spheres.mappingBuffer, mb) : ValueCell.create(mb), - indexBuffer: spheres ? ValueCell.update(spheres.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: spheres ? ValueCell.update(spheres.groupBuffer, gb) : ValueCell.create(gb), - } + return Spheres.create(cb, mb, ib, gb, centers.elementCount / 4, spheres) } } } diff --git a/src/mol-geo/geometry/spheres/spheres.ts b/src/mol-geo/geometry/spheres/spheres.ts index 0365b1fd0229c3f4169558b1dcbefc562670425c..c7f68dab4fd8b28574d73fd45e861279953ff205 100644 --- a/src/mol-geo/geometry/spheres/spheres.ts +++ b/src/mol-geo/geometry/spheres/spheres.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -13,15 +13,15 @@ import { Theme } from '../../../mol-theme/theme'; import { SpheresValues } from '../../../mol-gl/renderable/spheres'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; -import { calculateBoundingSphere } from '../../../mol-gl/renderable/util'; +import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { Sphere3D } from '../../../mol-math/geometry'; import { createSizes, getMaxSize } from '../size-data'; import { Color } from '../../../mol-util/color'; import { BaseGeometry } from '../base'; import { createEmptyOverpaint } from '../overpaint-data'; import { createEmptyTransparency } from '../transparency-data'; +import { hashFnv32a } from '../../../mol-data/util'; -/** Spheres */ export interface Spheres { readonly kind: 'spheres', @@ -36,22 +36,66 @@ export interface Spheres { readonly indexBuffer: ValueCell<Uint32Array>, /** Group buffer as array of group ids for each vertex wrapped in a value cell */ readonly groupBuffer: ValueCell<Float32Array>, + + /** Bounding sphere of the spheres */ + readonly boundingSphere: Sphere3D } export namespace Spheres { + export function create(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number, spheres?: Spheres): Spheres { + return spheres ? + update(centers, mappings, indices, groups, sphereCount, spheres) : + fromArrays(centers, mappings, indices, groups, sphereCount) + } + export function createEmpty(spheres?: Spheres): Spheres { const cb = spheres ? spheres.centerBuffer.ref.value : new Float32Array(0) const mb = spheres ? spheres.mappingBuffer.ref.value : new Float32Array(0) const ib = spheres ? spheres.indexBuffer.ref.value : new Uint32Array(0) const gb = spheres ? spheres.groupBuffer.ref.value : new Float32Array(0) - return { - kind: 'spheres', - sphereCount: 0, - centerBuffer: spheres ? ValueCell.update(spheres.centerBuffer, cb) : ValueCell.create(cb), - mappingBuffer: spheres ? ValueCell.update(spheres.mappingBuffer, mb) : ValueCell.create(mb), - indexBuffer: spheres ? ValueCell.update(spheres.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: spheres ? ValueCell.update(spheres.groupBuffer, gb) : ValueCell.create(gb) + return create(cb, mb, ib, gb, 0, spheres) + } + + function hashCode(spheres: Spheres) { + return hashFnv32a([ + spheres.sphereCount, + spheres.centerBuffer.ref.version, spheres.mappingBuffer.ref.version, + spheres.indexBuffer.ref.version, spheres.groupBuffer.ref.version + ]) + } + + function fromArrays(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number): Spheres { + + const boundingSphere = Sphere3D() + let currentHash = -1 + + const spheres = { + kind: 'spheres' as const, + sphereCount, + centerBuffer: ValueCell.create(centers), + mappingBuffer: ValueCell.create(mappings), + indexBuffer: ValueCell.create(indices), + groupBuffer: ValueCell.create(groups), + get boundingSphere() { + const newHash = hashCode(spheres) + if (newHash !== currentHash) { + const b = calculateInvariantBoundingSphere(spheres.centerBuffer.ref.value, spheres.sphereCount * 4, 4) + Sphere3D.copy(boundingSphere, b) + currentHash = newHash + } + return boundingSphere + }, } + return spheres + } + + function update(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number, spheres: Spheres) { + spheres.sphereCount = sphereCount + ValueCell.update(spheres.centerBuffer, centers) + ValueCell.update(spheres.mappingBuffer, mappings) + ValueCell.update(spheres.indexBuffer, indices) + ValueCell.update(spheres.groupBuffer, groups) + return spheres } export const Params = { @@ -88,10 +132,8 @@ export namespace Spheres { const counts = { drawCount: spheres.sphereCount * 2 * 3, groupCount, instanceCount } const padding = getMaxSize(size) - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - spheres.centerBuffer.ref.value, spheres.sphereCount * 4, - transform.aTransform.ref.value, instanceCount, padding, 4 - ) + const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) return { aPosition: spheres.centerBuffer, @@ -131,10 +173,9 @@ export namespace Spheres { function updateBoundingSphere(values: SpheresValues, spheres: Spheres) { const padding = getMaxSize(values) - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - values.aPosition.ref.value, spheres.sphereCount * 4, - values.aTransform.ref.value, values.instanceCount.ref.value, padding, 4 - ) + const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } diff --git a/src/mol-geo/geometry/text/text-builder.ts b/src/mol-geo/geometry/text/text-builder.ts index 4cc27190e5d3694cb24be8670a703307cbff1133..577efb3a78947b81a8e959c64b2c0893dd16845b 100644 --- a/src/mol-geo/geometry/text/text-builder.ts +++ b/src/mol-geo/geometry/text/text-builder.ts @@ -1,11 +1,10 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { ValueCell } from '../../../mol-util/value-cell' import { ChunkedArray } from '../../../mol-data/util'; import { Text } from './text'; import { getFontAtlas } from './font-atlas'; @@ -290,17 +289,7 @@ export namespace TextBuilder { const ib = ChunkedArray.compact(indices, true) as Uint32Array const gb = ChunkedArray.compact(groups, true) as Float32Array const tb = ChunkedArray.compact(tcoords, true) as Float32Array - return { - kind: 'text', - charCount: indices.elementCount / 2, - fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft), - centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb), - mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb), - depthBuffer: text ? ValueCell.update(text.depthBuffer, db) : ValueCell.create(db), - indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb), - tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb), - } + return Text.create(ft, cb,mb, db, ib, gb, tb, indices.elementCount / 2, text) } } } diff --git a/src/mol-geo/geometry/text/text.ts b/src/mol-geo/geometry/text/text.ts index 776de616c713735c96833c18a90e9a38b87e3535..f46c95f2f08924850599516fdb27f3143fc24c5e 100644 --- a/src/mol-geo/geometry/text/text.ts +++ b/src/mol-geo/geometry/text/text.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -15,7 +15,7 @@ import { createSizes, getMaxSize } from '../size-data'; import { createMarkers } from '../marker-data'; import { ColorNames } from '../../../mol-util/color/names'; import { Sphere3D } from '../../../mol-math/geometry'; -import { calculateBoundingSphere, TextureImage, createTextureImage } from '../../../mol-gl/renderable/util'; +import { TextureImage, createTextureImage, calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { TextValues } from '../../../mol-gl/renderable/text'; import { Color } from '../../../mol-util/color'; import { Vec3 } from '../../../mol-math/linear-algebra'; @@ -26,6 +26,7 @@ import { createRenderObject as _createRenderObject } from '../../../mol-gl/rende import { BaseGeometry } from '../base'; import { createEmptyOverpaint } from '../overpaint-data'; import { createEmptyTransparency } from '../transparency-data'; +import { hashFnv32a } from '../../../mol-data/util'; type TextAttachment = ( 'bottom-left' | 'bottom-center' | 'bottom-right' | @@ -38,7 +39,8 @@ export interface Text { readonly kind: 'text', /** Number of characters in the text */ - readonly charCount: number, + charCount: number, + /** Font Atlas */ readonly fontTexture: ValueCell<TextureImage<Uint8Array>>, @@ -54,9 +56,18 @@ export interface Text { readonly groupBuffer: ValueCell<Float32Array>, /** Texture coordinates buffer as array of uv values wrapped in a value cell */ readonly tcoordBuffer: ValueCell<Float32Array>, + + /** Bounding sphere of the text */ + readonly boundingSphere: Sphere3D } export namespace Text { + export function create(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number, text?: Text): Text { + return text ? + update(fontTexture, centers, mappings, depths, indices, groups, tcoords, charCount, text) : + fromData(fontTexture, centers, mappings, depths, indices, groups, tcoords, charCount) + } + export function createEmpty(text?: Text): Text { const ft = text ? text.fontTexture.ref.value : createTextureImage(0, 1, Uint8Array) const cb = text ? text.centerBuffer.ref.value : new Float32Array(0) @@ -65,17 +76,56 @@ export namespace Text { const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0) const gb = text ? text.groupBuffer.ref.value : new Float32Array(0) const tb = text ? text.tcoordBuffer.ref.value : new Float32Array(0) - return { - kind: 'text', - charCount: 0, - fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft), - centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb), - mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb), - depthBuffer: text ? ValueCell.update(text.depthBuffer, db) : ValueCell.create(db), - indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib), - groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb), - tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb) + return create(ft, cb, mb, db, ib, gb, tb, 0, text) + } + + function hashCode(text: Text) { + return hashFnv32a([ + text.charCount, text.fontTexture.ref.version, + text.centerBuffer.ref.version, text.mappingBuffer.ref.version, + text.depthBuffer.ref.version, text.indexBuffer.ref.version, + text.groupBuffer.ref.version, text.tcoordBuffer.ref.version + ]) + } + + function fromData(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number): Text { + + const boundingSphere = Sphere3D() + let currentHash = -1 + + const text = { + kind: 'text' as const, + charCount, + fontTexture: ValueCell.create(fontTexture), + centerBuffer: ValueCell.create(centers), + mappingBuffer: ValueCell.create(mappings), + depthBuffer: ValueCell.create(depths), + indexBuffer: ValueCell.create(indices), + groupBuffer: ValueCell.create(groups), + tcoordBuffer: ValueCell.create(tcoords), + get boundingSphere() { + const newHash = hashCode(text) + if (newHash !== currentHash) { + const b = calculateInvariantBoundingSphere(text.centerBuffer.ref.value, text.charCount * 4, 4) + Sphere3D.copy(boundingSphere, b) + currentHash = newHash + } + return boundingSphere + }, } + return text + } + + function update(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number, text: Text) { + text.charCount = charCount + ValueCell.update(text.fontTexture, fontTexture) + ValueCell.update(text.centerBuffer, centers) + ValueCell.update(text.mappingBuffer, mappings) + ValueCell.update(text.depthBuffer, depths) + ValueCell.update(text.indexBuffer, indices) + ValueCell.update(text.groupBuffer, groups) + ValueCell.update(text.tcoordBuffer, tcoords) + return text } export const Params = { @@ -130,10 +180,8 @@ export namespace Text { const counts = { drawCount: text.charCount * 2 * 3, groupCount, instanceCount } const padding = getPadding(text.mappingBuffer.ref.value, text.depthBuffer.ref.value, text.charCount, getMaxSize(size)) - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - text.centerBuffer.ref.value, text.charCount * 4, - transform.aTransform.ref.value, instanceCount, padding - ) + const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount) return { aPosition: text.centerBuffer, @@ -194,10 +242,9 @@ export namespace Text { function updateBoundingSphere(values: TextValues, text: Text) { const padding = getPadding(values.aMapping.ref.value, values.aDepth.ref.value, text.charCount, getMaxSize(values)) - const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere( - values.aPosition.ref.value, text.charCount * 4, - values.aTransform.ref.value, values.instanceCount.ref.value, padding - ) + const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding) + const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) + if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) } diff --git a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts index fa41657a85bb36c895d95b447b21b84975471e4c..77295ea5c96bd7a78f6e8606f88b3c049b4b767d 100644 --- a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts +++ b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts @@ -27,16 +27,16 @@ export interface TextureMesh { readonly kind: 'texture-mesh', /** Number of vertices in the texture-mesh */ - readonly vertexCount: ValueCell<number>, + vertexCount: number, /** Number of groups in the texture-mesh */ - readonly groupCount: ValueCell<number>, + groupCount: number, readonly geoTextureDim: ValueCell<Vec2>, /** texture has vertex positions in XYZ and group id in W */ readonly vertexGroupTexture: ValueCell<Texture>, readonly normalTexture: ValueCell<Texture>, - readonly boundingSphere: ValueCell<Sphere3D>, + readonly boundingSphere: Sphere3D } export namespace TextureMesh { @@ -44,22 +44,22 @@ export namespace TextureMesh { const width = vertexGroupTexture.getWidth() const height = vertexGroupTexture.getHeight() if (textureMesh) { - ValueCell.update(textureMesh.vertexCount, vertexCount) - ValueCell.update(textureMesh.groupCount, groupCount) + textureMesh.vertexCount = vertexCount + textureMesh.groupCount = groupCount ValueCell.update(textureMesh.geoTextureDim, Vec2.set(textureMesh.geoTextureDim.ref.value, width, height)) ValueCell.update(textureMesh.vertexGroupTexture, vertexGroupTexture) ValueCell.update(textureMesh.normalTexture, normalTexture) - ValueCell.update(textureMesh.boundingSphere, boundingSphere) + Sphere3D.copy(textureMesh.boundingSphere, boundingSphere) return textureMesh } else { return { kind: 'texture-mesh', - vertexCount: ValueCell.create(vertexCount), - groupCount: ValueCell.create(groupCount), + vertexCount, + groupCount, geoTextureDim: ValueCell.create(Vec2.create(width, height)), vertexGroupTexture: ValueCell.create(vertexGroupTexture), normalTexture: ValueCell.create(normalTexture), - boundingSphere: ValueCell.create(boundingSphere), + boundingSphere: Sphere3D.clone(boundingSphere), } } } @@ -94,9 +94,9 @@ export namespace TextureMesh { const overpaint = createEmptyOverpaint() const transparency = createEmptyTransparency() - const counts = { drawCount: textureMesh.vertexCount.ref.value, groupCount, instanceCount } + const counts = { drawCount: textureMesh.vertexCount, groupCount, instanceCount } - const transformBoundingSphere = calculateTransformBoundingSphere(textureMesh.boundingSphere.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value) + const transformBoundingSphere = calculateTransformBoundingSphere(textureMesh.boundingSphere, transform.aTransform.ref.value, transform.instanceCount.ref.value) return { uGeoTexDim: textureMesh.geoTextureDim, @@ -104,9 +104,9 @@ export namespace TextureMesh { tNormal: textureMesh.normalTexture, // aGroup is used as a vertex index here and the group id is retirieved from tPositionGroup - aGroup: ValueCell.create(fillSerial(new Float32Array(textureMesh.vertexCount.ref.value))), + aGroup: ValueCell.create(fillSerial(new Float32Array(textureMesh.vertexCount))), boundingSphere: ValueCell.create(transformBoundingSphere), - invariantBoundingSphere: textureMesh.boundingSphere, + invariantBoundingSphere: ValueCell.create(Sphere3D.clone(textureMesh.boundingSphere)), ...color, ...marker, @@ -142,7 +142,7 @@ export namespace TextureMesh { } function updateBoundingSphere(values: TextureMeshValues, textureMesh: TextureMesh) { - const invariantBoundingSphere = textureMesh.boundingSphere.ref.value + const invariantBoundingSphere = textureMesh.boundingSphere const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value) if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) { ValueCell.update(values.boundingSphere, boundingSphere) diff --git a/src/mol-geo/util/marching-cubes/builder.ts b/src/mol-geo/util/marching-cubes/builder.ts index fde7aea04a36662139ac7c92f70fff878da7285f..8525aa07648feb9d4a4ea1ccb5ff3e1e3fc7f384 100644 --- a/src/mol-geo/util/marching-cubes/builder.ts +++ b/src/mol-geo/util/marching-cubes/builder.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> @@ -7,7 +7,7 @@ */ import { ChunkedArray } from '../../../mol-data/util'; -import { ValueCell, noop } from '../../../mol-util'; +import { noop } from '../../../mol-util'; import { Mesh } from '../../geometry/mesh/mesh'; import { AllowedContours } from './tables'; import { LinesBuilder } from '../../geometry/lines/lines-builder'; @@ -52,17 +52,7 @@ export function MarchinCubesMeshBuilder(vertexChunkSize: number, mesh?: Mesh): M const nb = ChunkedArray.compact(normals, true) as Float32Array; const ib = ChunkedArray.compact(indices, true) as Uint32Array; const gb = ChunkedArray.compact(groups, true) as Float32Array; - - return { - kind: 'mesh', - vertexCount, - triangleCount, - vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), - groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb), - indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), - normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), - normalsComputed: true - } + return Mesh.create(vb, ib, nb, gb, vertexCount, triangleCount, mesh) } } } diff --git a/src/mol-model/loci.ts b/src/mol-model/loci.ts index 97e28b0bc1e2afef9ecd604b20d1adc591f355bc..462adbe7a8a864440ed8d4e8e335eb609e85230a 100644 --- a/src/mol-model/loci.ts +++ b/src/mol-model/loci.ts @@ -161,11 +161,10 @@ namespace Loci { sphereHelper.radiusStep(tmpPos); } } else if (loci.kind === 'shape-loci') { - // TODO - return void 0; + return Sphere3D.copy(boundingSphere, loci.shape.geometry.boundingSphere) } else if (loci.kind === 'group-loci') { // TODO - return void 0; + return Sphere3D.copy(boundingSphere, loci.shape.geometry.boundingSphere) } else if (loci.kind === 'data-loci') { // TODO maybe add loci.getBoundingSphere()??? return void 0; diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index 78981b0fb197b97573e7fae674612e3f381eff83..22c939e38816cee1b2c91518aa31ab56586be6b9 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -47,7 +47,7 @@ async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structu } const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime) - Mesh.transformImmediate(surface, transform) + Mesh.transform(surface, transform) if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface) return surface @@ -90,7 +90,7 @@ async function createStructureGaussianSurfaceMesh(ctx: VisualContext, structure: } const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime) - Mesh.transformImmediate(surface, transform) + Mesh.transform(surface, transform) if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface) return surface diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index cf7b32f45d3eca92387ac2fe39998f80db634dba..04bd8c7f54c4beba04875370728705120547926c 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -26,7 +26,7 @@ async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure } const wireframe = await computeMarchingCubesLines(params, lines).runAsChild(ctx.runtime) - Lines.transformImmediate(wireframe, transform) + Lines.transform(wireframe, transform) return wireframe } diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts index 2908c2275cfeb5a8d18b248da72a480d7f305987..0971b4a11ff202d6e421abb96ba75c438de39271 100644 --- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts +++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts @@ -35,7 +35,7 @@ async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, struct } const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime) - Mesh.transformImmediate(surface, transform) + Mesh.transform(surface, transform) if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface) return surface diff --git a/src/mol-repr/structure/visual/molecular-surface-wireframe.ts b/src/mol-repr/structure/visual/molecular-surface-wireframe.ts index c87eaab5379b894d73742d927e4eabfd6ecbea52..b7b809b61b2a9c31154e8028a0ead2657e0d58c8 100644 --- a/src/mol-repr/structure/visual/molecular-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/molecular-surface-wireframe.ts @@ -36,7 +36,7 @@ async function createMolecularSurfaceWireframe(ctx: VisualContext, unit: Unit, s } const wireframe = await computeMarchingCubesLines(params, lines).runAsChild(ctx.runtime) - Lines.transformImmediate(wireframe, transform) + Lines.transform(wireframe, transform) return wireframe } diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index 9b07cc625687ee615500f7701858e6b26cbba50e..8657b53842beabe1f358e2cf91bf7300a0ae8d43 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -78,7 +78,7 @@ export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Vol const transform = VolumeData.getGridToCartesianTransform(volume); ctx.runtime.update({ message: 'Transforming mesh...' }); - Mesh.transformImmediate(surface, transform); + Mesh.transform(surface, transform); return surface; } @@ -114,7 +114,7 @@ export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume }, lines).runAsChild(ctx.runtime) const transform = VolumeData.getGridToCartesianTransform(volume); - Lines.transformImmediate(wireframe, transform) + Lines.transform(wireframe, transform) return wireframe; } diff --git a/src/tests/browser/marching-cubes.ts b/src/tests/browser/marching-cubes.ts index 859e01e8ec7e27fbe9b93270df1be60e366fc235..4f8e8335b34dfd2ae04c720e74c64a49e43b667c 100644 --- a/src/tests/browser/marching-cubes.ts +++ b/src/tests/browser/marching-cubes.ts @@ -133,7 +133,7 @@ async function init() { const surface = await computeMarchingCubesMesh(params).run() console.timeEnd('cpu mc') console.log('surface', surface) - Mesh.transformImmediate(surface, densityData.transform) + Mesh.transform(surface, densityData.transform) const meshProps = { doubleSided: true, flatShaded: false, alpha: 1.0 } const meshValues = Mesh.Utils.createValuesSimple(surface, meshProps, Color(0x995511), 1) const meshState = Mesh.Utils.createRenderableState(meshProps)