-
-
Save SEVEZ/7c9251661a00afc667bc to your computer and use it in GitHub Desktop.
# Latest version, uses Tumble Pivot Point viewport | |
# feature, and proprietary algorithm, works in all recent | |
# versions of Maya, Python 2.7 / 3+. Gives more predictable | |
# and stable results. | |
# Pavel Sevets 2022 | |
import maya.cmds as mc | |
import maya.api.OpenMaya as om | |
from math import pi | |
def PS_perspOrthoToggle(): | |
if mc.contextInfo( 'tumbleContext', ex=1, ): | |
mc.tumbleCtx( 'tumbleContext', e=1, ot=1, asp=1, lt=0 ) | |
panel = mc.getPanel( wf=1 ) | |
if 'modelPanel' not in panel: return 1 | |
cam = mc.modelPanel( panel, q=1, cam=1 ) | |
if mc.objectType( cam, i='camera' ): | |
cam = mc.listRelatives( cam, p=1 )[0] | |
if not mc.camera( cam, q=1, o=1 ): | |
# store camera's FOV in custom attribute | |
if not mc.attributeQuery( 'p2oFOV', node=cam, ex=1 ): | |
mc.addAttr( cam, ln='p2oFOV', at='float', dv=0, h=1 ) | |
mc.setAttr( cam + '.p2oFOV', mc.camera( cam, q=1, hfv=1 ) ) | |
# camera's transformation matrix | |
M = om.MMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ) | |
M = om.MTransformationMatrix( M ) | |
# quantize camera rotation to 90 degrees | |
oro = mc.xform( cam, q=1, ws=1, ro=1 ) | |
cro = [ round( r / 90.0 ) * pi / 2.0 for r in oro ] | |
oro = [ r * pi / 180.0 for r in oro ] | |
# calculating local space quaternion | |
# to correct camera's orientation | |
q1 = om.MEulerRotation( oro ).asMatrix() | |
q1 = om.MTransformationMatrix( q1 ).rotation(1) | |
q2 = om.MEulerRotation( cro ).asMatrix() | |
q2 = om.MTransformationMatrix( q2 ).rotation(1) | |
q = q2 * q1.inverse() | |
# rotate matrix with quaternion | |
M.rotateBy( q, om.MSpace.kObject ) | |
# get camera's tumble pivot and rotate pivot | |
tp = om.MVector( mc.camera( cam, q=1, wci=1 ) ) | |
tr = om.MVector( mc.xform( cam, q=1, ws=1, rp=1 ) ) | |
# recalc tumble pivot position | |
# in camera's local space | |
tp = M.asMatrix() * ( tp - tr ) | |
# rotate camera around it's tumble pivot | |
tp -= q.inverse().asMatrix() * tp | |
# translate camera to the new position | |
M.translateBy( tp, om.MSpace.kObject ) | |
# apply modified transform via matrix | |
mc.xform( cam, ws=1, m=M.asMatrix() ) | |
mc.viewPlace( cam, up=mc.camera( cam, q=1, wup=1 ), o=1 ) | |
# make manip aligned to screen axes | |
# comment two lines below to keep manip intact | |
rot = mc.xform( cam, q=1, ro=1, ws=1, a=1 ) | |
mc.manipPivot( o=rot ) | |
else: | |
ow = mc.camera( cam, q=1, ow=1 ) | |
coi = mc.camera( cam, q=1, coi=1 ) | |
M = om.MMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ) | |
M = om.MTransformationMatrix( M ).asRotateMatrix() | |
v = M.inverse() * om.MVector( 0.0, 0.0, -1.0 ) | |
tp = v * ( coi - ow ) | |
# correct camera's roll if | |
# it's upside down or tilted | |
wup = om.MVector( mc.camera( cam, q=1, wup=1 ) ) | |
# uncomment below to turn off roll correction | |
#''' | |
M = om.MMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ) | |
M = om.MTransformationMatrix( M ).asRotateMatrix() | |
v = M.inverse() * om.MVector( 0.0, 0.0, -1.0 ) | |
N = v ^ om.MVector( 0.0, 1.0, 0.0 ) | |
if N.length() >= 1E-5: | |
K = - ( N * wup ) / ( N * N ) | |
P = ( wup + K * N ).normal() | |
if P * om.MVector( 0.0, 1.0, 0.0 ) < 0.0: | |
P *= -1.0 | |
wup = P | |
# uncomment below to turn off roll correction | |
#''' | |
mc.xform( cam, ws=1, r=1, t=tp ) | |
mc.camera( cam, e=1, coi=ow ) | |
mc.viewPlace( cam, up=wup, p=1 ) | |
if mc.attributeQuery( 'p2oFOV', node=cam, ex=1 ): | |
mc.viewPlace( cam, fov=mc.getAttr( cam + '.p2oFOV' ) ) | |
return 0 | |
# PS_perspOrthoToggle() |
# Old Pymel based version | |
# Based on scripts by James Drew, Davide Alidosi from | |
# http://www.creativecrash.com/maya/script/persptoortho | |
# and Deniseich from | |
# http://www.creativecrash.com/maya/script/full-130-scripts-for-modeling-uv-video-tutorials-for-each | |
import maya.cmds as mc | |
import pymel.core.datatypes as dt | |
global gP2Ofov | |
def PS_perspOrthoToggle (): | |
#this gets the current active camera | |
cam = mc.modelPanel( mc.getPanel( wf=1 ), q=1, cam=1 ) | |
# cam = mc.modelPanel( 'modelPanel4', q=1, cam=1 ) | |
#if current camera is in orthographic mode return to perspective mode | |
if mc.camera( cam, q=1, o=1 ): | |
gP2Oow = mc.camera( cam, q=1, ow=1 ) | |
gP2Ocoi = mc.camera( cam, q=1, coi=1 ) | |
v = dt.TransformationMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ).asRotateMatrix().inverse() * dt.Vector(0,0,-1) | |
tp = v * ( gP2Ocoi - gP2Oow ) | |
mc.xform( cam, ws=1, r=1, t=tp ) | |
mc.camera( cam, e=1, coi=gP2Oow ) | |
mc.camera( cam, e=1, o=0 ) | |
global gP2Ofov | |
if gP2Ofov: mc.camera( cam, e=1, hfv=gP2Ofov ) | |
else: | |
#stores camera attributes for returning to persp | |
gP2Otr = mc.xform( cam, q=1, ws=1, t=1 ) | |
gP2Oro = mc.xform( cam, q=1, ws=1, ro=1 ) | |
gP2Ocoi = mc.camera( cam, q=1, coi=1 ) | |
global gP2Ofov | |
gP2Ofov = mc.camera( cam, q=1, hfv=1 ) | |
mc.camera( cam, e=1, o=1 ) | |
mc.camera( cam, e=1, ow=gP2Ocoi ) | |
v = dt.TransformationMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ).asRotateMatrix().inverse() * dt.Vector(0,0,-1) | |
#quantize camera rotation to 90 degrees | |
cro = [ round( ri / 90 ) * 90 for ri in gP2Oro ] | |
mc.xform( cam, ws=1, ro=cro ) | |
# match camera position to objects on screen | |
cp = dt.Vector( gP2Otr ) | |
tp = cp + v * gP2Ocoi | |
def _c( a, b ): return 1 if a > b else -1 | |
np = tp + gP2Ocoi * dt.Vector( _c( cp.x, tp.x ), _c( cp.y, tp.y ), _c( cp.z, tp.z ) ) | |
av = abs( v ) | |
n = av.index( max( av ) )[0] | |
tp[n] = np[n] | |
mc.xform( cam, ws=1, a=1, t=tp ) | |
#PS_perspOrthoToggle() |
# This version works with Maya API 2.0 and has no delay at start | |
# Based on scripts by James Drew, Davide Alidosi from | |
# http://www.creativecrash.com/maya/script/persptoortho | |
# and Deniseich from | |
# http://www.creativecrash.com/maya/script/full-130-scripts-for-modeling-uv-video-tutorials-for-each | |
import maya.cmds as mc | |
import maya.api.OpenMaya as om | |
global gP2Ofov | |
gP2Ofov = None | |
def PS_perspOrthoToggle (): | |
#this gets the current active camera | |
cam = mc.modelPanel( mc.getPanel( wf=1 ), q=1, cam=1 ) | |
# cam = mc.modelPanel( 'modelPanel4', q=1, cam=1 ) | |
#if current camera is in orthographic mode return to perspective mode | |
if mc.camera( cam, q=1, o=1 ): | |
gP2Oow = mc.camera( cam, q=1, ow=1 ) | |
gP2Ocoi = mc.camera( cam, q=1, coi=1 ) | |
M = om.MMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ) | |
v = om.MTransformationMatrix( M ).asRotateMatrix().inverse() * om.MVector( 0.0, 0.0, -1.0 ) | |
tp = v * ( gP2Ocoi - gP2Oow ) | |
mc.xform( cam, ws=1, r=1, t=[ tp.x, tp.y, tp.z ] ) | |
mc.camera( cam, e=1, coi=gP2Oow ) | |
mc.camera( cam, e=1, o=0 ) | |
global gP2Ofov | |
if gP2Ofov: mc.camera( cam, e=1, hfv=gP2Ofov ) | |
else: | |
#stores camera attributes for returning to persp | |
gP2Otr = mc.xform( cam, q=1, ws=1, t=1 ) | |
gP2Oro = mc.xform( cam, q=1, ws=1, ro=1 ) | |
gP2Ocoi = mc.camera( cam, q=1, coi=1 ) | |
global gP2Ofov | |
gP2Ofov = mc.camera( cam, q=1, hfv=1 ) | |
mc.camera( cam, e=1, o=1 ) | |
mc.camera( cam, e=1, ow=gP2Ocoi ) | |
M = om.MMatrix( mc.xform( cam, q=1, ws=1, m=1 ) ) | |
v = om.MTransformationMatrix( M ).asRotateMatrix().inverse() * om.MVector( 0.0, 0.0, -1.0 ) | |
#quantize camera rotation to 90 degrees | |
cro = [ round( ri / 90 ) * 90 for ri in gP2Oro ] | |
mc.xform( cam, ws=1, ro=cro ) | |
# match camera position to objects on screen | |
cp = om.MVector( gP2Otr[0], gP2Otr[1], gP2Otr[2] ) | |
tp = cp + v * gP2Ocoi | |
def _c( a, b ): return 1 if a > b else -1 | |
np = tp + om.MVector( _c( cp.x, tp.x ), _c( cp.y, tp.y ), _c( cp.z, tp.z ) ) * gP2Ocoi | |
av = [ abs( v.x ), abs( v.y ), abs( v.z ) ] | |
m = max( av ) | |
if m == av[0]: | |
tp.x = np.x | |
elif m == av[1]: | |
tp.y = np.y | |
else: | |
tp.z = np.z | |
mc.xform( cam, ws=1, a=1, t=[ tp.x, tp.y, tp.z ] ) | |
#PS_perspOrthoToggle() |
Hello,
Thanks for maintaining this script!
I'd like to have this functionality as I recently got into blender but now find myself back in maya for a project. I miss this a lot.
I have downloaded v3 and copied it into my documents maya version (2020) scripts folder.
I am unsure what I do with the python code but figured it might be a runtime command which I add via the hotkey editor? This way I can assign a hotkey to the command?
I've set the Tumble Tool settings advised but I get the following code:
# Error: line 1: ImportError: file <maya console> line 1: No module named PS_perspOrthoToggle #
Anyway, it's not working and I'm not sure if I've set it up correctly so asking for your help.
Thanks in advance.
Error: line 1: ImportError: file line 1: No module named PS_perspOrthoToggle
The fact the script is falling over so early in the code suggests to me the custom command cannot find the script?
Hey,
Thanks for getting back to me so quickly. Much appreciated.
This is what I have so far, I figured I was on the right track. Can you see anything wrong with how I have it setup?
change script name from PS_perspOrthoToggl_v3.py to PS_perspOrthoToggl.py
Ahhhh I have to rename the script file it self !
Nice. Works well now.
For the record the downloaded file is named
PS_perspOrthoToggl_v3.py
I had to rename it to
PS_perspOrthoToggle.py
Confusion over.
Got it. Thanks both.
v3 has been updated - there was a small problem with maintaining the scale after zooming an ortho view and then switching from ortho to persp.