Introduction
I am currently working on an EM simulator for which I will need 3D visualisation capabilities. As usual I have decided to “overcomplicate” matters by using a very “unique” assortment of programming languages and libraries to do this (both for fun and to learn new things). Naturally, I want to use Rust for this project. This is not only because simulation software needs to extract as much performance from the hardware as possible, but also because I really appreciate Rust’s rich and rigid type system when building large projects as it helps keep things organised. And then there is the rich library ecosystem associated with Rust which usually comes in very handy but turns out to be somewhat limited in this particular case (at the time of writing). If easy library access were my primary factor under consideration, Python would likely be the best choice for this project.
My First Challenge
My first major obstacle was finding a sparse linear algebra library for use in Rust. This was not that difficult as there are many good looking options out there. Initially I used a combination of https://crates.io/crates/russell_sparse and https://crates.io/crates/sprs as that gave me a convenient enough way to build sparse matrices and solve sparse linear systems, but I quickly ran into a roadblock with this combination not having support for finding a limited number of eigenvalues.
After some research it turned out the Fortran library Arpack (or its more maintained fork https://github.com/opencollab/arpack-ng) is most commonly used to implemented this functionality (even in Matlab). Since I could not find a decent Rust wrapper for Arpack, I spent a very significant amount of time trying to implement a proper one myself. However, towards the end of this process I was not very comfortable with how awkward it turned out to be merging something from such a different era into something as oppinionated as Rust. The result just felt “off”.
This prompted me to again look around seriously for more modern alternatives. A notable mention here is https://slepc.upv.es/, but it seemed that would be similarly difficult to integrate and would likely also require using PETSc as my base linear algebra library. All in all this was not very attractive for integration with Rust either.
Thankfully, my new-found experience with Arpack taught me about the “shift invert method” which helped me to realise that the modern Rust library https://crates.io/crates/faer was already very close to offering the functionality I needed. Thus I created https://github.com/sarah-quinones/faer-rs/pull/233 with the final missing piece and have since ported my simulation code base to use faer.
Finally The VTK Challenge
There are many libraries for 3D visualition out there and even many Rust-native options. However, as far as I can tell, there is nothing out there that is quite as powerful and easy to use for visualising simulation data as https://vtk.org/. Thus, I was determined to use VTK. Since VTK is a C++ library and does not have Rust bindings, the easiest way to use it would be to write my visualisation code in C++. As someone who used to do that for a living, this idea does not bother me that much so I decided to go for it.
The thing is that VTK is not a full GUI libary and needs to be integrated with something else to build a full user interface. It is commonly integrated with Qt and there is therefore good native support for that. However, for various reasons, I was not excited to use Qt for this project and thus opted to leave that option as a last resort.
Initially I experimented with VTK’s wasm functionality to see if I could integrate it into a web-based GUI. This was attracitve as I have recently had good experiences building with https://svelte.dev/ and was not opposed to the idea of using it to build this GUI too. Of course, it would be a bit annoying to suddently need a whole client-server architecture and pass data between a Rust backend and Typescript front-end, but that also comes with advantages of course. I was particularly attracted by the idea of then not having to deal with the pain of building and packaging a native app for multiple platforms.
Unfortunately my experiments with VTK on wasm did not turn out as I hoped. It works, but the whole “emscripten” system used to compile C++ to wasm and then make WebGL look like normal OpenGL etc. just turned out to be way more hacky/fragile than I ever imagined it to be. It meant that doing anything slightly outside the scope of the demo apps would likely prove to be extremely difficult. Something as simple as trying to have multiple independent Svelte “widgets” powered by VTK is an example of something that turned out to be very challenging. And all of this becomes exponentially more complicated when you want to start having multi-threading which is an option I would really like to have available if needed. All in all I decided there was too much “funny business” involved here and that this pain was not worth my time.
Here it is worth noting that VTK also has a native JavaScript port (https://kitware.github.io/vtk-js/index.html) which would probably make integration with Svelte nearly trivial as compared to the wasm option, but I really don’t like the idea of such a heavy library being written in JS and therefore having to run with significantly reduced efficiency. I’m sure it works just fine on modern computers, but it just makes me a bit sad to use such an inefficient solution.
So eventually I decided to go the more interesting root and integrate VTK into a native Rust GUI library. For this, I somewhat arbitrarily chose https://github.com/emilk/egui as it seems like a fun and easy-to-use option. I am not convinced that its “immediate mode” architecture is the most efficient solution out there, but in my case the 3D part of the GUI would be the “heavy part”, so I was not too concerned with what I used for the 2D parts. I also like that eframe is one of the few professionally maintened options out there since it is backed by a company delivering commercial software based on it.
Conclusion
In the end it took much more effort than I bargained for, but I finally got this integration working and am proud to share the result as a template for others that is now available at https://github.com/Gerharddc/vtk-egui-demo/tree/main.
Comments
Comments are hosted on GitHub