Trouble uniquely identifying a Mesh

rhinocommon
unhandled

(Alonso Rosado) #1

Hello all!

This is kind of a silly question but please bear with me. What is the way to uniquely identify a mesh within the scene?

I was delving into using the ChangeQueue when I found “three” (depends on wether you consider a RhinoObject geometry or not) different kinds of representation of geometry that are used: Mesh, MeshInstance and RhinoObject.

To identify each one, intially it would seem relatively easy. A RhinoObject has a single GUID associated to it that is unique! So far so good. Also, it would seem that the MeshInstance has two values to properly identify it: The MeshId, which “allegedly”(later on explained) identifies the mesh instanced, and the InstanceId, which is an unsigned int that identifies the number of said instance.

But, when I try to identify a Mesh, the documentation states:

Id Get the Object Guid this mesh is for.

Does this mean that a Mesh.Id returns the Id of the Object to which the mesh is associated? If that is so, would that mean that the mesh has no means of getting an unique Identifier? I say this because a RhinoObject may have several meshes associated to it, as per the logic of GetMeshes() being plural and returning a Mesh[]. That would mean that no mesh is uniquely identified, which I find confusing. This also translates to the MeshInstance documentation, that states the same in the MeshId:

MeshId Get the Object Guid this mesh is for.

Sorry if I’m being a bit dense, as realise that this might be referring to a Guid associated to the more general C#'s Object class, but I still can’t find anything resemblig to a Guid associated to it within the Microsoft’s MSDN documentation.

Oh, and while we are at it , would someone mind explaining to me how are the MeshInstance.InstanceId integer identifiers are set? Do they represent the number of instances of a unique mesh (and thus are repeated if more than one object has instances in the scene) or the more general number of defined instances in the scene.

Thank you in advance.

Alonso


(Nathan 'jesterKing' Letwory) #2

FYI I’ll be typing explanatory text regarding this tonight and tomorrow.

While I do the typing you could check the code for the Raytraced integration to see if it opens up the usage for you:


(Alonso Rosado) #4

@nathanletwory, thank you kindly for the swift answer :blush:.
I will revise the code in depth asap. And also, thank you in advance for the explainatory text, I’ll be looking forward to it.


(Nathan 'jesterKing' Letwory) #5

The main geometry you get is the Rhino.Render.ChangeQueue.Mesh. The Id() from the Mesh is there to identify this mesh, and as you noticed the mesh may contain multiple mesh parts. Each of this part is uniquely identified by combining the ID and the mesh index. Mesh data is given through ApplyMeshChanges.

The mesh data on its own is only half of the story. For regular objects you could just push that data to your render engine and be done with it, but the interesting part is what you get in ApplyMeshInstanceChanges. For normal objects you’ll find that you get only one instance. The MeshInstance.MeshId indeed corresponds to Mesh.Id(), and the MeshInstance.MeshIndex is the rank of the mesh part from Mesh.

For objects that have sub-object materials applied you’ll find you get more than one mesh instance signalled. Indeed, you’ll have received several mesh parts for such an object in ApplyMeshChanges. As a test do this with a simple box, subselect one face and add only to it a material. You’ll see you get multiple mesh parts for the Mesh data of that box. You’ll also see you get more than one MeshInstance to build that object - one for each mesh part.

It becomes even more interesting when you have block instances in your scene. Add a simple box, create a block out of it, and copy the new block instance several times in your scene. You should see only the one Mesh, but as many MeshInstances as copies of your block instance. You’ll find that the MeshInstance.MeshId corresponds to the Mesh.Id(), and the MeshInstance.MeshIndex accordingly to the mesh part index (especially clear if you used the box with the one sub-object material). This should allow you to do instancing in your render solution (or for whatever use you have chosen the ChangeQueue mechanism :slight_smile: ).

The MeshInstance.InstanceId is a unique identifier for that particular instance. Although not important it is a CRC of related Guids and the mesh index. Point is that it is unique and a fast datatype for you to use.

I hope the text makes sense when you also look at the linked code from RhinoCycles.

Let me know if you find this still unclear, or if you have more questions regarding the topic.

/Nathan


(Alonso Rosado) #6

@nathanletwory, thank you kindly for your time! The explaination is crystal clear and just what I needed.


(Alonso Rosado) #7

Hello @nathanletwory,

related to this, I’ve been delving in what would be an Import/Export to an external software process and I’ve found that the geometry, (in the particular case I’m using, the Mesh) provided by the Changequeue is different from the one you can get from the RhinoDoc.

What I mean to ask is, how should I proceed to uniquely identify a mesh, object, instance, etc in both the changequeue and the RhinoDoc simultaneously?

Thanks in advance,

Alonso.

Edit: To clear this up, Im trying to use a single string identifier to unambiguously identify an element in the scene, be it through the changequeue or accessing the tables in the Document, setting certain parameters in an intermediate structure.


(Nathan 'jesterKing' Letwory) #8

In what way are they different from each other?

Does this mean you’re looking to use custom user data on objects?


(Alonso Rosado) #9

Not exactly, let me explain better.

The Mesh that you obtain from the changequeue has an unique Id of its own, as in this:

In its structure, its very similar to what a RhinoObject would be. On the other hand, the Geometry based Mesh has not an unique Id, and thus this confuses me a bit.

Regarding the custom data, the thing is that I’m trying to have a parallel scene structure, which means I’d like to embed as few data as possible within the rhino objects, though it may be necessary in the end, at least to host the identifiers.


(Nathan 'jesterKing' Letwory) #10

