Skip to content

Instantly share code, notes, and snippets.

@rraallvv
Last active January 29, 2019 11:04
Show Gist options
  • Save rraallvv/5959438 to your computer and use it in GitHub Desktop.
Save rraallvv/5959438 to your computer and use it in GitHub Desktop.
Blender Add-on to enable turntable rotation with the Z-axis up (Crtl+LeftMouseDrag)
'''
Enable turntable rotation with Z axis up. This addon allows you to have both rotations available, either the built-in trackball, or the turntable provided by the addon can be used at any time without the need to change the user preferences.
'''
bl_info = {
'name': 'Rotate Turntable Z-axis Up',
'author': '',
'version': (0, 0, 1),
'blender': (2, 6, 7),
'location': '3d view > Ctrl + LMB-drag',
'description': 'Enable turntable rotation with Y axis up.',
'wiki_url': '',
'tracker_url': '',
'category': '3D View'}
import bpy
from mathutils import *
from math import *
class RotateTurntableZUp(bpy.types.Operator):
'''Turntable rotation Z-axis up.'''
bl_idname = "view3d.turntable_z_up"
bl_label = "Turntable rotation Z-axis up"
angle_yaw=0
angle_pitch=0
mouse_last_pos=Vector((0,0))
axis_selected=0
do_alignment=True
def execute(self, context):
region_3d = context.space_data.region_3d
# world axis in world space
xa=Vector((1,0,0))
ya=Vector((0,1,0))
za=Vector((0,0,1))
# select Z axis to alignt the camera
camera_up_axis=za.copy()
camera_up_axis.rotate(region_3d.view_rotation.inverted())
world_up_axis=za
# find rotation yaw in camera space, rotation yaw in world space, separation angle between them, and the rotation needed to align the camera axis up in the world space
if camera_up_axis.y > 0:
camera_rotation_yaw=Quaternion(camera_up_axis,self.angle_yaw)
world_rotation_yaw=Quaternion(world_up_axis,self.angle_yaw)
separation_angle=atan2(camera_up_axis.y,camera_up_axis.x)-pi*0.5
rotation_alignment=Quaternion(za,separation_angle)
elif camera_up_axis.y < 0:
camera_rotation_yaw=Quaternion(camera_up_axis,-self.angle_yaw)
world_rotation_yaw=Quaternion(world_up_axis,-self.angle_yaw)
separation_angle=atan2(camera_up_axis.y,camera_up_axis.x)+pi*0.5
rotation_alignment=Quaternion(za,separation_angle)
else:
camera_rotation_yaw=Quaternion((0,0,0,1))
world_rotation_yaw=Quaternion((0,0,0,1))
separation_angle = 0
rotation_alignment=Quaternion((0,0,0,1))
# check if there are selected objects in case of the user preference to rotate around the selection pivot
selected_objects = len(bpy.context.selected_objects) > 0 and bpy.context.user_preferences.view.use_rotate_around_active
# find the pivot point location
if selected_objects:
saved_location = bpy.context.scene.cursor_location.copy()
bpy.ops.view3d.snap_cursor_to_selected()
pivot_location = bpy.context.scene.cursor_location.copy()
bpy.context.scene.cursor_location = saved_location
# rotate the view_location and view_rotation to perform the turn table rotation
if self.do_alignment:
# on invocation rotate the view_location to avoid the origin or the pivot to jump abruptly
if selected_objects:
region_3d.view_location=region_3d.view_location-pivot_location
region_3d.view_rotation=region_3d.view_rotation*Quaternion(za, separation_angle)
camera_normal_axis=za
camera_normal_axis.rotate(region_3d.view_rotation)
region_3d.view_location.rotate(Quaternion(camera_normal_axis, separation_angle))
if selected_objects:
region_3d.view_location=region_3d.view_location+pivot_location
self.do_alignment=False
else:
# oter wise do the alignment
region_3d.view_rotation=region_3d.view_rotation*rotation_alignment
# compensate the rotation is there is objects selected, to rotate around the pivot point
if selected_objects:
camera_horizontal_axis=xa.copy()
camera_horizontal_axis.rotate(region_3d.view_rotation)
world_rotation_pitch=Quaternion(camera_horizontal_axis,self.angle_pitch)
pivot_to_camera = region_3d.view_location - pivot_location
pivot_to_camera.rotate(world_rotation_yaw*world_rotation_pitch)
region_3d.view_location = pivot_location + pivot_to_camera
# find rotation pitch in camera space
camera_rotation_pitch=Quaternion(xa,self.angle_pitch)
region_3d.view_rotation=region_3d.view_rotation*camera_rotation_yaw*camera_rotation_pitch
return {'FINISHED'}
def modal(self, context, event):
region_3d = context.space_data.region_3d
if event.type == 'MOUSEMOVE':
#find the yaw and pitch angles from the mouse position variation
mouse_pos=Vector((event.mouse_region_x,event.mouse_region_y))
self.angle_yaw=-(mouse_pos.x-self.mouse_last_pos.x)/200.0
self.angle_pitch=(mouse_pos.y-self.mouse_last_pos.y)/200.0
self.execute(context)
self.mouse_last_pos=Vector((event.mouse_region_x,event.mouse_region_y))
elif event.type in {'LEFTMOUSE', 'MIDDLEMOUSE', 'RIGHTMOUSE', 'ESC'}:
return {'FINISHED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.space_data.type == 'VIEW_3D':
region_3d = context.space_data.region_3d
self.mouse_last_pos=Vector((event.mouse_region_x,event.mouse_region_y))
self.axis_selected=0
self.do_alignment=True
context.window_manager.modal_handler_add(self)
if region_3d.view_perspective == 'CAMERA':
region_3d.view_perspective = 'PERSP'
return {'RUNNING_MODAL'}
else:
return {'CANCELLED'}
def register():
bpy.utils.register_class(RotateTurntableZUp)
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name="3D View", space_type='VIEW_3D')
kmi = km.keymap_items.new('view3d.turntable_z_up', 'EVT_TWEAK_L', 'ANY', shift=False, ctrl=True, alt=False)
def unregister():
bpy.utils.unregister_class(RotateTurntableZUp)
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps['3D View']
for kmi in km.keymap_items:
if kmi.idname == 'view3d.turntable_z_up':
km.keymap_items.remove(kmi)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment