I am currently in the process of developing an Augmented Reality Unity-App which is intended to render models which have previously been created in BIM/CAD software. Whilst a direct export/import of such objects is easily done thanks to the utilities provided by the Speckle Ex- and Importers, the given BIM/CAD Data can get to an excessive size for the given AR environment.
Whilst the solution is clearly to render only the relevant models (for the current perspective/location) from a single commit, there are 2 ways to go about it - either all model data is loaded beforehand using the Unity-Importer, and a selection of “relevant objects to render” is done within the unity application, or only the relevant “objects to render” are requested from the server in the first place to reduce download size. In this context, I was wondering if there is an established way to request only parts of the object data saved in a single commit.
My first thought was to export what is essentially a bounding box from unity which may be compared against the displayView given in the object, in a sense that “anything within bounding box XY” is then exported to unity. Is there a way to (e.g.) use the GraphQL queries to request object’s geometry in a format compatible to three.js for this kind of comparison?
Thanks for any input in advance, I realize this is a rather specific topic and may not be fully solved in a single post like this
This should be entirely possible - with some caveats.
The Speckle Server can deliver data partially according to the criteria you define. This is because there is full support for GraphQL querying - designed for this scenario.
However, this is limited to making queries filtering to data properties.
The tricky part would only be what you define as relevant content. I haven’t explored making the queries filter to a geometric location based on a bounding box, but it may be possible with compound filters TBD.
I may give this a play, in the meantime, because you have full access to the Speckle Core operations, take a look at some other examples of commit data filtering:
thanks for the lightning fast reply! I’ll definetly give the provided links a read . For now, let me formulate my question a bit more precisely, since I’ve already “played” a bit with the GraphQL queries.
I do already have the geometry/location/coordinates of a “box” in unity which serves as a marker for “relevant” data - anything within it would count as “relevant”.
My question now is how i would design a query which delivers the origin/location of an object in a specific commit? I’m still very new to speckle itself and haven’t really worked with the way it stores the transform/geometry data for a given object. Correct me if I’m wrong, but as far as my understanding goes, the contents of the “transform” property (matrix), especially index 3,7,11 hold the origin of a given object.
The last step would then be to query for / use the connector to import only the objects i have confirmed to be “in my box”, or, well, get access to their mesh data, which still eludes me until now Does the unity connector already have built-in requests for singular objects from a commit, or will i have to “steal” some code from it to build my own?
Sorry for the delay. I was investigating where we are at.
While the transform object can 100% be query-filtered by compound filters on the resultant in GraphQL that could be useful, this is only half the story. We apply transforms to Instances which, in turn, have definition objects. The transforms will have been made from A point relative to the position of the definition object. That point could be at the end of a very large object.
What I think would make your quasi-spatial query easiest would be if the bounding box representation of the definition was transformed and present on the instance. We do not do this right now, but it is food for thought, given this use case.
Whilst the previous questions were a bit out there, I’ve gotten to a more concrete implementation idea of where i wanna go with this. Setting so far:
The initial commit comes straight from Revit
Bounding Box / Area that’s relevant for me is provided by Unity
Provided slightly adjusted Unity Speckle Connector is present with which i can import by (Reference) ID of single Objects
Tested first GraphQL queries straight from Unity via fitting plugin
Familiarized myself a bit more with the GraphQL Queries
Whilst testing some queries with my given Revit commit, i noticed that most data has to be accessed via consecutive Queries given that the first Query will only provide me with a reference ID - which in turn has to be given into another query which then accesses the data stored in a given object within my commit. Whilst this allows me to address single objects directly, i still sadly cannot properly query by “transform” property or something similiar, since all of this data is saved within… funnily enough, the “data” JSON property, in which GraphQL (to my knowledge) can’t read single fields.
Going via “@Types” or the “elements” array, i can access all objects sorted in a manner similar to how they’re sorted within unity post-import, and after 2 more Queries i can get to a point where i have the Revit-Definition data of a single object, whilst the large Vertice/Datachunk parts of their data is still only referenced.
This way, during the selection process, no full meshes/vertice groups have to get downloaded to unity itself. Instead, i could make use of the descriptive Revit Properties (depending on the speckle type) to build simple box colliders for each object - essentially building a mini-importer that completely ignores the meshes provided by speckle, yet building a selection of colliders to check my boundingBox against.
Once this check is done (and i cleaned the scene of the colliders), I could simply make use of the (Reference) IDs I got from the earlier GraphQL requests to only import those objects that were contained within the bounding box.
Writing this all down makes it sound like a rather unhinged way to save on some Megabytes, but for a mobile AR App and massive Revit models this might be a saving grace . Is there any rather obvious mistakes or unnecessary steps you can spot?
You are correct that the Instance/Definition relationship doesn’t propagate as per straightforwardly detached objects, so recursive queries are necessary.
At some point, GraphQL hits its limits as a spatial querying tool.
One thing that has come to my mind is that if this activity is recurrent, you could have automation triggered on a new commit to a Project stream that runs a Python script to perform spatial indexing and write that back to Speckle. The Unity app could then interface not with raw Revit data but with a fit-for-purpose one that can be accessed with optimised querying.
We have a lot to explore in this area to make words into understandable action, but working on “live” data will always have its benefits as much as benefits.
A flat list of objects, spatially indexed that is kept up to date with BIM data coming out of authoring tools sounds like a good fit for your purposes.
Welp, maybe it’s time to get into learning Python towards the end of the project, but for now that’s a bit out of the scope of my work… great idea to move this recurrent “conversion” process to a separate call though so it only has to run once!
GraphQL queries and filtering have been finished, all required data is present in the program for the “bounding box” comparison, and the first iteration of the program is almost ready to go. I ran into a rather small issue on the final stretch though - I realized I’ve been making use of the SpeckleReceiverEditor.cs (or, well, its “receive!” button) in my testing runs for importing singular objects from a commit via their ID (i more or less just exchanged the objectId parameter within the ReceiveAsync function).
Now, however, I’m obviously trying to move away from the editor - and have failed to find a way to properly start my own receive request with the SpeckleReceiver.cs. Is the “ReceiveAndConvert_Routine” not the correct place to start? And am I missing some doucmentation on the topic?
Assuming you simply want to match the behaviour of clicking the receive in the inspector, you can do this quite simply by starting ReceiveAndConvert_Routine as a coroutine like so:
var speckleReceiver = GetComponent<SpeckleReceiver>();
If you’d prefer not to use Coroutines, you can also use ReceiveAndConvert_Async instead, however you would need to ensure it runs on the Unity thread, and the entire receive will all happen on a single frame. So coroutines are normally preferred for runtime receives.