How do I align the ridge along the top of the helmet in an axis direction? I would like to have the highest point of the helmet at (0,0,0) and have the ridge pointing along any axis.
The old fashioned way, assuming you don't want to change the object's origin with respect to its mesh.. harnessing the object to an aligned Empty, by parenting.
- ShiftS 3D Cursor to the point you eventually want at World 0, and create an Empty there
- Select 3 points defining the plane you want aligned to an axis and create an orientation from them
- With the Empty in Object Mode, Header > Object Transform > Align to Transform Orientation
- Rotate the Empty by whichever 90° increments take you to the desired alignment
- CtrlP Parent the object to the Empty, and AltG, AltR bring the Empty to the origin.
Un-parent your object, keeping the transform.
First thing to try is ⎇ AltR to delete object rotations:
If it doesn't work, it means the rotation is applied: all vertices are moved to their world positions and rotation is cleared. This means there no longer is any rotation information, and you need to manually add that information… Here's probably the most reasonable strategy:
Align vertex up
Select the vertex that is supposed to be the highest vertex:
Then back in object mode (it's important to go back to object mode, so that the bmesh data existing in edit mode is transferred back to normal mesh data) paste this into Python console (it's in the Scripting tab, but you can also change any area to it, either using mouse or ⬆ ShiftF4):
C.object.rotation_euler = next(v for v in C.object.data.vertices if v.select).co.to_track_quat('Z').inverted().to_euler()
[I used inline formatting because it's a long oneliner, this way it wraps and is easier to select]
after pressing ↩ Enter, the object will get a rotation aligning selected vertex up:
Now you can also ✲ CtrlA, R Apply Rotation.
Align a line to axis
Very similar to the above, except this time select a vertex on the ridge, that is NOT the top vertex:
Then move its coordinate (the vertex is left alone, the copy of the coord is moved) down to $z = 0$, then decide where the vertex should point:
'X' or (+)
'Y' and add the second attribute (omitted in the previous step), defining the 2nd axis, which should point up - current Z axis (meaning: keep up pointing up). Therefore the one-liner becomes:
C.object.rotation_euler = (next(v for v in C.object.data.vertices if v.select).co*Vector((1, 1, 0))).to_track_quat('Y', 'Z').inverted().to_euler()
Here's a more readable script that does both steps: (⚠ I haven't tested this one so there could be some error):
top_vertex_index = 100 other_vertex_index = 55 align_to = 'Y' import bpy from bpy import context as C from mathutils import Vector ob = C.object me = ob.data top_vertex = me.vertices[top_vertex_index] quat = top_vertex.co.to_track_quat('Z') quat.invert() euler = quat.to_euler() ob.rotation_euler = euler bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) other_vertex = me.vertices[other_vertex_index] co = other_vertex.co * Vector((1, 1, 0)) quat = co.to_track_quat(align_to, 'Z') quat.invert() euler = quat.to_euler() ob.rotation_euler = euler
Similar logic could be used in Geometry Nodes, using Align Euler to Vector node, or in constraints, using Track to constraint…