Skip to content

Instantly share code, notes, and snippets.

@rraallvv
Created July 12, 2013 17:10
Show Gist options
  • Save rraallvv/5986060 to your computer and use it in GitHub Desktop.
Save rraallvv/5986060 to your computer and use it in GitHub Desktop.
Adds turntable rotation that rotates freely independently of the view rotation, with out gimbal lock.
bl_info = {
'name': 'Rotate trackball in all axis',
'author': '',
'version': (0, 0, 1),
'blender': (2, 6, 7),
'location': '3d view > Alt + LMB-drag',
'description': 'Add trackball rotation that rotates freely around all axes.',
'wiki_url': '',
'tracker_url': '',
'category': '3D View'}
import bpy
from mathutils import *
from math import *
class RotateTrackballAllAxes(bpy.types.Operator):
'''Trackball rotation in all axes.'''
bl_idname = "view3d.trackball_all_axes"
bl_label = "Trackball rotation in all axes"
angle_yaw=0
angle_pitch=0
mouse_last_pos=Vector((0,0))
def execute(self, context):
region_3d = context.space_data.region_3d
xa=Vector((1,0,0))
ya=Vector((0,1,0))
# calculates rotation in the camera space
camera_rotation_pitch=Quaternion(xa,self.angle_pitch)
camera_rotation_yaw=Quaternion(ya,self.angle_yaw)
selected_objects = len(bpy.context.selected_objects) > 0 and bpy.context.user_preferences.view.use_rotate_around_active
if selected_objects:
'''
calculates view_location rotation in world space to counteract
the pivot rotating around keeping it in it's current position
'''
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
xa.rotate(region_3d.view_rotation)
ya.rotate(region_3d.view_rotation)
world_rotation_pitch=Quaternion(xa,self.angle_pitch)
world_rotation_yaw=Quaternion(ya,self.angle_yaw)
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
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))
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(RotateTrackballAllAxes)
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name="3D View", space_type='VIEW_3D')
kmi = km.keymap_items.new('view3d.trackball_all_axes', 'EVT_TWEAK_L', 'ANY', shift=False, ctrl=False, alt=True)
def unregister():
bpy.utils.unregister_class(RotateTrackballAllAxes)
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps['3D View']
for kmi in km.keymap_items:
if kmi.idname == 'view3d.trackball_all_axes':
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