@SoundDifferent I saw your post on Polycount. Don’t know if you’re still looking for a solution to this as it’s been a long time.
With the basis shape of the mesh as one extreme (Xn), you can have a shape key that moves all vertices to the other extreme, all together.
So all vertices that will move start at Xn, and the shape key puts them all at X1 (you can do this by using Vertex Slide to move them all together).
Then use a vertex group with weights created by script to be perfectly linear (as much as numerical precision will let you, at least), and use that group as the blending for that shape key.
(This is an animated GIF, click in case it doesn’t play)
The script I wrote for this is below. Before running it, you need to select a vertex sequence, and then use Shift+Click to unselect and reselect the first vertex, as the first vertex of the sequence needs to be the active one. You also need to make sure that there’s a vertex group in the object named “X1Blend”, but you can change its name in the script of course:
obj = bpy.context.active_object
VERTEX_GROUP_NAME = 'X1Blend'
VERTEX_GROUP_INDEX = obj.vertex_groups.find(VERTEX_GROUP_NAME)
if VERTEX_GROUP_INDEX == -1:
raise Exception('Group not found, check if the name is right')
mesh = bpy.context.active_object.data
bm = bmesh.from_edit_mesh(mesh)
# Traverse the selected vertices, assigning linear weights.
deformLayer = bm.verts.layers.deform.active
visited = set()
TOTAL_SELECTED_VERTICES = len([v for v in bm.verts if v.select])
currentVertex = bm.select_history.active # Start from the active element (assumed to be a vertex).
currentIndex = 0
# Add the current vertex to visited set.
# Set its weight.
# A linear formula for interpolating the weight can be (vertex_index / (total_vertices-1)),
# with 'vertex_index' being a zero-based index.
# If there are 3 selected vertices, their weights will be: 0.0, 0.5, 1.0.
# If there are 5 selected vertices, their weights will be: 0.0, 0.25, 0.5, 0.75, 1.0.
# And so on.
weight = currentIndex / (TOTAL_SELECTED_VERTICES - 1)
currentVertex[deformLayer][VERTEX_GROUP_INDEX] = weight
currentIndex += 1
# Reference the next vertex, if there is one.
currentVertex = next(
for linkedEdge in currentVertex.link_edges
if linkedEdge.select and linkedEdge.other_vert(currentVertex) not in visited
None # Will default to None if the next vertex can't be found (like after the last one).