Colour gradient number remapping

I decided to cluster part of your code and apply it to a recent effort of mine in another thread that applied a color gradient to a mesh.

In that case, I used EdgeSrf for distinct colors and, secondarily, to get the area centroid of each face since the gradient depends on the Z value of faces.

Anyway, I started by clustering your code and then started messing around with it… I got something that appears to avoid the “remeshing” problem you mentioned. Here is the CMesh cluster:

Trial 2_2023Sep21a3

And a refactor of Trial 2_2023Sep17a.gh from the other thread using the cluster (white group) and not using EdgeSrf:


Trial 2_2023Sep21a.gh (67.5 KB)

The result is stunning - better than any previous attempt of mine to color mesh faces.

Before, using EdgeSrf (Rendered top view).:

After, using the CMesh cluster (top view is the same in Wireframe, Shaded and Rendered):

There are a few differences where face colors change. I believe these are due to how I determined Z height without Area ‘C’, using the average of Face Boundary vertices instead.

P.S. Come to think of it, I don’t know why the cluster works because the faces are not planar. :thinking:

P.P.S. The CMesh cluster works without the Srf param:

Trial 2_2023Sep21a4

3 Likes

Back to this thread…


Sun-Study_2023Sep21b.gh (663.5 KB)
Sun-Study_2023Sep21b.3dm (589.9 KB)

Error inside the cluster on the SMesh (Simple Mesh) component, doesn’t appear to affect results?

  1. Face[0] in the brep cannot be represented by a triangle or a quad.
2 Likes

Very cool, thanks @Joseph_Oster!

I went ahead and cleaned up the cluster I|O a little bit and added optional blurring.

Graph Space:
image

Model Space (with blurring enabled):

Note:

Blurring does not effect your face selection logic

20230921_Trial 2_2023Sep21a_Response_01a.gh (83.1 KB)

I thought perhaps this was from a 0 length edge but that does not seem to be the case… hmm… unless it’s a meshing tolerance issue?

Either way you are correct in that it does not seem to effect the result

EDIT:

Simple Mesh component is perfect as it doesn’t jack around trying to subdivide the existing mesh. Awesome!

Here’s the updated version of what I shared earlier

Graph Space:

Model Space:

cough cough check out the .3dm size this time <600kb :wink:

20230921_Sun-Study_sample_Response_01b.gh (441.7 KB)

20230921_Sun-Study_sample_Response_01b_Bake_Result.3dm (592.0 KB)

1 Like

FWIW, here’s an older version of the component we use to color analysis meshes. It uses a couple of methods I’ve posted here and there (1, 2, 3). As noted in one of those topics, the primary bottleneck here is still unwelding the mesh, which would likely be faster by skipping the normal checking. But still, the colorMeshFaces method here is likely substantially faster (~60ms) than the methods posted above I suspect, admittedly without checking:


200818_ColorMeshFaces_AHD_00.gh (441.8 KB)

Edit: The input mesh is actually already unwelded here, so if we skip that step it computes twice as fast:


200818_ColorMeshFaces_AHD_01.gh (441.5 KB)

4 Likes

I distinctly don’t like blurring and don’t consider it essential to the task of coloring mesh faces.

1 Like

The Rhino file of the colored mesh I posted earlier was only 589.9 KB.

That’s a huge improvement over 72 .5 MB using EdgeSrf :exclamation:

1 Like

It’s just the size of the input mesh plus the added color information. It’s hardly surprising that this will be MUCH smaller than representing the same mesh as a collection of surfaces/breps!



InputMesh.3dm (565.4 KB)
OutputMesh.3dm (595.8 KB)

1 Like

Ahh yes, I was caught up in comparing against the mesh that was re-topologized I shared initially which was around 1-2mb.

Certainly not essential, personally I like having the option when diagramming/visualizing solar studies and such with a context that doesn’t have any other “pixelated” shaders present. Personal preference of course. I think the cluster has the blurring off by default.

Thanks for sharing this @AndersDeleuran , looks great!

1 Like

Awesome!
Thanks all, this has been incredibly helpful. I consider myself to be a pretty solid GH user, but Im able to follow about 90% of the discussion. Maybe a quick point summary (and please correct me anywhere) so I understand better:

  • My original idea was probably ‘correct’, but for some reason the native GH nodes were not acting like i was expecting. I think this was fundamentally an internal GH problem…? (in my mind I was just re associating a new RGB color code to the exact same mesh faces)

  • So based on this, the idea is to rebuild the meshes from new boundaries individually / exploded (instead of vertices and faces), and then join them back together…?

  • The re-build / re-surfacing idea is great, and seems to work well, but is absolutely massive due to relying on nurbs instead of mesh. Also learn something new everyday - you can bake surfaces with a color!

  • I am not following the finer points of why the outputs are remeshing or not …

  • A couple of Joseph’s last scripts still round-tripped from mesh to surface, how crucial is this? I’d love to remove that from the computation time if possible … and i’m still not copmletely understanding why its necessary (though totally acknowledge that it appears to work like i want it to). It would just be great to ‘lighten up’ the functions as much as possible.

  • Appreciate the input from Anders, but my python knowledge is still very basic so i try to avoid it as much as possible for professional projects …

