How do I align vertices along a arbitrary axis?

Started by
10 comments, last by Kryzon 10 years, 11 months ago

I'm new to Blender and I have a question that you modeling veterans can probably answer:

I've been searching all over as to how to align a selection of vertices in Blender along an arbitrary axis but haven't found anything that points to a ready solution.

Ideally, I'd be able to just:

  1. Select a series of vertices in Edit Mode.
  2. Bring up the vertex actions menu.
  3. Select something like "Align" from the menu.
  4. The selected vertices would then be automatically aligned along the line formed by the first and last vertex in the selection.
  5. Then I could just left click or press Enter to commit.
  6. Additionally, it would be awesome if I could press X, Y, or Z before committing the alignment action to preserve the corresponding coordinate value when aligning the vertices.

Does anything like this already exist in blender?

Also, I'm aware of the technique where you scale your selection to zero along a single coordinate axis to align the selection along that axis, but that doesn't solve the issue where the desired result is alignment along an arbitrary line between two vertices.

Thanks in advance for any insight you can provide.

Advertisement

It sounds too specific what you're asking (it's not necessarily a bad thing).

Even in 3DS Max, a commercial software with powerful modelling tools, there's only axis-aligned planar alignment of vertices (that is, it's limited to the XY, YZ and XZ planes); It's not arbitrary like what you want, and not in a vector\3D line, and not with regard to the order in which the vertices were selected.

But you defined all the steps for what you want and that's an interesting point - it shows you understand the logic behind it, and you even presented ideas for options for toggling (the X,Y and Z constraints you mentioned). It doesn't sound over complicated either.

It'd be mapping each vertex position to the 3D line formed by vertices V[1] and V[n] in a selection of 'n' vertices, and you would do this based on the closest distance from each vertex to this 3D line.

You see, Blender has an API bound with Python, so you can build your own modelling tools by coding Python scripts. You can find educational material both on Python and on making scripted tools for Blender, so it'd be a great idea if you could dedicate some time to study this.

If you learn to code Python tools for Blender then you can pretty much add most "simple" features like these yourself. I myself am very tempted to do this too.

It isn't exactly what you want, but you could scale to whatever axis is closest(X, Y, Z) and then rotate them into position once they are aligned. The only other things I can think of is if you have a plane and you snap to it(see snapping), but that is somewhat more complicated to set up than the first way.

I agree with Kryzon here though, that isn't a bad idea for a tool to have. In fact, it may even exist already, but since it would be one of the less used tools, it wouldn't be as obvious.

I just remembered something else(duh). You delete all the vertices except for the end points. Select those end points, hit 'F" to create an edge, and the either subdivide that edge. This way you recreate the vertices all along that single edge.



Select those end points, hit 'F" to create an edge, and the either subdivide that edge. This way you recreate the vertices all along that single edge.

I don't know much of Blender, but if you manually move the vertices you inserted into the edge, the edge won't be a straight line anymore (if you zoom in really close you'll see it's a bit sloppy from not being mathematically perfect). It's something that really annoyed me for a while until I discovered 'constraints'.

So you need to use something like Vertex Slide or Custom Transform Orientation to let your vertices slide mathematically perfect along the edge. In 3DS Max, this is called "edge constraint".

Select those end points, hit 'F" to create an edge, and the either subdivide that edge. This way you recreate the vertices all along that single edge.

I don't know much of Blender, but if you manually move the vertices you inserted into the edge, the edge won't be a straight line anymore (if you zoom in really close you'll see it's a bit sloppy from not being mathematically perfect). It's something that really annoyed me for a while until I discovered 'constraints'.

So you need to use something like Vertex Slide or Custom Transform Orientation to let your vertices slide mathematically perfect along the edge. In 3DS Max, this is called "edge constraint".

Yes, my first point was the actual creation of the vertices on the straight line. Once you do that, then yes indeed you would be best to do the vertex slide tool to keep things straight. It is the easiest way I know to slide the verts along the straight edge, considering it takes more time/effort to set up the contraints and/or the custom transform orientation.



Wow! After a couple of days, REPLIES! =D

You see, Blender has an API bound with Python, so you can build your own modelling tools by coding Python scripts. You can find educational material both on Python and on making scripted tools for Blender, so it'd be a great idea if you could dedicate some time to study this.

If you learn to code Python tools for Blender then you can pretty much add most "simple" features like these yourself. I myself am very tempted to do this too.

Yeah, that's actually exactly what I've been doing the last couple of days. I already have the operation part of the code figured out and working. The part I'm stuck at is getting the python script to be processed in a modal manner so that I can toggle which axis coordinates to preserve. The Blender Python API describes using a modal() function in the custom operator class that gets called after execute() or invoke() return {'RUNNING_MODAL'}. Only problem is that my modal() function is never getting called. I've posted on the Blender forums regarding this issue:

http://www.blender.org/forum/viewtopic.php?t=27384

I just remembered something else(duh). You delete all the vertices except for the end points. Select those end points, hit 'F" to create an edge, and the either subdivide that edge. This way you recreate the vertices all along that single edge.

I don't know much of Blender, but if you manually move the vertices you inserted into the edge, the edge won't be a straight line anymore (if you zoom in really close you'll see it's a bit sloppy from not being mathematically perfect). It's something that really annoyed me for a while until I discovered 'constraints'.

