Color Mesh Faces (No Bleeding) - Best Practice?

rhinocommon
grasshopper
python

#1

Hi All,

I’m revisiting some old code for coloring mesh faces (without them bleeding into each other!), and feel like I might be missing something here. The basic approach I’ve been using is to:

  1. Unweld the mesh, or, make a new mesh and append the faces onto this.
  2. Color the face corners of this now unwelded mesh.

Now this approach works just fine.

But both unwelding and setting the colors are pretty heavy processes (at about 280 and 140 ms respetivley in this case). So I am looking to speed this up a bit, and wondering if there might be better/faster overall approaches that I am missing?

Leading me to: At least sitting setting the colors can be sped up by calling MeshVertexColorList.SetColor, however this only appears to set one corner on fully unwelded meshes (but is substantially faster than setting each corner individually):

While it works as expected on a welded mesh (but of course with colors bleeding across faces):

And yes, I do realize that writing a compiled C# component (or, eww, a C++ plugin), or threading etc. can speed things up. But I’m asking what I might be missing in terms of the base logics here, and perhaps, also pointing out a bug (i.e. MeshVertexColorList.SetColor) and/or features that might be missing in RhinoCommon.

Best,

Anders


#2

Hi @AndersDeleuran,

i do use the unweld trick too. To set the colors faster i built them threaded and the thread writes to a preallocated list using indices. The colors can be set in one go using MeshVertexColorList.SetColors. It is faster than doing it one by one.

_
c.


#3

Cheers Clement, setting the colors in one go is a really good idea.

I ended up going with a slightly different approach than the ones above (basically: make an empty mesh, iterate the input mesh faces and add the vertices of these faces to the empty mesh, while also adding the colors at this index, and finally the face). This appears to be almost twice as fast the initial method above:

With the cost of adding the colors being quite small (about 20 ms out a total 120 ms, which is roughly the same as doing the Unweld):

Anywho, I wonder though if MeshVertexColorList.SetColor Method (MeshFace, Color) should be considered broken here (i.e. it only sets one vertex corner when the input is unwelded as par the second example in my original post).


#4

I agree this is broken based on the apparently intended functionality. @Dale is this something you can confirm?
MeshVertexColorList.SetColor Method will set only one vertex’s color resulting in this outcome for an unwelded mesh: (only each lower-right corner is colored)

-Willem


#5

Indeed, also this does not appear to be exclusive to unwelded meshes (also the mesh vertices must already have colors, otherwise you get an IndexOutOfRangeException back), just did a more minimal test:

180416_MeshVertexColorListSetColor_00.gh (15.1 KB)


(Dale Fugier) #6

Hi @Willem, @AndersDeleuran,

For mesh vertex colors, which are optional, either Mesh.VertexColors.Count is zero or it has the same count as Mesh.Vertices.Count, in which case Mesh.VertexColors{i] reports the color assigned to Mesh.Vertices[i].

Does this help?

– Dale


#7

Hi @dale,

i think what @AndersDeleuran and @Willem report is that it does not work for all 4 vertices when a mesh face is used to assign a color, even after all colors have been set using CreateMonotoneMesh. An error is probably in this method. I have not tested it yet.

_
c.


#8

That’s exactly right @clement. I attached the minimal example demonstrating this above in the Grasshopper definition.


(Dale Fugier) #9

@AndersDeleuran,

This:

m.VertexColors.SetColor(f,c)

should produce the same result as this:

m.VertexColors.SetColor(f.A, c)
m.VertexColors.SetColor(f.B, c)
m.VertexColors.SetColor(f.C, c)
m.VertexColors.SetColor(f.D, c)

I’ll dig into this more…

https://mcneel.myjetbrains.com/youtrack/issue/RH-45553

– Dale


#10

This is great @dale!

While we’re at it: I wonder if a simple workaround to all this might be to add the option that Mesh.Unweld takes no angleToleranceRadians input, and thereby makes an absolute/hard unweld without checking the difference of normals (which I assume is what makes it quite heavy to call on large meshes)?


(Dale Fugier) #11

Hi @AndersDeleuran,

I believe passing an angle tolerance of zero to Mesh.Unweld should do the trick. Also, you could just run through each of the faces, make a copy of the vertex and set the face.vi to the new index. Run compact when it’s done to get rid of the no longer referenced vertexes and then run compute vertex normals to cook up new normals from the face normals.

– Dale


#12

It does indeed (as per my original post), but is still quite heavy/slow on large meshes, due to the normal checking that is going under the hood I assume (which isn’t needed as we know we want to unweld everything in this case). So my point is that if one gives the method an angle tolerance of zero (or nothing), the method should skip the normal checking, which should severely speed things up (again, I assume).

That is the other method I’ve been going with in the posts above, where the last one is a bit faster, but still these large loops are inherently costly (especially in Python), and again, it feels a bit like a dodgy workaround (to something unweld should be capable of doing faster).

Thanks again.

Edit: Also, being able set all face colors in one go (ala MeshVertexColorList.SetColors) would be great, in case you guys will be fiddling with any of this.