Proper mesh offset

Hi all!

Talking about the “mesh offset” function, the type that returns a mesh with the same topology (same amount of vertexes and faces), what is the current best algorithms/software/tools to achieve so?
… be it Rhino context or not.

I’m looking around before investing time on this…

Our usual mesh offsets function is the “move the vertex by the wanted distance along the normal” … and so the distance between the faces is almost never the wanted distance.
That’s more like:
’ Hey, the vertexes moved! Take it as an “offset” and be happy with it! ’
Concept explained with 2D curves:

Black: starting mesh
Red: current “offset”
White: optimal result (in 2D we have offset curve Loose …)

I know well that a vertex surrounded by more than 4 faces will not always have a solution.
But our current function is not even trying! :sweat_smile:


A mesh with any vertex surrounded by more than 3 faces generally doesn’t have an offset solution with:

  • the same number of vertices
  • its faces parallel to the input

(and this offset is trivial to find when you do have such a 3-valent mesh, but it’s a very restrictive condition you don’t ever really encounter except when you’re deliberately designing planar hex meshes). For 4 faces each vertex has to be conical, which is also very restrictive and doesn’t happen accidentally (when you do have a conical mesh, you can offset it with the face-face offset component in K2).

For general meshes though you have to choose which one of those 2 conditions you are willing to let go of. I think keeping the vertex count and letting the face-face distances vary is the sensible default.
I agree though it would be nice to have the other option (constant face-face, but the offset can have different vertex count). I did get something working to generate this on all convex meshes, but for concave vertices there are a lot of possibilities to check. I’ll have another look though and see if I can get it working.

See in particular the example 3dm here showing 2 different valid face-face offset solutions for a single 4-valent vertex.

1 Like

I remember your comment on that thread. On point.

Yeah, I know, I mentioned that.
Altering the vertices count is something that alter the topology, so I personally am not really interested in a function that adds vertices… maybe if it adds really few vertices, only on extreme cases, then ok…

All this is related to SubD tasks, having an offset with 1:1 congruent topology is optimal, imho.
Even if the offset is not perfect, I need something better than our current offset.

1 to 6

mesh offset types.3dm (1.9 MB)
2 is Rhino SubD offset, which differs from 3 … unexpected for me.
3 is Rhino mesh offset which is the same as Weaverbird “Distance On Diagonals”
4 is Weaverbird “Hypotenuse Average”
(Weaverbird experimental mode “Planes Intersections” fails…)
5 is an offset where any point is “at least” as distant as the offset amount from the original mesh
6 is an offset where any point is “at maximum” as distant as the offset amount from the original mesh
(note that the offset amount is 1 unit , but only 5 and 6 “try” to respect that as face-face distance…)

Back to my question, rephrased:
Is Rhino mesh offset (keeping topology but just using the normals) the only available function?
Do better functions/tools exist? (in other software)

I’m not criticizing Rhino, I’ve already seen other way-more-expensive software do the offset the same way as rhino…

You said more than 4, I was just saying that it’s even more limited than that - an equal distance face offset with the same topology as the original is impossible for general meshes with more than 3 faces around any vertex.

As long as we’re clear you’re asking for the impossible here!..which is fine -
If you can say what is the measure of closeness to this ideal you want to be minimised, or define what are the properties you want this offset to have, I think we can look at making a tool for it.

If sticking to the condition of not changing topology, then it’s all a question of choosing a normal and a distance per vertex.
There are lots of different options for defining a vertex normal (I’d guess that’s the reason for the difference between Mesh offset and SubD offset, since the latter is maybe using the normal of the smooth surface rather than of the control polygon).
For a mesh you can get a vertex normal as an average the surrounding face normals, unweighted, or weighted by interior angle at the vertex, or by face area etc. Alternatively you can intersect planes - only with 3 do you always get a point, but you could take the average of these for each consecutive set of 3 (or of all combinations of 3).

Once you’ve chosen a direction, then choosing a distance that results in an average or ‘at least’ or ‘at most’ face-face distance should be simply a question of sorting the plane intersections along the line.

… my bad :see_no_evil:

… cool.

But, has anyone ever already made something like that?

I can put up some code, but it would be a waste if, for example, blender have a nice function that I can exploit by exporting/importing .obj …
(I’ve never used blender, it was just an example… I never leave Rhino womb…
I know just a bunch of CAD software, a little… and none of them have a decent mesh offset

What would you consider a decent single vertex mesh offset for a vertex like this?
For symmetry surely we require that it lies on the orange line, but anywhere along that line will have the same big ratio between the marked blue and green face-face distances (if we keep the faces parallel to the original).

Depending on the limits of the situation, i would choose between one of the two solution (like 5 and 6 in my picture ^ ), like:
(5) "nothing can enter this volume
(6) “the maximum thickness of the plastic is…”

In your picture, I would give full priority to blue lines and using the green as guideline only, OR the opposite … never an average.
(just my specific workflow…)

But as you said this is a simple symmetric scenario, i’m thinking about something more generalized…

Waiting for knowledge from here, i’ll try to code something…

Here’s a mesh offset script example of what I was talking about earlier: (25.4 KB)
You can choose between targeting at-least, at-most and average face-face distances, or standard vertex-vertex.

It’s easy to find meshes where no approaches work though, particularly with highly concave vertices, or non-planar quads, and I think trying to find a way of offsetting by simply moving vertices that works on all cases would be a recipe for frustration.

I’m pretty sure there are plenty of cases where it is simply geometrically impossible, and the only way mesh offsetting can be truly robust is to allow changes in the topology - i.e. adding new vertices in the offset.

For example - the Császár polyhedron is a valid, closed, planar faced, mesh, without any self intersections, but however you try to move the vertices outward to make an offset, you get something that not only doesn’t keep a minimum distance from the original, but actually intersects it. That’s an extreme example, but I think it’s fairly likely that a version of this phenomenon will occur on some vertices of any moderately complex mesh with concave parts.


As usual, only gold from you! Thank you Daniel!

I tried to code too… you are right!
(first of all why the ambiguity between Vector3f and Vector3, float and double … I’m doing so many casts …)

… yes. Some tactical new vertex would indeed help a lot.
But having a function that have the permission to add vertices, scare me with a
“What if it added vertices where I haven’t noticed?”
And, it is way more complex a function like that. I think.

I’ll test/study your algorithm and report. Thanks!

1 Like

mesh offset 1
The weighted average + the “at least” is sort of promising, but the mesh is broken and invalid…

In the code you are re-creating the face normals by cross-product the sorted neighbor vertexes to avoid the “unrelated” face normal if it’s a ngon. Make sense.
The problem is a face might not exist (like a hole in the mesh), and instead topology vertex neighbor faces are not sorted… tricky.

I’ve noticed that the normals of neighbor faces of a vertex are most of the times limited to a half-sphere range, if not, it’s an absurd mesh anyway. I’m trying to exploit that…

Oh yes, I forgot to mention - that code assumes a closed mesh, and will break when it isn’t.
To make it work also for meshes with boundaries you’d need to include a check for whether a face actually exists between consecutive neighbours of a vertex before using its angle/plane, in both the normal calculation and the distance check.
This sort of thing does get a bit annoying to do in the Rhino Mesh structure and is usually the point where I’d turn to Plankton (where things like getting cyclically ordered neighbouring vertices and corresponding faces is simple, and halfedges along a boundary are easily identified because their adjacent face is set to -1. Also no converting back and forth between Vertex indices and TopologyVertex indices).

Maybe, but I’d be cautious of assuming that too readily.