BS Modify Pivot Addon Release!

add-ons

(juang3d) #1

Hi guys.

I want to present our first addon for Blender.

In this case, since we come from 3dsmax and Maya, we missed a lot the ability to change the objects pivot orientation and I saw a lot of people here in the forums asking for the same thing, some people suggested to use the Hook modifer, but we wanted something simpler, similar to the ¨Affect Pivot Only¨ button present in 3dsmax… so we did it :slight_smile:

Here you have a video explaining it:

And here is the direct download link to the addon:

http://www.bone-studio.com/blenderaddons/BS_Modify_Pivot.zip

Hope you like it, comment it and if you have improvements in mind or you find any bugs, please tell me, I´ll try to fix it when I have a bit of time.

Cheers!


(Martynas Žiemys) #2

I thought it would be nice to have it as a modal operator and use it on the fly while working. It seems a bit more convenient. Like this:


You are welcome to use the code if you wish since I already wrote it (it might need a bit of cleaning up):


import bpy
selection = list()

def AlignPivotRotation(object, pivot_object):
    rotation = object.matrix_world.to_quaternion().inverted() * pivot_object.matrix_world.to_quaternion()  
    for v in object.data.vertices:
        v.co = rotation.inverted().to_matrix().to_4x4() * v.co
    object.matrix_world *= rotation.to_matrix().to_4x4()
    return 
def AlignPivotLocation(object, pivot_object):
    # remember selection, active, cursor location and mode
    original_cursor_location = bpy.context.scene.cursor_location.copy()
    original_selection = list()
    if len(bpy.context.selected_objects): 
        for everyobject in bpy.context.selected_objects:
            original_selection.append(everyobject)
    original_active = bpy.context.scene.objects.active
    original_mode = bpy.context.object.mode 
    bpy.ops.object.mode_set(mode = 'OBJECT')
    bpy.ops.object.select_all(action='DESELECT')
    
    # set pivot location
    bpy.context.scene.cursor_location = pivot_object.location
    object.select = True
    bpy.context.scene.objects.active = object
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
    
    # reset selection, active, cursor location and mode
    bpy.ops.object.select_all(action='DESELECT')
    if original_selection:
        for every_object in original_selection:
            every_object.select = True 
    bpy.context.scene.objects.active = original_active
    bpy.ops.object.mode_set(mode = original_mode)  
    bpy.context.scene.cursor_location = original_cursor_location
    return

class MZPivot(bpy.types.Operator):
    bl_idname = "object.mz_pivot"
    bl_label = "Pivot" 
    bl_options = {"REGISTER", "UNDO"} 
    operation = bpy.props.EnumProperty(
    name="Operation:",
    description="Operation - Rotate or Grab",
    items=(
        ('ROTATE', "ROTATE", ""),
        ('GRAB', "GRAB", "")
           ),
    default='GRAB',
    )
    original_mode = bpy.props.StringProperty()
    object_name = bpy.props.StringProperty()
    start = 0 
    def modal(self, context, event):
        self.start += 1             
        if self.start == 1:
            if self.operation == 'ROTATE':
                bpy.ops.transform.rotate('INVOKE_DEFAULT') 
            if self.operation == 'GRAB':
                bpy.ops.transform.transform('INVOKE_DEFAULT') 
        if event.type in {'ENTER', 'LEFTMOUSE'}:  # modal rotation finished:     
            # math    
            AlignPivotRotation(bpy.data.objects[self.object_name], bpy.context.scene.objects.active)
            bpy.data.objects[self.object_name].rotation_euler = bpy.context.scene.objects.active.rotation_euler # in case greater than 180 degrees
            AlignPivotLocation(bpy.data.objects[self.object_name], bpy.context.scene.objects.active)                 
            # cleanup
            bpy.ops.object.delete()            
            if selection:
                for obj in selection:
                    obj.select = True                         
            bpy.context.scene.objects.active = bpy.data.objects[self.object_name]
            bpy.ops.object.mode_set(mode = self.original_mode)                                  
            del(selection[:])
            return {'FINISHED'}   
                   
        if event.type in {'RIGHTMOUSE', 'ESC', 'SPACE'}:  # modal rotation canceled: 
            bpy.ops.object.delete()
            if selection:
                for obj in selection:
                    obj.select = True
            bpy.context.scene.objects.active = bpy.data.objects[self.object_name]
            bpy.ops.object.mode_set(mode = self.original_mode)
            del(selection[:])
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.object is not None : 
            # remember stuff
            self.original_mode = context.object.mode
            self.object_name = context.active_object.name
            bpy.ops.object.mode_set(mode = 'OBJECT')           
            if len(context.selected_objects): 
                for objs in context.selected_objects:
                    selection.append(objs)
                bpy.ops.object.select_all(action='DESELECT') 
                           
            tempPivot = bpy.data.objects.new( ("Pivot Point of " + self.object_name), None )
            tempPivot.show_x_ray = 1  
            tempPivot.show_axis = 1   
            tempPivot.matrix_world = bpy.context.scene.objects.active.matrix_world # place temp empty at the center of the object
            bpy.context.scene.objects.link( tempPivot )
            bpy.ops.object.select_all(action='DESELECT')
            tempPivot.select = True 
            bpy.context.scene.objects.active = tempPivot            
            context.window_manager.modal_handler_add(self)            
            return {'RUNNING_MODAL'}
        else:
            self.report({'ERROR'}, "No active object")
            return {'CANCELLED'}
            

def register():
    bpy.utils.register_class(MZPivot)

def unregister():
    bpy.utils.unregister_class(MZPivot)


if __name__ == "__main__":
    register()

(juang3d) #3

Pretty cool Martin, I´ll implement it as soon as I have some time, but as something optional, one of the cool things with our addon is that the axis created is an standard object, so you can do whatever you want to it, a friend asked me if it could be constrained to another object, don´t ask me why, but it seems that it is something standard in maya´s world.

But in any case your implementation seems great too for many situations, how does this affect to the transform values and the delta transform values?

Cheers and thanks for the code and the suggestion! :smiley:


(Martynas Žiemys) #4

I did like the idea of separate object very much as well. I create an empty its just that it gets deleted when the operation is finished, so you can use all the usual rotate and grab snapping, numerical input, axis constraints and so on. I also like the idea that it can toggle between edit and object mode as needed, because I need to set origin location for symmetrize action quite a lot and want to be able to do it from edit mode.


(juang3d) #5

Your implementation is pretty cool, I’ll include it as soon as i can.

At first I thought to do it modal but since it is my first add on I have not too much experience with Blender and Python, so finally I decided to do it as it is right now, and my testers liked it more than if it were modal, but I clearly see the benefits of being modal, specially the one you named about edit mode :slight_smile:

Cheers and thanks again!


(Birkov) #6

Very good addon. Coming from 3dsmax, moving pivots in this way is one of this features that you love.


(juang3d) #7

Totally agree!!

But I´m happy that this won´t be needed in 2.8! :smiley:

Finally the cursor witl have also orientation, so the cursor workflow will debunk this, and IMHO it is much better than this :slight_smile:

Cheers!


(kynu) #8

not really… As we don’t have yet transform operations for the cursor. It just snaps, isn’t it?


(juang3d) #9

But we will have those transform values soon, it was confirmed to me by Pablo Vazquez :slight_smile:


(CYNIC78) #10

Nice one. It will helps to those who jumped in blender from 3d max :slight_smile:
One more feature i miss in blender is “turn hidden edge” command very usefull for low poly modelling.