Perhaps the Id() is a misnomer and it should’ve really been called ObjectId (and as a property, at that). The Guid returned from that is not the Mesh identifier, but instead it is the object identifier. The Id identifies the object the mesh is for.


(Alonso Rosado) #11

Yeah, that clears the issue quite a bit :sweat_smile:. Sorry if I’m being a bit dense and thanks for your attention again @nathanletwory.


(Nathan 'jesterKing' Letwory) #12

That’s ok. Keep the questions coming, it can be a learning process. It after all took several years to stich this system together!

If you run into other issues, but not related to identifying meshes, please don’t forget to start a new thread topic :slight_smile:


Is it feasible to calculate the Render Queue MeshInstance's ID from a Rhino Doc
(Alonso Rosado) #13

Will do! :+1:


(Alonso Rosado) #14

Recently, I’ve been trying to mount a system based on the conclusion @nathanletwory and I reached here, but the trouble I’m facing is related to this post.

Let’s put an example. I wan’t to modify data on InstanceBox1. InstanceBox1 has been generated within my parallel structure with the name “Instance_” + <InstanceId> using the ChangeQueue’s ApplyMeshInstanceChanges provided data, thus, the MeshInstance data.

If I generate a command that takes the selected objects from the screen, and, for example, wants to change some data associated to said objects within my parallel structure, the data available are not those from the ChangeQueue, but data from the RhinoDoc, the only source from which I can identify which objects are selected in the viewport. And, if the selected objects are instances, there seems to be no way to uniquely associate the results obtained from a ChangeQueue to the possible results obtained from a RhinoDoc. I thought of associating userdata to each instance, but said user data are seemingly not accessible from the ChangeQueue.

This means that from the RhinoDoc there is no way I can ascertain which parallel structure im referring to…

I thought of using a similar structure to what @nathanletwory did in RhinoCycles plugin:

/// <summary>
/// Record what meshinstanceid (objectid) points to what meshid
/// </summary>

private readonly Dictionary<uint, Tuple<Guid, int>> _rhObjectidMeshid = new
Dictionary<uint, Tuple<Guid, int>>();

But, the objectid contained within the meshinstanceID, though unique, is not directly the Guid of said object in structures.

What I mean is, is there a way to have available at the same time the id of the instance in RhinoDoc and the one provided from the ChangeQueue? This way i could build something similar to the dictionary that @nathanletwory did and solve this problem.


(Nathan 'jesterKing' Letwory) #16

@alonso.rosado, I am asking @andy, who may have some ideas regarding this.


(Alonso Rosado) #17

Thanks @nathanletwory, sorry for the insistance over this issue. I’m grateful you are bearing with me.


(Nathan 'jesterKing' Letwory) #18

Hey there, I just realized that it is already possible to access userdata attached to geometry objects, even through the ChangeQueue. I actually use this to tag objects as cutting volumes for Raytraced cutout support ( essentially a generalised form of clipping planes). I tag an object with custom user data, and in my ChangeQueue implementation I override ProvideOriginalObject, returning true.

Once you start returning true from ProvideOriginalObject you’ll find that ChangeQueue.Mesh will have its Attributes property populated. This gives you access to ObjectAttributes, which will carry any of the user data that is attached to the original objects Attributes.

This means you can also find the ObjectId of the original object, and much more.

Accessing the ObjectAttributes in ChangeQueue.ApplyMeshChanges():

Attaching custom user data to an objects’ Attributes:

The custom user data for this case:


(Alonso Rosado) #19

Well thank you @nathanletwory!

This is quite a lot of info, so It’ll take some time , but its hightly probable that Im able to get a workaround going with this! I’ll let you know what happens.

Thanks,

Alonso


(Alonso Rosado) #20

@nathanletwory, I’ve been analysing your proposed solution and, while it opens possibilities to several features regarding RhinoObjects per se, when dealing with instances it still doesn’t allow several things.

The MeshIntance given info is somewhat limited.

As far as we’ve discussed, the MeshInstance InstanceId is a CRC of several data of the instance, and while it’s unique, it doesn’t allow for identification when, for example, I want to use the selected objects on the viewport to define some settings on the parallel structure for the required objects.

For example:

var selected = doc.Objects.GetSelectedObjects(false, false);

This returns the selected RhinoObjects, which easily may ot may not be instances.It can be checked doing:

public static bool IsInstance(RhinoObject obj)
{
return obj != null && obj.ObjectType == Rhino.DocObjects.ObjectType.InstanceReference;
}

Even if I were to use the way of obtaining an InstanceObject shown here:

var iref = objref.Object() as Rhino.DocObjects.InstanceObject;

I would not be able to bond easily said object to the info given to me by MeshInstance, simply because the only common ground is the transform.

This wouldn’t be a problem if each instance provided by the changequeue were to have its own UserData, as I could simply use those to set the data necessary for identification within.

Right now, this means I cannot use the ChangeQueue to populate my parallel structure, because if I were to try and modify something, if it were not to be modified from the changequeue, I wouldn’t be able to properly identify it.

Also, while we are at it, I’m wondering which would be an adequate place to initiate a changequeue that keeps track of the changes in a doc while there’s no render engine.

Thanks in advance,

Alonso


(Nathan 'jesterKing' Letwory) #21

Right, Attributes on a MeshInstance would indeed very useful. Logged as: RH-45700

I didn’t really test the idea, but I suppose you could start a queue in a command, disconnected from any rendering engine. I suggest you try instantiating a change queue from a command with the active view for the given document.