Browse Source

improved ply to mesh conversion

Alexander Rose 6 years ago
parent
commit
41bf52bceb
2 changed files with 42 additions and 8 deletions
  1. 3 0
      src/mol-io/reader/ply/parser.ts
  2. 39 8
      src/mol-model-formats/shape/ply.ts

+ 3 - 0
src/mol-io/reader/ply/parser.ts

@@ -11,6 +11,9 @@ import { Tokenizer, TokenBuilder, Tokens } from '../common/text/tokenizer';
 import { Column } from 'mol-data/db';
 import { TokenColumn } from '../common/text/column/token';
 
+// TODO add support for binary ply files
+// TODO parse elements asynchronously
+
 interface State {
     data: string
     tokenizer: Tokenizer

+ 39 - 8
src/mol-model-formats/shape/ply.ts

@@ -97,9 +97,8 @@ function createPlyShapeParams(plyFile?: PlyFile) {
 export const PlyShapeParams = createPlyShapeParams()
 export type PlyShapeParams = typeof PlyShapeParams
 
-async function getMesh(ctx: RuntimeContext, vertex: PlyTable, face: PlyList, groupIds: ArrayLike<number>, mesh?: Mesh) {
-    const builderState = MeshBuilder.createState(vertex.rowCount, vertex.rowCount / 4, mesh)
-    const { vertices, normals, indices, groups } = builderState
+function addVerticesRange(begI: number, endI: number, state: MeshBuilder.State, vertex: PlyTable, groupIds: ArrayLike<number>) {
+    const { vertices, normals, groups } = state
 
     const x = vertex.getProperty('x')
     const y = vertex.getProperty('y')
@@ -112,17 +111,17 @@ async function getMesh(ctx: RuntimeContext, vertex: PlyTable, face: PlyList, gro
 
     const hasNormals = !!nx && !!ny && !!nz
 
-    for (let i = 0, il = vertex.rowCount; i < il; ++i) {
-        if (i % 100000 === 0 && ctx.shouldUpdate) await ctx.update({ current: i, max: il, message: `adding vertex ${i}` })
-
+    for (let i = begI; i < endI; ++i) {
         ChunkedArray.add3(vertices, x.value(i), y.value(i), z.value(i))
         if (hasNormals) ChunkedArray.add3(normals, nx!.value(i), ny!.value(i), nz!.value(i));
         ChunkedArray.add(groups, groupIds[i])
     }
+}
 
-    for (let i = 0, il = face.rowCount; i < il; ++i) {
-        if (i % 100000 === 0 && ctx.shouldUpdate) await ctx.update({ current: i, max: il, message: `adding face ${i}` })
+function addFacesRange(begI: number, endI: number, state: MeshBuilder.State, face: PlyList) {
+    const { indices } = state
 
+    for (let i = begI; i < endI; ++i) {
         const { entries, count } = face.value(i)
         if (count === 3) {
             // triangle
@@ -133,6 +132,38 @@ async function getMesh(ctx: RuntimeContext, vertex: PlyTable, face: PlyList, gro
             ChunkedArray.add3(indices, entries[2], entries[0], entries[3])
         }
     }
+}
+
+async function getMesh(ctx: RuntimeContext, vertex: PlyTable, face: PlyList, groupIds: ArrayLike<number>, mesh?: Mesh) {
+    const builderState = MeshBuilder.createState(vertex.rowCount, vertex.rowCount / 4, mesh)
+
+    const x = vertex.getProperty('x')
+    const y = vertex.getProperty('y')
+    const z = vertex.getProperty('z')
+    if (!x || !y || !z) throw new Error('missing coordinate properties')
+
+    const nx = vertex.getProperty('nx')
+    const ny = vertex.getProperty('ny')
+    const nz = vertex.getProperty('nz')
+
+    const hasNormals = !!nx && !!ny && !!nz
+    const updateChunk = 100000
+
+    for (let i = 0, il = vertex.rowCount; i < il; i += updateChunk) {
+        addVerticesRange(i, Math.min(i + updateChunk, il), builderState, vertex, groupIds)
+
+        if (ctx.shouldUpdate) {
+            await ctx.update({ message: 'adding ply mesh vertices', current: i, max: il })
+        }
+    }
+
+    for (let i = 0, il = face.rowCount; i < il; i += updateChunk) {
+        addFacesRange(i, Math.min(i + updateChunk, il), builderState, face)
+
+        if (ctx.shouldUpdate) {
+            await ctx.update({ message: 'adding ply mesh faces', current: i, max: il })
+        }
+    }
 
     const m = MeshBuilder.getMesh(builderState);
     m.normalsComputed = hasNormals