K3D tools

Technical perspective

 

Artur Trzęsiok

Sage Days 74

CIAS, Observatoire de Paris, Meudon

Technology stack

  • ThreeJS (15.000+ commits)
  • Travis
  • Grunt tool
  • Karma runner
  • Pako
  • Json-patch
  • Vagrant + Puppet
  • Bower/NPM

Project decomposition

K3D standalone

K3D jupyter

  • ThreeJS as abstraction layer to WebGL
  • Viewer for internal json-based format
  • Package delivered as Bower/NPM module with semantic versioning
  • E2E testing done on screenshot level
  • Based on IPython widgets
  • Internal communication Based on json-patch format
  • Based on NumPy package
  • Provide high-level function that will produce json format for K3D standalone

Library details

  • Size: 2.5 MB
  • Proof of concept -
    3 months of development
  • Low level Javascript performance improvements
    • TypedArray
    • Avoid prototype
    • Flat structure
  • High level performance improvements
    • Greedy Mesh
    • Octree
    • etc.
  • Every object generator as plugin
    • Line
    • Marching Cubes
    • Points Clouds
    • STL
    • Surface
    • Text
    • Texture
    • Vectors
    • Vectors Field
    • Voxles

Culled Mesh

Greedy Mesh

Performance over readability

    for (y = 0, i = 0, p = 0; y < height - 1; y++) {
        for (x = 0; x < width - 1; x++, p++, i += 18) {
            // Performance over readability
            vertices[i] = vertices[i + 9] = x / (width - 1);
            vertices[i + 1] = vertices[i + 10] = y / (height - 1);
            vertices[i + 2] = vertices[i + 11] = heights[p];

            vertices[i + 3] = vertices[i + 15] = (x + 1) / (width - 1);
            vertices[i + 4] = vertices[i + 16] = (y + 1) / (height - 1);
            vertices[i + 5] = vertices[i + 17] = heights[p + 1 + width];

            vertices[i + 6] = (x + 1) / (width - 1);
            vertices[i + 7] = y / (height - 1);
            vertices[i + 8] = heights[p + 1];

            vertices[i + 12] = x / (width - 1);
            vertices[i + 13] = (y + 1) / (height - 1);
            vertices[i + 14] = heights[p + width];
        }

        //skip last column
        p++;
    }

Communication scheme

Browser

Python

plot = K3D()
field = K3D.marching_cubes(field, level=0.8)
plot += field
plot.display()

Send K3D browser widget

Send and store internal json data

Load K3D standalone widget + small helper to dispatch Jupyter commands

Display object + store json

field.color = 0xFFFF00
  1. Update Python object
  2. Compute new exported json
  3. Compute difference beetwen new and stored version
  4. Send difference (json-diff format)
  1. Apply patch on stored json
  2. Update scene

Example internal json

{
   "metadata" : {},
   "objects" : [{
         "type" : "Line",
         "modelViewMatrix" : [
            1.5, 0.0, 0.0, 1.5,
            0.0, 1.5, 0.0, 0.0,
            0.0, 0.0, 1.5, 0.0,
            0.0, 0.0, 0.0, 1.0
         ],
         "color" : 16711680,
         "pointsPositions" : [
            -3.0, 2.0, 0.0,
            -1.0, 2.0, 0.0,
            -1.0, 1.0, 0.0,
            -2.0, 0.0, 0.0,
            -1.0, 0.0, 0.0,
            -1.0, -2.0, 0.0,
            -3.0, -2.0, 0.0
         ]
      }, {
         "type" : "Line",
         "pointsPositions" : [
            1.0, 2.0, 0.0,
            2.0, 2.0, 0.0,
            3.0, 1.0, 0.0,
            3.0, -1.0, 0.0,
            2.0, -2.0, 0.0,
            1.0, -2.0, 0.0,
            1.0, 2.0, 0.0
         ]
      }
   ]
}

Example internal json

{
   "metadata" : {},
   "objects" : [{
         "type" : "Line",
         "modelViewMatrix" : [
            1.5, 0.0, 0.0, 1.5,
            0.0, 1.5, 0.0, 0.0,
            0.0, 0.0, 1.5, 0.0,
            0.0, 0.0, 0.0, 1.0
         ],
         "color" : 16711680,
         "pointsPositions" : "AABAwAAAAEAAAAAAAACAvwAAAEAAAAAAAACAvwAAgD8AAAAAAAAA
                              wAAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAMAAAAAAAABAwAAA
                              AMAAAAAA"
      }, {
         "type" : "Line",
         "pointsPositions" : "AACAPwAAAEAAAAAAAAAAQAAAAEAAAAAAAABAQAAAgD8AAAAAAABA
                              QAAAgL8AAAAAAAAAQAAAAMAAAAAAAACAPwAAAMAAAAAAAACAPwAA
                              AEAAAAAA"
      }
   ]
}

Example json patch
(rfc 6902)

[
  { "op": "replace", "path": "/baz", "value": "boo" },
  { "op": "add", "path": "/hello", "value": ["world"] },
  { "op": "remove", "path": "/foo"}
]

K3D

By Artur Trzesiok

K3D

  • 1,045