Creating a grid with bmesh results in 0,0,0 rotation

Hi guys, I am running into an issue where I’m making a face by defining 4 verts and then I want to rotate that face to match a certain axis, but it’s not working because my created face is always 0,0,0 rotation.

Here is my code. It will take an object that doesn’t have a zero’d out rotation and move it to the origin and make it match ob2. I just need this to work even though I have 0,0,0 on my rotation. Is this possible?

ob1 = bpy.data.objects[‘A’]
ob2 = bpy.data.objects[‘B’]

oldpos = ob1.location

ob1.rotation_mode = ‘QUATERNION’

inv = ob1.matrix_world.copy()
inv.invert()

ob1.matrix_world = ob1.matrix_world @ inv

vec = ob2.location - ob1.location

quat = vec.to_track_quat(‘Z’, ‘Y’)

ob1.rotation_quaternion = quat

Yeah rotation_quaternion does nothing. Instead, modify the matrix.

ob1.matrix_world @= quat.to_matrix().to_4x4()

Note that augmented multiplication requires the object to be modified to have a zeroed rotation, since the rotation matrix is absolute.

1 Like

Hey, thank you for the help! It still doesn’t match exactly though. I’m wondering if maybe the answer is to get a tangent space matrix with N, a random up vec , and the cross product and then somehow compare those to the same matrix of the B plane? And then that difference in angles could somehow tell me the offset?

2020-01-04_17-20-36

I’m not sure what the right approach for making plane A and plane B have the same alignment

Remember seeing this a while back when I was making a move origin addon.

Tweaked it to work in object mode. Select two planes. The active plane is the target.

import bpy 
import bmesh
from mathutils import Matrix

context = bpy.context
deg = context.evaluated_depsgraph_get()
objs = context.selected_objects

A = context.object
B = objs[objs.index(A) - 1]

src_mw = A.matrix_world.copy()
src_bm = bmesh.new()
src_bm.from_object(A, deg)
src_bm.faces.ensure_lookup_table()
src_face = src_bm.faces[0]
src_o = src_face.calc_center_median()
src_normal = src_face.normal
src_tan = src_face.calc_tangent_edge()

# This is the target, we change the sign of normal to stick face to face
dst_mw = B.matrix_world.copy()
dst_bm = bmesh.new()
dst_bm.from_object(B, deg)
dst_bm.faces.ensure_lookup_table()
dst_face = dst_bm.faces[0]
dst_o = dst_face.calc_center_median()
dst_normal = -(dst_face.normal)
dst_tan = (dst_face.calc_tangent_edge())

vec2 = src_normal @ src_mw.inverted()
matrix_rotate = dst_normal.rotation_difference(vec2).to_matrix().to_4x4()

vec1 = src_tan @ src_mw.inverted()
dst_tan = dst_tan @ matrix_rotate.inverted()
mat_tmp = dst_tan.rotation_difference(vec1).to_matrix().to_4x4()
matrix_rotate = mat_tmp @ matrix_rotate
matrix_translation = Matrix.Translation(src_mw @ src_o)

# This line applied the matrix_translation and matrix_rotate
B.matrix_world = matrix_translation @ matrix_rotate.to_4x4()

# We need to recalculate these value since we change the matrix_world
dst_mw = B.matrix_world.copy()
dst_bm = bmesh.new()
dst_bm.from_object(B, deg)
dst_bm.faces.ensure_lookup_table()
dst_face = dst_bm.faces[0]
dst_o = dst_face.calc_center_median()

# Be Careful, the order of the matrix multiplication change the result,
# We always put the transform matrix on "Left Hand Side" to perform the task
dif_mat = Matrix.Translation(B.location - dst_mw @ dst_o)
B.matrix_world = dif_mat @ B.matrix_world
1 Like

Thank you so much ! I will have to study it to understand why this works exactly but it is doing everything I wanted. This is perfect.

Blender community is unreal :slight_smile:

1 Like