11
$\begingroup$

I need to sort the vertices sequentially to make an effect, something like this video. I know I should draw them by hand, but sometimes when I subdivide edges, vertex indexes will change.

The vertices in the below image are correct.

Enter image description here

For example, vertices in the below image are sorted randomly. Can you sort them sequentially?

Enter image description here

I tried to sort them along the x-axis or z-axis, but it didn't work.

Enter image description here

Please consider that your solution should work for complex shapes:

Enter image description here

$\endgroup$
3
  • $\begingroup$ Do you have the python script of your attempt at sorting x and y axis. (I assume it did work, it's not the result you are after) $\endgroup$
    – batFINGER
    Commented Aug 20, 2020 at 7:37
  • $\begingroup$ @batFINGER I used this script $\endgroup$ Commented Aug 20, 2020 at 7:40
  • $\begingroup$ The title is incomprehensible near "indices". Can you fix it? $\endgroup$ Commented Aug 21, 2020 at 7:48

4 Answers 4

15
$\begingroup$

Sorting vertex indices.

Answer here https://blender.stackexchange.com/a/36619/15543 shows how to sort vertex indices using bmesh.

Answer here How to order a list of vertices based upon position? goes some way to show how to walk the edges for an order.

To be sure to be sure would walk the edges as shown above until the first vert is re-encountered (since its a loop) and use this for the order. Will leave it up to you to piece together the script from what is here

As demonstrated in @Leander's answer

Shortest Path

Using the script from What is the bmesh equivalent to bpy.ops.mesh.shortest_path_select()? could select edge as link between first and last index vert, temporarily remove it, find the shortest remaining path (the only path) from edges two verts. Reinstate the edge.

Face winding order

Instead for a closed loop like above, contend can fill with an ngon, use the ngon face verts as order (the winding order) re-sort the verts and remove the ngon face created.

import bpy
import bmesh

ob = bpy.context.object
assert ob.type == "MESH"
me = ob.data

bm = bmesh.from_edit_mesh(me)

f = bmesh.ops.contextual_create(
        bm,
        geom=bm.verts[:] + bm.edges[:],
        )["faces"][0]

for i, v in enumerate(f.verts):
    v.index = i
bm.verts.sort()
bm.faces.remove(f)

bmesh.update_edit_mesh(me)

Select a first vert and clockwise or counter

To select the zeroth vert, and ensure anticlockwise (from top view) indexing

Run in edit mode, select the vert you wish to have index 0. Assumes the shape lies in the XY plane. If the normal of the created face points down the winding is flipped.

enter image description here Random order, vert 22 selected, script below run

import bpy
import bmesh
from mathutils import Vector

ob = bpy.context.object
assert ob.type == "MESH"
me = ob.data

bm = bmesh.from_edit_mesh(me)
v0 = bm.select_history.active
f = bmesh.ops.contextual_create(
        bm,
        geom=bm.verts[:] + bm.edges[:],
        )["faces"][0]

fverts = f.verts[:]

if f.normal.dot((0, 0, 1)) < 0:
    fverts.reverse()

for i, v in enumerate(fverts):
    v.index = i
    if v is v0:
        iv0 = i

for v in fverts:
    v.index = (v.index - iv0) % len(fverts) 
    
bm.verts.sort()

bm.faces.remove(f)

bmesh.update_edit_mesh(me) 
$\endgroup$
5
  • $\begingroup$ And here I was walking the edges >_> $\endgroup$
    – Leander
    Commented Aug 20, 2020 at 8:17
  • $\begingroup$ @Leander yours is a very clever "outside the box" solution. Are you ripping the selected first vert? $\endgroup$
    – batFINGER
    Commented Aug 20, 2020 at 8:41
  • $\begingroup$ Just deleted the edge to stop the extra edge from blocking the screencast. $\endgroup$
    – Leander
    Commented Aug 20, 2020 at 8:57
  • $\begingroup$ @batFINGER your solution didn't work in complex shapes it just worked for simple shapes $\endgroup$ Commented Aug 20, 2020 at 10:12
  • $\begingroup$ @batFINGER I tested on several shapes and it works correctly! thank you, man! you're great! $\endgroup$ Commented Aug 20, 2020 at 12:15
10
$\begingroup$
  1. Add a shapekey.
  2. In that shapekey, place the vertices which are to be first and last far away from each other on the x axis.
  3. Select all other (inbetween vertices).
  4. Choose W > Smooth Vertices and set a high iteration count. The vertices will be smoothed.
  5. Sort them by x-axis. Mesh > Sort Elements > X Axis
  6. Delete the shapekey.

process demo

$\endgroup$
6
  • $\begingroup$ Oh my God, you are a legend! it's a nice solution without a line of code! I have a lot of shapes to sort can you write a python script? because I used the python tag in my question. $\endgroup$ Commented Aug 20, 2020 at 7:41
  • $\begingroup$ your solution didn't work for complex shapes it just worked for simple shapes $\endgroup$ Commented Aug 20, 2020 at 10:34
  • $\begingroup$ no sorry. I tried again and I have the same result. It didn't work for complex shapes.I also tried to move that two-point in infinity position along x axis but it didn't work correctly. $\endgroup$ Commented Aug 20, 2020 at 11:18
  • $\begingroup$ Upload your blend with the "complex shape", I don't know why it shouldn't work... $\endgroup$
    – Leander
    Commented Aug 20, 2020 at 11:21
  • $\begingroup$ I uploaded the file and I attached It to my question. $\endgroup$ Commented Aug 20, 2020 at 11:28
7
$\begingroup$

Using Python, you can walk the edges and assign them a new index.

import bpy
import bmesh

me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)

