Bladeren bron

renamed Sureface to Mesh, wip MeshBuilder

Alexander Rose 7 jaren geleden
bovenliggende
commit
91385af098

+ 4 - 4
src/apps/render-test/mcubes.ts

@@ -6,7 +6,7 @@
 
 import { Run } from 'mol-task'
 import { compute } from 'mol-geo/util/marching-cubes/algorithm'
-import { Surface } from 'mol-geo/shape/surface'
+import { Mesh } from 'mol-geo/shape/mesh'
 import { Tensor, Mat4, Vec3 } from 'mol-math/linear-algebra'
 
 function fillField(tensor: Tensor, f: (x: number, y: number, z: number) => number, min: number[], max: number[]): Tensor {
@@ -27,7 +27,7 @@ function fillField(tensor: Tensor, f: (x: number, y: number, z: number) => numbe
     return tensor
 }
 
-export default async function computeSurface(f: (x: number, y: number, z: number) => number, data?: { field: Tensor, surface: Surface }) {
+export default async function computeSurface(f: (x: number, y: number, z: number) => number, data?: { field: Tensor, surface: Mesh }) {
     let field: Tensor;
     if (data) field = data.field;
     else {
@@ -51,7 +51,7 @@ export default async function computeSurface(f: (x: number, y: number, z: number
     const scale = Mat4.fromScaling(Mat4.zero(), Vec3.create(size[0] / (grid[0] - 1), size[1] / (grid[1] - 1), size[2] / (grid[2] - 1)));
 
     const transform = Mat4.mul(Mat4.zero(), translation, scale);
-    Surface.transformImmediate(surface, transform);
-    Surface.computeNormalsImmediate(surface);
+    Mesh.transformImmediate(surface, transform);
+    Mesh.computeNormalsImmediate(surface);
     return { surface, field };
 }

+ 65 - 0
src/mol-geo/shape/mesh-builder.ts

@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2018 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 } from 'mol-math/linear-algebra';
+import { ChunkedArray } from 'mol-data/util';
+
+import Box, { BoxProps } from '../primitive/box';
+import { Mesh } from './mesh';
+
+type ElementId = { id: number }
+
+export interface MeshBuilder {
+    add(t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array): number
+    addBox(t: Mat4, props?: BoxProps & ElementId): number
+    getMesh(): Mesh
+}
+
+const tmpV = Vec3.zero()
+
+export namespace MeshBuilder {
+    export function create(initialCount = 2048, chunkSize = 1024): MeshBuilder {
+        const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, initialCount);
+        const normals = ChunkedArray.create(Float32Array, 3, chunkSize, initialCount);
+        const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, initialCount * 3);
+
+        // const offsets = ChunkedArray.create<number>(n => new Uint32Array(n), 1, 1000);
+        // const elementIds = ChunkedArray.create(Uint32Array, 1, chunkSize, initialCount);
+
+        ChunkedArray.compact(indices, true)
+
+        const add = (t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array) => {
+            const offset = vertices.elementCount * vertices.elementSize
+            for (let i = 0, il = _vertices.length; i < il; i += 3) {
+                Vec3.fromArray(tmpV, _vertices, i)
+                Vec3.transformMat4(tmpV, tmpV, t)
+                // Vec3.transformDirection(tmpV, tmpV, n)  // TODO
+                ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]);
+            }
+            // ChunkedArray.add(vertices, _vertices[i])
+            return offset
+        }
+
+        return {
+            add,
+            addBox: (t: Mat4, props?: BoxProps & ElementId) => {
+                const box = Box(props)
+                return add(t, box.vertices, box.normals, box.indices)
+            },
+            getMesh: () => {
+                return {
+                    vertexCount: vertices.elementCount,
+                    triangleCount: indices.elementCount,
+                    vertexBuffer: ValueCell.create(ChunkedArray.compact(vertices, true) as Float32Array),
+                    indexBuffer: ValueCell.create(ChunkedArray.compact(indices, true) as Uint32Array),
+                    normalBuffer: ValueCell.create(ChunkedArray.compact(normals, true) as Float32Array),
+                    normalsComputed: true,
+                }
+            }
+        }
+    }
+}

+ 48 - 52
src/mol-geo/shape/surface.ts → src/mol-geo/shape/mesh.ts

@@ -7,8 +7,10 @@
 import { Task } from 'mol-task'
 import { ValueCell } from 'mol-util'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
