5
$\begingroup$

Help me rotation new object by normal a face other object. I have code that works half. The axes at the selected polygon and the new object must be the same

code - http://pasteall.org/632513/python

scene - http://pasteall.org/blend/index.php?id=48131

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

code - http://pasteall.org/632513/python

scene - http://pasteall.org/blend/index.php?id=48131

$\endgroup$
3
  • $\begingroup$ The MathViz addon is very useful to visualize matrices, quats and vecs. Is the normal axis in image above in local or global coordinates? $\endgroup$
    – batFINGER
    Oct 25, 2017 at 4:14
  • $\begingroup$ I do not understand ... The manipulator in normal mode i.imgur.com/PnOisQi.png I need the local axis of the new object to look the same as this normal $\endgroup$ Oct 25, 2017 at 8:51
  • 1
    $\begingroup$ if you encounter some issue with 2.8 replace every "*" with "@" wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API $\endgroup$
    – Fox
    Apr 24, 2019 at 0:17

3 Answers 3

8
$\begingroup$

Align to vector using Vector.rotation_difference(v)


Altered the script from this answer to find the quaternion rotation difference between the local z axis of the edit mesh and the normal of its selected (active) face.

Run script with target object in edit mode, one face selected and active. An object in scene named "Cube.001" will be located at face centre and oriented by face normal.

import bpy
from mathutils import Matrix, Vector
import bmesh
context = bpy.context
obj = context.edit_object
mw = obj.matrix_world.copy()
bm = bmesh.from_edit_mesh(obj.data)
# for this example jmake a face active
face = bm.select_history.active
o = face.calc_center_median()
# calculate the axis dif in local coords

axis_src = face.normal
# local z-axis
axis_dst = Vector((0, 0, 1))

matrix_rotate = mw.to_3x3()
matrix_rotate = matrix_rotate * axis_src.rotation_difference(axis_dst).to_matrix()
matrix_translation = Matrix.Translation(mw * o) # 

obj2 = context.scene.objects.get("Cube.001")
obj2.matrix_world = matrix_translation * matrix_rotate.to_4x4()

enter image description here Result of script. Moved cube in edit mode, showing local coords.

$\endgroup$
12
  • $\begingroup$ Sumptuously! That's what I needed. Many thanks $\endgroup$ Oct 25, 2017 at 10:23
  • $\begingroup$ Look at the top polygon does not work. i.imgur.com/JqYfL7F.gifv $\endgroup$ Oct 25, 2017 at 19:59
  • $\begingroup$ @ВладКиндюшов whoops, should have checked that. Anyhoo, think I have it now. $\endgroup$
    – batFINGER
    Oct 26, 2017 at 6:32
  • $\begingroup$ I add ".inverted()" in to "axis_src.rotation_difference(axis_dst).to_matrix()" line 18 i.imgur.com/lSksTnW.gifv $\endgroup$ Oct 27, 2017 at 19:40
  • 2
    $\begingroup$ Think using BMFace.calc_tangent will give us the other alignment vector (that the normal axes are showing) to align object x axis to. (can make the rotation matrix with Matrix(norm, tangent, norm.cross(tangent)). Apologies. $\endgroup$
    – batFINGER
    Oct 28, 2017 at 0:07
7
$\begingroup$

Alexander Nedovizin solved this problem

import bpy
from mathutils import Matrix, Vector
import bmesh
context = bpy.context
obj = context.edit_object
mw = obj.matrix_world.copy()
bm = bmesh.from_edit_mesh(obj.data)
face = bm.select_history.active
o = face.calc_center_median()

axis_src = face.normal
axis_src2 = face.calc_tangent_edge()
axis_dst = Vector((0, 0, 1))
axis_dst2 = Vector((0, 1, 0))

vec2 = axis_src * obj.matrix_world.inverted()
matrix_rotate = axis_dst.rotation_difference(vec2).to_matrix().to_4x4()

vec1 = axis_src2 * obj.matrix_world.inverted()
axis_dst2 = axis_dst2*matrix_rotate.inverted()
mat_tmp = axis_dst2.rotation_difference(vec1).to_matrix().to_4x4()
matrix_rotate = mat_tmp*matrix_rotate
matrix_translation = Matrix.Translation(mw * o) #

obj2 = context.scene.objects.get("Cube.001")
obj2.matrix_world = matrix_translation * matrix_rotate.to_4x4()
$\endgroup$
2
  • $\begingroup$ From 2.8+ version you have to change replace "mw * o" with "mw @ o". But it still does not work for Blender 3.2. $\endgroup$
    – Lala_Ghost
    Aug 10, 2022 at 7:56
  • $\begingroup$ Lala_Ghost you need to replace all * with @. This solution is the only one that worked for me. $\endgroup$
    – APEC
    Mar 13, 2023 at 10:45
3
$\begingroup$

I had to modify Alexander's solution a bit to make it work:

import bpy
import mathutils
C = bpy.context
cursor = C.scene.cursor
obj = C.active_object
p = obj.data.polygons

#get the normal and center of the selected face
normal = obj.data.polygons[p.active].normal
center = obj.data.polygons[p.active].center

#generate a quaternion rotation from the normal vector
up = normal.to_track_quat('X', 'Y')

print(up)

#set the cursor to the center location and rotate it to match the up vector
cursor.location = center
cursor.rotation_quaternion = up
cursor.rotation_quaternion.to_euler()
#get the object world matrix
mat = obj.matrix_world

print(mat)
#generate the location and rotation
rot = cursor.rotation_quaternion.to_euler()
print(rot)
loc = mat @ cursor.location.copy()

obj2 = C.scene.objects.get("Cube.001")
obj2.location = loc
obj2.rotation_euler = rot

#bpy.ops.object.mode_set(mode='OBJECT')
#bpy.ops.mesh.primitive_cube_add(location = loc, size = 0.1, rotation =rot)
#bpy.ops.object.empty_add(type='ARROWS',location = loc, rotation =rot)
$\endgroup$

You must log in to answer this question.

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