Back to projects

Personal project · C++ and WebGL

3D Analyzer — Mesh inspector with a C++ engine

Quoting a part for manufacturing means measuring it. I built a tool that reads the 3D file, computes the mesh's real volume and estimates the material needed.

  • C++
  • Vue 3
  • Three.js
  • WebGL

Context

A personal project, built alone. Computation engine in native C++, interface in Vue 3 with Three.js.

The problem

An STL or OBJ file of a real part has tens or hundreds of thousands of triangles. Processing that in JavaScript, on the browser's main thread, freezes the interface — and an interface frozen during a calculation looks broken.

But the bigger problem was not speed. It was that the number was wrong.

Technical decisions

  1. Two processes, two languages

    The C++ engine handles geometry — it loads the mesh, walks the triangles, computes volume and area. Vue handles what the browser is good at: a reactive interface and WebGL rendering through Three.js. Each side does what it does best. The cost is real and large: the application stops being portable, stops running in a browser alone, and requires compilation before it starts. To ship it to users this would be the wrong call. For a local analysis tool it is the right one — and it is the one that taught me the most.

  2. Volume by the divergence theorem, not the bounding box

    The first version computed volume by multiplying the three dimensions of the box around the part. It is simple, it is fast, and it is wrong for anything that is not a cuboid: a sphere cost the same as the cube containing it. I replaced it with the divergence theorem applied to the mesh triangles, accumulated in the same pass that was already reading the file. The calculation went from the volume of the space the part occupies to the volume of the part itself.

  3. A number that tells you whether the other one can be trusted

    The divergence theorem assumes a closed mesh. A mesh with holes still returns a value, and that value can even be correct by accident. I began accumulating the sum of the area vectors as well — the closure residual — in the same pass. If the mesh is watertight the residual is effectively zero; if it is not, the residual gives it away. The tool stopped returning just a number and started saying whether that number can be trusted.

  4. Streaming STL parsing, with constant memory

    STL files are walked triangle by triangle, accumulating results as the read progresses, instead of being loaded into memory whole. Consumption stops depending on file size: a two-hundred-megabyte part uses the same memory as a two-megabyte one.

  5. Explicit GPU memory management

    Three.js does not automatically free the GPU memory of meshes and materials that leave the scene — the JavaScript garbage collector knows nothing about VRAM. An application that loads models in sequence without disposing of the previous ones accumulates memory until it slows down and dies, and the error surfaces far from its cause. I explicitly dispose of the old meshes and materials before each new model.

What went wrong

The volume was wrong from the start, and nobody would have noticed by looking at the interface. A bounding box always gives a plausible number — it is only the right number when the part is a cuboid. For a sphere, the box gives nearly twice the real volume.

I only caught it by comparing the result against a part whose volume I already knew. And once I had fixed it, I realised there was a second problem underneath: the new formula assumes a closed mesh, and nothing in the program checked for that. A part with a hole would still return a normal-looking number.

The fix for both turned out to be the same pass over the file: volume and closure residual are accumulated side by side, and the second qualifies the first.

I wrote two tests that exist only for this: they prove that volume changes when the part is moved through space, and that the residual does not. If anyone ever swaps the formula for one that depends on position, the tests catch it.

Outcome

A working tool, with 34 tests compiled against the real engine. It reads STL and OBJ, computes volume, area and triangle count, renders the model in WebGL and exports to PDF and Excel.

What I'd do differently

I would have split App.vue much earlier. It runs to one thousand seven hundred lines and grew by accumulation, because every new feature was faster to add there than to separate out. Today it is the file that costs the most to change — and the price of letting it grow is higher than splitting it halfway would have been.

Back to projects