+import Sphere from 'mol-math/geometry/sphere'
+import { transformPositionArray } from '../util';
 
-export interface Surface {
+export interface Mesh {
     vertexCount: number,
     triangleCount: number,
     vertexBuffer: ValueCell<Float32Array>,
@@ -17,11 +19,11 @@ export interface Surface {
     normalsComputed: boolean,
 
     vertexAnnotation?: ValueCell<ArrayLike<number>>
-    //boundingSphere?: { center: Geometry.LinearAlgebra.Vector3, radius: number };
+    boundingSphere?: Sphere
 }
 
-export namespace Surface {
-    export function computeNormalsImmediate(surface: Surface) {
+export namespace Mesh {
+    export function computeNormalsImmediate(surface: Mesh) {
         if (surface.normalsComputed) return;
 
         const normals = surface.normalBuffer.ref.value && surface.normalBuffer.ref.value!.length >= surface.vertexCount * 3
@@ -58,8 +60,8 @@ export namespace Surface {
         surface.normalsComputed = true;
     }
 
-    export function computeNormals(surface: Surface): Task<Surface> {
-        return Task.create<Surface>('Surface (Compute Normals)', async ctx => {
+    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...');
@@ -68,20 +70,15 @@ export namespace Surface {
         });
     }
 
-    export function transformImmediate(surface: Surface, t: Mat4) {
-        const p = Vec3.zero();
-        const vertices = surface.vertexBuffer.ref.value;
-        for (let i = 0, _c = surface.vertexCount * 3; i < _c; i += 3) {
-            p[0] = vertices[i];
-            p[1] = vertices[i + 1];
-            p[2] = vertices[i + 2];
-            Vec3.transformMat4(p, p, t);
-            vertices[i] = p[0];
-            vertices[i + 1] = p[1];
-            vertices[i + 2] = p[2];
-        }
-        surface.normalsComputed = false;
-        //surface.boundingSphere = void 0;
+    export function transformImmediate(mesh: Mesh, t: Mat4) {
+        transformRangeImmediate(mesh, t, 0, mesh.vertexCount)
+    }
+
+    export function transformRangeImmediate(mesh: Mesh, t: Mat4, offset: number, count: number) {
+        transformPositionArray(t, mesh.vertexBuffer.ref.value, offset, count)
+        // transformDirectionArray(n, mesh.normalBuffer.ref.value, offset, count)  // TODO
+        mesh.normalsComputed = false;
+        // mesh.boundingSphere = void 0;
     }
 }
 
@@ -168,38 +165,37 @@ export namespace Surface {
 //         return computation(async ctx => await laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1));
 //     }
 
-//     export function computeBoundingSphere(surface: Surface): Computation<Surface> {
-//         return computation<Surface>(async ctx => {
-//             if (surface.boundingSphere) {
-//                 return surface;
-//             }
-//             await ctx.updateProgress('Computing bounding sphere...');
-
-//             const vertices = surface.vertices;
-//             let x = 0, y = 0, z = 0;
-//             for (let i = 0, _c = surface.vertices.length; i < _c; i += 3) {
-//                 x += vertices[i];
-//                 y += vertices[i + 1];
-//                 z += vertices[i + 2];
-//             }
-//             x /= surface.vertexCount;
-//             y /= surface.vertexCount;
-//             z /= surface.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);
-//             }
-//             surface.boundingSphere = {
-//                 center: LinearAlgebra.Vector3.fromValues(x, y, z),
-//                 radius: Math.sqrt(r)
-//             }
-//             return surface;
-//         });
-//     }
-
+    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;
+        });
+    }
 
 //     export function transform(surface: Surface, t: number[]): Computation<Surface> {
 //         return computation<Surface>(async ctx => {

+ 24 - 9
src/mol-geo/util.ts

@@ -4,9 +4,9 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Vec3 } from 'mol-math/linear-algebra'
+import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra'
 
-export function normalizeVec3array<T extends Helpers.NumberArray> (a: T) {
+export function normalizeVec3Array<T extends Helpers.NumberArray> (a: T) {
     const n = a.length
     for (let i = 0; i < n; i += 3) {
         const x = a[ i ]
@@ -19,12 +19,26 @@ export function normalizeVec3array<T extends Helpers.NumberArray> (a: T) {
     }
 }
 
+const tmpV = Vec3.zero()
+
+export function transformPositionArray (t: Mat4, array: Helpers.NumberArray, offset: number, count: number) {
+    for (let i = 0, il = count * 3; i < il; i += 3) {
+        Vec3.fromArray(tmpV, array, offset + i)
+        Vec3.transformMat4(tmpV, tmpV, t)
+        Vec3.toArray(tmpV, array, offset + i)
+    }
+}
+
+export function transformDirectionArray (t: Mat3, array: Helpers.NumberArray, offset: number, count: number) {
+    // TODO
+}
+
 export function setArrayZero(array: Helpers.NumberArray) {
     const n = array.length
     for (let i = 0; i < n; ++i) array[i] = 0
 }
 
-// iterate over the entire buffer and apply the radius to each vertex
+/** iterate over the entire buffer and apply the radius to each vertex */
 export function appplyRadius(vertices: Helpers.NumberArray, radius: number) {
     const v = Vec3.zero()
     const n = vertices.length
@@ -36,8 +50,10 @@ export function appplyRadius(vertices: Helpers.NumberArray, radius: number) {
     }
 }
 
-// indexed vertex normals weighted by triangle areas http://www.iquilezles.org/www/articles/normals/normals.htm
-// normal array must contain only zeros
+/**
+ * indexed vertex normals weighted by triangle areas http://www.iquilezles.org/www/articles/normals/normals.htm
+ * normal array must contain only zeros
+ */
 export function computeIndexedVertexNormals<T extends Helpers.NumberArray> (vertices: Helpers.NumberArray, indices: Helpers.NumberArray, normals: T) {
     const a = Vec3.zero()
     const b = Vec3.zero()
@@ -71,12 +87,11 @@ export function computeIndexedVertexNormals<T extends Helpers.NumberArray> (vert
         normals[ ci + 2 ] += cb[ 2 ]
     }
 
-    normalizeVec3array(normals)
+    normalizeVec3Array(normals)
     return normals
 }
 
-// vertex normals for unindexed triangle soup
-// normal array must contain only zeros
+/** vertex normals for unindexed triangle soup, normal array must contain only zeros */
 export function computeVertexNormals<T extends Helpers.NumberArray> (vertices: Helpers.NumberArray, normals: T) {
     setArrayZero(normals)
 
@@ -108,6 +123,6 @@ export function computeVertexNormals<T extends Helpers.NumberArray> (vertices: H
         normals[ i + 8 ] = cb[ 2 ]
     }
 
-    normalizeVec3array(normals)
+    normalizeVec3Array(normals)
     return normals
 }

+ 3 - 3
src/mol-geo/util/marching-cubes/algorithm.ts

@@ -7,7 +7,7 @@
 import { Task, RuntimeContext } from 'mol-task'
 import { ChunkedArray } from 'mol-data/util'
 import { Tensor } from 'mol-math/linear-algebra'
-import { Surface } from '../../shape/surface'
+import { Mesh } from '../../shape/mesh'
 import { Index, EdgeIdInfo, CubeEdges, EdgeTable, TriTable } from './tables'
 import { ValueCell } from 'mol-util'
 
@@ -23,7 +23,7 @@ export interface MarchingCubesParameters {
 
     annotationField?: Tensor,
 
-    oldSurface?: Surface
+    oldSurface?: Mesh
 }
 
 export function compute(parameters: MarchingCubesParameters) {
@@ -71,7 +71,7 @@ class MarchingCubesComputation {
         this.state.vertexBuffer = <any>void 0;
         this.state.verticesOnEdges = <any>void 0;
 
-        let ret: Surface = {
+        let ret: Mesh = {
             vertexCount:  this.state.vertexCount,
             triangleCount: this.state.triangleCount,
             vertexBuffer: this.parameters.oldSurface ? ValueCell.update(this.parameters.oldSurface.vertexBuffer, vb) : ValueCell.create(vb),

+ 20 - 1
src/mol-math/geometry/sphere.ts

@@ -1 +1,20 @@
-// TODO: rebranded vec4
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Vec3 } from '../linear-algebra'
+
+export interface Sphere {
+    center: Vec3
+    radius: number
+}
+
+export namespace Sphere {
+    export function create(center: Vec3, radius: number): Sphere {
+        return { center, radius }
+    }
+}
+
+export default Sphere