So you need to use something like Vertex Slide or Custom Transform Orientation to let your vertices slide mathematically perfect along the edge. In 3DS Max, this is called "edge constraint".

Yes, my first point was the actual creation of the vertices on the straight line. Once you do that, then yes indeed you would be best to do the vertex slide tool to keep things straight. It is the easiest way I know to slide the verts along the straight edge, considering it takes more time/effort to set up the contraints and/or the custom transform orientation.

Thanks for the alternative. I'm not sure if that will get the precision that I'm looking for, but constraints seem to be the best alternative that I've run across so far. I'll keep those tools in mind in the future.

Well, if you delete the current verts, and then create a single edge, and then subdivide the edge, and then only move those verts using the vertex slide, it will be perfectly precise. The catch, as Kryzon mentioned is that you can't move the verts yourself directly, rather via the tool, so that the verts stay exactly straight on the edge. You don't need constraints for this.



Ok, I finally got the script working. You can find the full code here:

http://www.blender.org/forum/viewtopic.php?p=104692#104692

Thanks for the recommendations guys. =)

Thanks for sharing.

I want to ask you where did you learn pythoning with Blender, and if there are any resources you'd recommend to the total beginner (good how-to guides, articles etc.).

Regards.

Thanks for sharing.

I want to ask you where did you learn pythoning with Blender, and if there are any resources you'd recommend to the total beginner (good how-to guides, articles etc.).

Regards.

Largely, I just googled around. I think I started with the query "Blender scripting", found a basic tutorial, and went from there.

I didn't even know Python before starting this, tho it wasn't hard to figure out the syntax. It's basically the same as javascript except:

  1. You use indentation instead of curly braces to indicate scope.
  2. Colons are put at the end of anything that has an inner scope, such as classes, if statements, or for loops.
  3. You use 'not' instead of '!'.
  4. You use 'and' instead of '&&'.
  5. You use 'or' instead of '||'.

You can access the documentation for Blender scripting by going to:
http://www.blender.org/documentation/blender_python_api_2_66a_release/

or by going to Help -> Python API References from within Blender itself (which is better if you want to ensure that the documentation you're looking at matches the version you're using).

Blender has a view for a Text Editor that allows you to edit scripts from within Blender itself. I prefer to use Sublime Text 2 myself as it has more options regarding coding, but the Text Editor within Blender has a menu for templates which will allow you to load up boiler plate scripts that you can examine, test, and modify to help you learn the ropes around Blender scripting.

As far as gotchas that I ran into while trying to make this Align Vert operator:

  1. There are 3 key functions for a operator:
    a) execute(self, context):
    This method is what is called when you run your script via the console or a batch process or when your operator isn't setup to be modal. It's a one-shot function that performs an operation based on the current settings and that's it.
    b) invoke(self, context, event):
    This method is an initializer function that allows you to set your settings to default values and whatever preprocessing you need.
    c) modal(self, context, event):
    This method is what gets called when a modal event happens. Modal events happen when execute(), invoke(), or modal() return:
    
    {'RUNNING_MODAL'}
    

    This starts a modal event loop that allows the modal() method to handle user input (key presses and mouse input). This is the setup that I needed to allow X, Y, or Z to be pressed to toggle modes.

  2. You must register your operator class as a handler for modal events if you want your modal() function to be called after invoke() or execute() return {'RUNNING_MODAL'}. The event registration command is:

    
    context.window_manager.modal_handler_add(self)

    It is recommended that you add this line of code to your invoke() function.

  3. When your operator is triggered via SPACEBAR operator menu, it is by default run with the 'INVOKE_DEFAULT' operator context, which tries to call invoke() before execute() if invoke() exists. When you register your operator to a menu via code like:

    
    def menu_func(self, context):
        # Create the menu button
        self.layout.operator(AlignVerts.bl_idname, text="Align Verts")
    
    def register():
        bpy.utils.register_class(AlignVerts)
    
        # Add "Align Verts" menu to the "Mesh->Vertices" menu.
        bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func)
    
    def unregister():
        bpy.utils.unregister_class(AlignVerts)
    
        # Remove "Align Verts" menu from the "Mesh->Vertices" menu.
        bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)

    The menu will button created will by default run your operator with the operator context of 'EXEC_REGION_WIN', which will cause it to ignore your invoke() function and jump straight to the execute() function. To fix this add a line of code that changes the menu operator context before triggering your operator:
    
    def menu_func(self, context):
        # Operators triggered by menus have their operator context by default set to 
    # EXEC_REGION_WIN. We need it set to INVOKE_DEFAULT to call invoke() instead of
    # execute().
    self.layout.operator_context = 'INVOKE_DEFAULT'
    # Create the menu button self.layout.operator(AlignVerts.bl_idname, text="Align Verts") def register(): bpy.utils.register_class(AlignVerts) # Add "Align Verts" menu to the "Mesh->Vertices" menu. bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func) def unregister(): bpy.utils.unregister_class(AlignVerts) # Remove "Align Verts" menu from the "Mesh->Vertices" menu. bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)

I spent many hours learning these nuances. I hope these tips help. =D

This topic is closed to new replies.

Advertisement