# index of the start vertex
initial = bm.verts[0]

vert = initial
prev = None
for i in range(len(bm.verts)):
    print(vert.index, i)
    vert.index = i
    next = None
    adjacent = []
    for v in [e.other_vert(vert) for e in vert.link_edges]:
        if (v != prev and v != initial):
            next = v
    if next == None: break
    prev, vert = vert, next

bm.verts.sort()

bmesh.update_edit_mesh(me)
$\endgroup$
4
  • $\begingroup$ nice! it works like a charm! I'm confused about what answer should I accept! @batFINGER answer or your answer!😅 $\endgroup$ Commented Aug 20, 2020 at 12:09
  • 1
    $\begingroup$ @Leander there is also the BMEdge.other_vert(v) method that knowing one vert of edge v returns the other. $\endgroup$
    – batFINGER
    Commented Aug 20, 2020 at 12:14
  • $\begingroup$ Thanks a lot for reading through all these answer and giving helpful suggestions! $\endgroup$
    – Leander
    Commented Aug 20, 2020 at 15:00
  • $\begingroup$ "Python", not "python". $\endgroup$ Commented Aug 21, 2020 at 7:50
5
$\begingroup$

Without a script:

  1. V split the mesh at the vertex you want to be first, if it's not already.
  2. Header > Object Menu > Convert the mesh to a curve
  3. Edit mode, right-click menu, switch the direction of the spline, if necessary
  4. Object mode, right-click menu, Convert back to a mesh.

Gordian Knot

I don't know why Convert isn't in the Object mode right-click menu for a mesh, that's kind of annoying.

Barring refinements, as supplied by @Seyed, the script would be:

import bpy
bpy.ops.object.convert(target='CURVE', keep_original= False)
bpy.ops.object.convert(target='MESH', keep_original= False)

Or, to split a cyclic mesh at a selection:

import bpy

# in edit mode, select one vertex

bpy.ops.mesh.split() 
bpy.ops.object.editmode_toggle()
bpy.ops.object.convert(target='CURVE', keep_original= False)
bpy.ops.object.convert(target='MESH', keep_original= False)

Then merge the two loose ends.

Thanks to @Paul St George

$\endgroup$
7
  • 1
    $\begingroup$ you're genius! nice job! It works with three lines of code!!! import bpy bpy.ops.object.convert(target='CURVE', keep_original= False) bpy.ops.object.convert(target='MESH', keep_original= False) $\endgroup$ Commented Aug 21, 2020 at 9:09
  • $\begingroup$ @SeyedMortezaKamali thanks! I'll put that in. $\endgroup$
    – Robin Betts
    Commented Aug 21, 2020 at 9:41
  • $\begingroup$ The outcome of this looks random. Se meshes have vertices in clockwise order and some in counter clockwise order and i wonder if it would be possible to get the same direction or at least determine what meshes that have clockwise order. $\endgroup$ Commented Sep 2, 2022 at 10:21
  • $\begingroup$ @RobinBetts Great solution ('Without a script'). Please will you tell me what this means: "V split the mesh at the vertex you want to be first, if it's not already." The rest I get. $\endgroup$ Commented Mar 20 at 21:20
  • $\begingroup$ Hi, @PaulStGeorge! The keyboard shortcut V will split the vertex, making the mesh acyclic, so the curve has well-defined start and end points. I guess nowadays, there would be a better solution than this, using Geometry Nodes .. ( Points to Curve ?).. and that should be able to fix user2404987's problem, too, which somehow I missed back then. $\endgroup$
    – Robin Betts
    Commented Mar 21 at 6:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .