Skip to content

Instantly share code, notes, and snippets.

@SEVEZ
Last active January 11, 2024 10:50
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SEVEZ/7c9251661a00afc667bc to your computer and use it in GitHub Desktop.
Save SEVEZ/7c9251661a00afc667bc to your computer and use it in GitHub Desktop.
Switch between perspective and matching orthographic view. The latest version is v3. #Release
# 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()
@ElasticParty
Copy link

ElasticParty commented May 3, 2022

@SEVEZ Please support for Maya 2023, Can't imagine my modeling life without it too!
This is one of the best script ever
Many Thank!!!!!

@SEVEZ
Copy link
Author

SEVEZ commented May 3, 2022

Guys, 2023 support is in progress, stay tuned

@markplayford
Copy link

markplayford commented May 3, 2022 via email

@SEVEZ
Copy link
Author

SEVEZ commented May 3, 2022

I guess it should work fine with some minor tweaks (if any), just convert syntax from python 2.7 to 3.9. But haven’t tested it yet myself

@ElasticParty
Copy link

I'm getting the same error in maya 22 and 23...# Error: line 1: SyntaxError: file line 1: name 'gP2Ofov' is used prior to global declaration.
I don't know how it works for you @markplayford

@ElasticParty
Copy link

Guys, 2023 support is in progress, stay tuned

thank you man!!!

@vaticanshadow
Copy link

pls update :( this is that one script I can't do without..

@mzs101
Copy link

mzs101 commented Jun 9, 2022

any news?

@proleskovskiy-i
Copy link

Thank you. Can not wait. :)

@JPEGjackal
Copy link

Guys, 2023 support is in progress, stay tuned

Hello! Any estimation on this?

@AerEbi
Copy link

AerEbi commented Jul 9, 2022

Can't work as I want without it in 2023.
I'm waiting...

@iIbrahimAhmed
Copy link

any progress in maya 2023 ?

@Njordy
Copy link

Njordy commented Aug 31, 2022

Error: name 'gP2Ofov' is used prior to global declaration

@SEVEZ
Copy link
Author

SEVEZ commented Sep 17, 2022

Hello guys, and apologies for late response. Uploaded an updated version, works in all recent versions of Maya, and Python 2.7 / 3+. Download v3 and use the same way as before. This version relies on Tumble Pivot point feature and uses a proprietary algorithm now. Proven to give a more predictable and stable result. Cheers

P.S. If you prefer to have your current manipulator axes intact when switching, comment out lines 72 and 73 by putting # in the beginning of the commands.

@Njordy
Copy link

Njordy commented Sep 17, 2022

Thank you!! :)

Sadly, I have the same "# Error: name 'gP2Ofov' is used prior to global declaration" as before...

@iIbrahimAhmed
Copy link

Hello guys, and apologies for late response. Uploaded an updated version, works in all recent versions of Maya, and Python 2.7 / 3+. Download v3 and use the same way as before. This version relies on Tumble Pivot point feature and uses a proprietary algorithm now. Proven to give a more predictable and stable result. Cheers

P.S. If you prefer to have your current manipulator axes intact when switching, comment out lines 72 and 73 by putting # in the beginning of the commands.

Thank You :)

@Davinci-D7
Copy link

Thank you!! :)
Sadly, I have the same "# Error: name 'gP2Ofov' is used prior to global declaration" as before...

Which maya version you're using. It works fine for me, tested on 2018 and 2020.

@Njordy
Copy link

Njordy commented Sep 18, 2022

@SEVEZ
Copy link
Author

SEVEZ commented Sep 18, 2022

Download v3, not v2. GitHub doesn’t let me reorder the files, alas.

@Njordy
Copy link

Njordy commented Sep 18, 2022

Download v3, not v2. GitHub doesn’t let me reorder the files, so v3 is in the bottom.

Ah, right!! I was using v2. :) Thanks. It works now!

@proleskovskiy-i
Copy link

Hello guys, and apologies for late response. Uploaded an updated version, works in all recent versions of Maya, and Python 2.7 / 3+. Download v3 and use the same way as before. This version relies on Tumble Pivot point feature and uses a proprietary algorithm now. Proven to give a more predictable and stable result. Cheers

P.S. If you prefer to have your current manipulator axes intact when switching, comment out lines 72 and 73 by putting # in the beginning of the commands.

Thank you very much. Everything works. Great job :)

@ElasticParty
Copy link

Thank you!!!!!!!!!! for all your efforts, everything works perfectly!!!!!!!

@SEVEZ
Copy link
Author

SEVEZ commented Sep 21, 2022

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.

@markesmith
Copy link

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

@ZergatulUA
Copy link

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?

image

@markesmith
Copy link

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?

image

@markesmith
Copy link

The fact the script is falling over so early in the code suggests to me the custom command cannot find the script?

@iIbrahimAhmed
Copy link

iIbrahimAhmed commented Jan 11, 2024

markesmith

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?

image

change script name from PS_perspOrthoToggl_v3.py to PS_perspOrthoToggl.py

@markesmith
Copy link

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.

@markesmith
Copy link

Got it. Thanks both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment