Open vinnividivicci opened 1 year ago
Well, I think it's important to separate some things regarding performance.
Instead of hacking this into three js I'd rather work with https://github.com/opensourceBIM/BIMsurfer/ While not very actively maintained, it is designed from scratch with large bim models in mind. Which isn't so hard when using some of the modern webgl2 api calls. It also has a couple of nice features such as section planes, measurement and cad-friendly orbit. You can try it online at https://view.ifcopenshell.org/ when you toggle rendering engine.
Hi @aothms and thanks for taking the time to reply in such detail, it has helped me make my thoughts clearer.
Of the three things you mentioned, the main one I would like to target is the second: Loading time.
Right now, with the Wasm-preview demo, it takes 45 seconds to load a 10Mb IFC file (I profiled it using the Chrome dev tools). The same model takes 15s to load in IFCjs (but with more errors...).
How do you think this parsing and geometry generation step can be sped up to similar speeds to IfcJS?
Based on the code and the profiler, it seems to me like we are doing a lot of back-and-forth calls from JS/Pyodide to Wasm and back over and over again:
Compared to IFCjs:
So, in my mind: if the IfcOpenShell WASM was able to, with one function call, output/return an entire model/object of the complete IFC file in a format compatible with ThreeJS (doing this in much faster compiled code), then we would have a "drop-in" replacement (or compatible library...) for IFC.js.
Cool insights from profiling. I'd be tempted to think the problem is not so much the per-mesh creation, but the way we go in C++ from (a) native array (b) sequence of python floats (c) sequence of javascript floats (d) javascript typed array. It looks trivial in code [0], but there is a lot of unnecessary back and forth. Also creating submeshes based on the material idxs doesn't help [1] of course.
[0] https://github.com/IfcOpenShell/wasm-preview/blob/master/index.html#L172 [1] https://github.com/IfcOpenShell/wasm-preview/blob/master/index.html#L189
So we need to look into [2] and [3] to seemlessly get the C++ buffers accessible in JS wasm as typed arrays.
[2] https://pyodide.org/en/0.16.1/type_conversions.html#typed-arrays [3] https://www.swig.org/Doc1.3/Python.html#Python_nn75
It seems that is a prerequisite anyway. If after that it is still obviously slow, we can (optionally) concatenate these buffers on the C++ side.
Thoughts?
I think you may be on to something. I dug deeper into the profiling and took a 24ms long section of a pattern that seems to repeat over-and-over. Of that 24ms section, at least 50% of the time (likely higher since at one point I stopped counting) is spent on wasm-to-js and js-to-wasm functions. Here are some of them circled:
However, I'm not sure how to optimize it in our JS/HTML example and if it's even realistic to think that going from js -> pyiodide wasm -> js -> ifcopenshell wasm -> js ... will ever be very efficient. Wouldn't have all the heavy lifting done in the IfcOpenShell WASM and returned as geometry + data that ThreeJS or BIMSurfer can use make more sense?
To be honest I don't understand this callstack very well. IntTools_FaceFace
and IntPatch_Intersection
are both opencascade methods calling each other, deeply in the processing of geometric entities, why would there be this js-to-wasm
in between?
It would be cool if we can annotate this profiling run with the various "events" that occur during page load, such as parsed ifc model, geometric tesselation computed, webgl representation created. So that we have a better understanding of the spacing between these events.
I've attached the trace created using Google Chrome Dev Tools in case you want to load it and explore: Trace-20230731T162030.zip
The trace starts after all the WASMs are loaded and just before I click on "load" which starts loading the model:
I'm not familiar enough with the lower-level function calls to tell where the transition from parsing to geometry creation happens.
Hello @aothms,
I have a question that's been bouncing around in my head for a while: is it currently possible (or how much work would it be...) to have the IfcOpenShell WASM generate one single mesh (or multiple) without having to iterate in javascript over the entire model and create unique meshes (which is very slow)?
If I understand correctly, this would be a similar approach to how IFC.js loads the model into ThreeJs. They have the heavy lifting of generating the mesh done by the WASM which spits out one mesh that is then loaded into the ThreeJs scene and then use subsets to turn things on and off.
I think this would be an interesting direction to take the IfcOpenShell WASM in the short term since it would make it into a possible alternative IFC loader for ThreeJs. I like the work IFC.js is doing but IfcOpenShell is a more mature API in my opinion and it's always good to have options 😃
Thanks for your time!