# How can I link objects with applied rotations?

[![enter image description here][1]][1]

All of these screws have a rotation of (0,0,0). Which means their rotation has already been applied. If I select them all and link them, they will all share the rotation of the active screw. Is there any way to preserve their current rotation during the 'link' operation?

I am guessing that you would need to use geometry nodes to analyze the current geometry. Each screw would have the same geonodes modifier, and would rotate about x,y,z until it minimized some property, like inertia. I know this is abstract thinking but maybe it will help somebody think of something clever. [1]: https://i.sstatic.net/9UaoK.jpg

• I don't understand, if all the screws have a rotation of 0, if you join them nothing should change since all of them have the same rotation?
– Alex
Commented Feb 13 at 18:17
• He wrote "link" not "join" which is a different operation. Commented Feb 13 at 18:23
• there's no way, they will all have the same orientation, or you need to save each orientation with as many custom orientations as you have objects Commented Feb 13 at 18:26
• Imagine an assembly with thousands of screws. There's no way to replace each screw with an instance? Commented Feb 13 at 18:29
• as the objects rotated from their origins? Commented Feb 13 at 18:29

Presuming all objects have initially been rotated from their origin and there is no other operation on them (no translation for instance).

We need to find two vertices that are not aligned with the mesh origin.

If these two exist, we can calculate two rotations in order to find the wanted result.

Below, green/blue is the object and yellow/red is the reference.

First rotation is the one that goes from one of the vectors to the other:

Once this rotation applied, to the green and blue, we have green over yellow and we have blue rotated:

Now we want this rotation, with the green/yellow as axis:

The following code does it. Select all the objects you want to "unrotate" with the reference one as active object and run the code.

import bpy
from math import degrees
from mathutils import Matrix

# loop over the vertices in order to find
# 2 of them that are not aligned with the
# origin of the mesh
def pick_points(verts, epsilon = 0.01):
for i1 in range(len(verts)):
v1 = verts[i1].co.normalized()
for i2 in range(i1 + 1, len(verts)):
v2 = verts[i2].co.normalized()
if v1.cross(v2).length > epsilon:
return i1, i2, v1, v2
return None, None, None, None

# Take the reference object, the active one
reference = bpy.context.active_object
# Find reference vertices for it
i1, i2, v1, v2 = pick_points(reference.data.vertices)

if i1 is None:
print("All vertices are aligned")
else:
# The vector formed by the projection of v2 on v1 to v2
pv2 = v2 - v2.project(v1)

# Loop over the selected object
for o in [o for o in bpy.context.selected_objects if o != reference]:
# Get the two vertices at same indices
ov1 = o.data.vertices[i1].co.normalized()
ov2 = o.data.vertices[i2].co.normalized()

# Get the rotation separating ov1 and the reference v1
q1 = ov1.rotation_difference(v1)
# Rotate ov2 with this rotation
ov2 = q1 @ ov2
# Get the vector formed by the projection of ov2 on v1 to ov2
pov2 = ov2 - ov2.project(v1)
# Get the rotation separating these to "p" vectors
q2 = pov2.rotation_difference(pv2)

# Combine the rotations = how to go from o to the reference
q = q2 @ q1

# Extract current world matrix components of o
t, _, s = o.matrix_world.decompose()

# Assign it the same component, but replacing the rotation part
# which is calculated above inverted
o.matrix_world = Matrix.LocRotScale(t, q.inverted(), s)

# Link objects to the ref/active one


Here is your file (I've used V4.0 here), with a copy of the screws and the script applied.

All works as expected:

Select them all with the original screw as active.

Run the script.

And the screws are instances with the wanted rotations.

• WOW. Ok I will try this now Commented Feb 17 at 20:32
• This is a really great answer, but I'm still back where I started. I have an assembly of the same screw in all sorts of orientations, but they are not instances - so they take a lot of unneeded memory. I need them to maintain their rotation after linking them. Commented Feb 17 at 20:44
• Well, JB, this is what the script is supposed to do. It does not work for your case? Commented Feb 18 at 6:39
• I could achieve the same results as this script by simply linking them. The problem with this script, and linking, is that all the screws change their rotation to match the active, I need them to stay the way they are, yet become instances. Commented Feb 18 at 21:31
• I've tested it and the script works for me here. Could you share a sample file with the screws, please? Commented Feb 19 at 6:02

There is no general way to do that. If the rotation is applied, you loose it so there is nowhere to get that back from.

You could attempt to get that information from the geometry in a Python script. For example you could compare the average of normals of all faces to the initial rotation of the first object and then figure out what the rotation should be based on that. Since the geometry is not completely symmetrical, I suspect that vector from averaging all face normals would be somehow relative to the orientation of the geometry and the same in all of them assuming the geometries are exact copies. Sounds like a lot of work for 5 screws. If you had hundreds of them, maybe that would pay off.

• FYI, my answer here. This is possible... considering there is only a rotation around the origin... If I was wrong for some cases, please tell me. Commented Feb 17 at 18:46