2
$\begingroup$

I'm trying to find a way to place an object on the selected face from another object according the normal face.

I'd like the local orientation of my first object correspond to the normals of the selected face from my second object.

This is my code.

import bpy
import bmesh
from mathutils import Vector


class TestPanel(bpy.types.Panel):
    bl_idname = "object.test_panel"
    bl_label = "Test Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'


    def draw(self, context):
        layout = self.layout
        layout.operator("object.clone_object", text="Add Suzanne")



class AddCloneObject(bpy.types.Operator):
    bl_idname = "object.clone_object"
    bl_label = "Clone object"

    def execute(self, context):

        if context.object.mode == 'EDIT':
           bpy.ops.object.mode_set(mode='OBJECT')
           obj = bpy.context.active_object

           bm = bmesh.new()
           bm.from_mesh(obj.data)

           selected_faces = [f for f in bm.faces if f.select]

           for face in selected_faces:

               face_location = face.calc_center_median() 
               loc_world_space = obj.matrix_world * Vector(face_location) 
               z = Vector((0,0,1))

               angle = face.normal.angle(z)
               axis = z.cross(face.normal)
               bpy.context.scene.cursor_location = loc_world_space

               bpy.ops.mesh.primitive_monkey_add(radius=0.5) 

               bpy.ops.transform.rotate(value=angle, axis=axis)


               print("face location = ", loc_world_space)
               print("angle = ", angle)
               print("axis = ", axis)
               print("Suzanne = ", context.active_object.matrix_world)

           bm.to_mesh(obj.data)
           bm.free()

           return {'FINISHED'}

       else:
           self.report({'INFO'}, "Need to be in edit_mode")

           return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

The X and Y axis are good, but the Z axis seems not to undergo rotation.

$\endgroup$

1 Answer 1

3
$\begingroup$

Made a couple of changes to this script, the main one is using the Vector.rotation_difference method instead of the angle method. This one calculates rotation in all 3 axes.

import bpy
import bmesh
from mathutils import Vector
from math import degrees # Added for more readable printing of rotation angles

class TestPanel(bpy.types.Panel):
    bl_idname = "object.test_panel"
    bl_label = "Test Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'

    def draw(self, context):
        layout = self.layout
        layout.operator("object.clone_object", text="Add Suzanne")


class AddCloneObject(bpy.types.Operator):
    bl_idname = "object.clone_object"
    bl_label = "Clone object"

    def execute(self, context):

        if context.object.mode == 'EDIT':
           bpy.ops.object.mode_set(mode='OBJECT')
           obj = bpy.context.active_object

           bm = bmesh.new()
           bm.from_mesh(obj.data)

           selected_faces = [f for f in bm.faces if f.select]

           for face in selected_faces:

               face_location = face.calc_center_median() 
               loc_world_space = obj.matrix_world * Vector(face_location) 
               z = Vector((0,0,1))

               # Changes start here
               rot = z.rotation_difference( face.normal ).to_euler()
               bpy.context.scene.cursor_location = loc_world_space

               bpy.ops.mesh.primitive_monkey_add(radius=0.5) 

               bpy.context.object.rotatation_euler = rot

               print("face location = ", loc_world_space)
               print("rotation = ", [degrees(a) for a in rot] )
               print("Suzanne = ", context.active_object.matrix_world)
               # And End here

           bm.to_mesh(obj.data)
           bm.free()

           return {'FINISHED'}

       else:
           self.report({'INFO'}, "Need to be in edit_mode")

           return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

For Blender 3.6

import bpy, bmesh
from mathutils import Vector
from math import degrees

# Check if the object is in edit mode
if bpy.context.object.mode == 'EDIT':
    # Switch to object mode
    bpy.ops.object.mode_set(mode='OBJECT')
    obj = bpy.context.active_object

    # Create a new bmesh object from the object's mesh data
    bm = bmesh.new()
    bm.from_mesh(obj.data)

    # Get a list of selected faces in the bmesh
    selected_faces = [f for f in bm.faces if f.select]

    # Iterate over each selected face
    for face in selected_faces:
        # Calculate the center location of the face
        face_location = face.calc_center_median() 
        # Convert the face location to world space
        loc_world_space = obj.matrix_world @ Vector(face_location) 
        # Define a vector pointing in the positive Z direction
        z = Vector((0,0,1))

        # Changes start here
        # Calculate the rotation difference between the Z vector and the face normal
        rot = z.rotation_difference(face.normal).to_euler()
        # Set the 3D cursor location to the world space location of the face
        bpy.context.scene.cursor.location = loc_world_space

        # Add a monkey primitive to the scene
        bpy.ops.mesh.primitive_monkey_add()

        # Set the rotation of the monkey object to the calculated rotation
        bpy.context.object.rotation_euler = rot

        # Print the face location, rotation, and the world matrix of the monkey object
        print("face location = ", loc_world_space)
        print("rotation = ", [degrees(a) for a in rot])
        print("Suzanne = ", bpy.context.active_object.matrix_world)
        # And End here

    # Update the object's mesh data with the modified bmesh
    bm.to_mesh(obj.data)
    bm.free()

enter image description here

$\endgroup$
3
  • $\begingroup$ Thanks for your answer, but the probleme stay the same. The Z axis got the good direction but his rotation value is not the same as the Z axis of the normal face :( $\endgroup$
    – pistiwique
    Commented Dec 12, 2015 at 12:31
  • $\begingroup$ I see, shame. Will have another look when I can. $\endgroup$
    – TLousky
    Commented Dec 12, 2015 at 15:29
  • 1
    $\begingroup$ Thanks, but i finally find the solution in the answer of CoDEmanX from this question : blender.stackexchange.com/questions/7150/… $\endgroup$
    – pistiwique
    Commented Dec 12, 2015 at 18:20

You must log in to answer this question.

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