It can be fixed by aligning the UVs of quad faces:
@jessesn , i think ShapeMap needs those 2 extra components:
- MeshFaceUV (for checking the directions)
- AlignMeshUV (for aligning the directions)
You have the file with both C# scripts I did with ChatGPT:
2-2_MeshModule-test 260413BC.gh (98.3 KB)
Perhaps having a pinch component would be useful.
Here’s the code but it’s a bit hard to tune.
Maybe @jessesn , you can write it better.
"""GhPython component
Inputs:
M : Mesh
P : List[Point3d] pinch points
W : List[float] weights per point
R : float influence radius (0 or None = auto)
Pow : float outer falloff power
MaxMove : float max move scale (0 or None = auto)
Output:
A : Mesh
"""
import Rhino
import math
def remap_weights(points, weights):
if not points:
return []
if not weights:
return [1.0] * len(points)
if len(weights) == 1 and len(points) > 1:
return [weights[0]] * len(points)
if len(weights) < len(points):
last = weights[-1]
return list(weights) + [last] * (len(points) - len(weights))
return list(weights[:len(points)])
def auto_radius(mesh):
bb = mesh.GetBoundingBox(True)
return bb.Diagonal.Length * 0.25
def auto_max_move(mesh):
bb = mesh.GetBoundingBox(True)
return bb.Diagonal.Length * 0.03
def smoothstep(x):
if x <= 0.0:
return 0.0
if x >= 1.0:
return 1.0
return x * x * (3.0 - 2.0 * x)
def pinch_mesh(mesh, points, weights, radius, power, max_move):
if mesh is None or not mesh.IsValid:
return None
if not points or len(points) == 0:
return mesh.DuplicateMesh()
if power is None:
power = 1.0
if radius is None or radius <= 0:
radius = auto_radius(mesh)
if max_move is None or max_move <= 0:
max_move = auto_max_move(mesh)
weights = remap_weights(points, weights)
new_mesh = mesh.DuplicateMesh()
verts = new_mesh.Vertices
# inner zone where motion gradually fades to zero near the pinch point
inner_radius = radius * 0.20
for i in range(verts.Count):
v = verts[i]
vx = v.X
vy = v.Y
vz = v.Z
move_x = 0.0
move_y = 0.0
for pt, wt in zip(points, weights):
dx = pt.X - vx
dy = pt.Y - vy
d = math.sqrt(dx * dx + dy * dy)
if d <= 1e-9 or d >= radius:
continue
ux = dx / d
uy = dy / d
# outer falloff: 1 near point influence zone, 0 at radius
t_outer = 1.0 - (d / radius)
outer_falloff = t_outer ** power
# inner slowdown: 0 at point, 1 outside the inner zone
t_inner = d / inner_radius if inner_radius > 1e-9 else 1.0
inner_slowdown = smoothstep(t_inner)
# combined effect
strength = outer_falloff * inner_slowdown
step = abs(wt) * strength * max_move
if wt < 0:
step = -step
move_x += ux * step
move_y += uy * step
verts.SetVertex(i, vx + move_x, vy + move_y, vz)
new_mesh.Normals.ComputeNormals()
new_mesh.Compact()
return new_mesh
A = pinch_mesh(M, P, W, R, Pow, MaxMove)
It looks great, and thanks for your sharing.
Could you share this .gh file? Thank you.
I uploaded an archive with rhino file (baked pinched mesh inside) and gh file with the full definition including UV alignment, pinch and mesh offset.
meshmodule test uvalign pinch and offset 260415BC.rar (15.3 MB)
I also made a small component for fast mesh offset. Could be useful for Shapemap workflow.