Not anymore, the Srf param has been removed from the CMesh cluster (here), which is intended as a replacement for the standard MCol (Mesh Colors) component. CMesh works the way I expect MCol to work - but it doesn’t?

I don’t work much with meshes so don’t understand much about them.

If this is for professional usage, you’d appreciate the substantial performance you can achieve. But you do you:

I don’t think one can replicate the key bits of Python here code using native components:

def colorMeshFaces(mesh,colors,unweld):
    
    """ Unwelds and color the faces of the mesh in place """
    
    mesh.VertexColors.CreateMonotoneMesh(rc.Display.ColorHSV(0,0,0))
    if unweld:
        mesh.Unweld(0,False) # Bottleneck
    for i in range(mesh.Faces.Count):
        mesh.VertexColors.SetColor(mesh.Faces[i],colors[i])

But one can at least use these components to de/re-construct the mesh while adding vertex colors:

230922_ColorMeshFaces_Comparison_00.gh (877.0 KB)

Totally agree - I would love to be using more python in my work. The difficulty comes from not having a large enough knowledge base to effectively trouble-shoot as problems arise. We don’t have anyone internally who i can turn to (As far as i’m aware). Appreciate the input though, no disagreements on me end.

1 Like

Agree - the only time i come into contact with meshes is for analysis like these …

I don’t see these two methods working the same at all?

CMesh cluster:

“Using Native Components”:

I have no idea what Weld Mesh and Unweld Mesh do? Same goes for many other mesh components: Unify Mesh, Smooth Mesh, Disjoint Mesh, Align Vertices, etc.

P.S. Curiously, “Using Native Components” gives the same result as Unweld Mesh before MCol (Mesh Colors). Without Unweld Mesh, MCol does this:

The CMesh cluster looks best to me. :sunglasses:

I know you know how to read component/parameter documentation, but I’ll bite:

I’m sure there are much better ways to wrangle the data here. But as I hinted at above, Grasshopper simply isn’t very well equipped for dealing with meshes (i.e. because it doesn’t expose many of the underlying RhinoCommon mesh properties/methods that well/at all). Whereas with a GHPython/C# script that can access the full Mesh class, you can do this (note the compute times):


230922_ColorMeshFaces_Native_00.gh (848.2 KB)

So in this case, I think it’s hard to argue that the scripted implementation isn’t the simpler solution. It’s certainly the fastest. But again, you guys do you guys :man_shrugging:

2 Likes

Thanks. Very interesting. The method using standard components is quite intricate, requiring a deep understanding of meshes, as well as GH data trees.

Yeah, and if I were 20 years younger, working in CAD, I would delve into it. But it’s only a hobby for me at this point so acquiring deep knowledge of something I rarely use has little interest.

On the other hand, this little bit of Python is pure gold!

for i in range(M.Faces.Count):
    M.VertexColors.SetColor(M.Faces[i],C[i])

It’s exactly what I expect from components like MCol (Mesh Colors), yet I am too often disappointed that such functionality exists only in the Rhino APIs, accessed via Python or C#.

Thanks again.

2 Likes

How does it work to have ‘M’ as the name of both input and output?

One little detail of the CMesh cluster bugged me so I fixed it. I had flattened the output of MCol so it wasn’t going to work properly with branches.

Built a rather elaborate demo / test GH file, only to realize that the fix makes it possible to have one mesh in each branch but otherwise the mesh colors are unaffected, they were correct. :thinking:

The result of flattening in this case was to combine the mesh faces (colored correctly) into a single mesh instead of separate meshes. So weird that three meshes that don’t touch each other can be considered one mesh.

cmesh_cluster_2023Sep22a


cmesh_demo_2023Sep24a.gh (27.7 KB)

1 Like

To partially answer my own question, I did a little experiment. I added an ‘x’ input to your Python, set to ‘List Access’, and added an ‘x’ output. I did nothing to the Python source - didn’t even open it. Wired a Series component to the ‘x’ input and Voilà :exclamation: As expected, the input series of numbers comes out the ‘x’ output. Amazing.

python_in-out

I guess the other part is that Python knows when a variable is SET, the output is affected.
Very tricky!!