Small scripts in maya using pymel

Hi, I been trying to learn pymel for maya and tool development too. so for practice I’m converting mel script to pymel. Thought this will help me understand the logic and the mathematical calculations and their syntax to implement them. I am not understanding the matrix and vector syntax in the script. I know the theory but getting stuck in syntax. Please can I get some advice and suggestions, and check where I’m making mistake.

import pymel.core as pm
import pymel.core.datatypes as pdt




def reSet(*args):
    
    # This proc resets the values back to 0, and 1 for the zoom
    resetCam = pm.optionMenuGrp(whichCam, query=True, value=True)

    pm.setAttr(resetCam + ".panZoomEnabled", 0)
    pm.setAttr(resetCam + ".horizontalPan", 0)
    pm.setAttr(resetCam + ".verticalPan", 0)
    pm.setAttr(resetCam + ".zoom", 1)


    pm.floatSliderGrp(x,e=True,value=0)
    pm.floatSliderGrp(y,e=True,value=0)
    pm.floatSliderGrp(z,e=True,value=0)




def zoomeratorUpdate(*args):
    cam = pm.optionMenuGrp(whichCam, query= True, value= True)
    hMaxOffset = pm.getAttr((cam + ".horizontalFilmAperture")/2)
    vMaxOffset = pm.getAttr((cam + ".verticalFilmAperture")/2)

    offx = pm.floatSliderGrp(edit=True, value= (pm.getAttr(cam + ".horizontalPan")), minValue=hMaxOffset, maxValue=hMaxOffset)
    offy = pm.floatSliderGrp(edit=True, value= (pm.getAttr(cam + ".verticalPan")), minValue=vMaxOffset, maxValue=vMaxOffset)
    offz = pm.floatSliderGrp(edit=True, value= (pm.getAttr(cam + ".zoom")))

    if (pm.objExists(cam + "_pointblastEXp")):
        pm.floatSliderGrp(offx, edit=True, enable=0)
        pm.floatSliderGrp(offy, edit=True, enable=0)
        pm.checkBox(pointBlastOption, edit=True, value=1)
        pm.button(reset, edit=True, enable=True)
    
    else: 
        pm.floatSliderGrp(offx, edit=True, enable=True)
        pm.floatSliderGrp(offy, edit=True, enable=True)
        pm.checkBox(pointBlastOption, edit=True, value=0)
        pm.button(reset, edit=True, enable=True)




def moveIt(*args):
    
    #This part actually changes the values of the offset attributes
    cam = pm.optionMenuGrp(whichCam, query= True, value= True)
    pm.setAttr(cam + ".panZoomEnabled", 1)
    
    offsetX = pm.floatSliderGrp(offx, query =True, value=True)
    offsetY = pm.floatSliderGrp(offy, query=True, value=True)

    pm.setAttr(cam+".horizontalPan", offsetX)
    pm.setAttr(cam+".verticalPan", offsetY)




def zoomIt(*args):
    
    # This part actually changes the values of the overscan Attributes
    cam = pm.optionMenuGrp(whichCam, query= True, value= True)
    pm.setAttr(cam + ".panZoomEnabled", 1)
    offsetZ = pm.floatSliderGrp(offz, query=True, value=True)

    pm.setAttr(cam+".zoom", offsetZ)




def pointblast(*args):

    _cam = pm.floatSliderGrp(whichCam, query=True, value=True)
    pointBlastFlag = pm.checkBox(pointBlastOption, query=True, value=True)
    if (pointBlastFlag ==0):
        if (pm.objExists(cam+"_pointblastEXP")):
            pm.delete(cam+"_pontblastEXp")
            moveIt()
            zoomIt()

    else:
        sel= []
        sel = pm.ls(selection=True, flatten=True)

        if (len(sel)=0):
            pm.error("Nothing selected")

        else:
            if (pm.objExists(cam+"_pointblastEXP")==0):

                expr = getExpressionForPointBlast(_cam, camShape, sel)
                pm.expression(name= (cam+"_pointblastExp"), string = expr, object="", alwaysEvaluate=True, unitConversion="all")


    zoomeratorUpdate()




def getMatrix(str(attr), *args)):
    
    v= []
    v = pm.getAttr(attr)
    mat = pdt.matrix(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15])

    return mat





def mult_vectorMatrix(vector(v), matrix(m), *args):
    
    v1 = pdt.matrix(v.x,v.y,v.z, 1)
    v2 = pdt.matrix(v1*m)

    return v2[0][0], v2[0][1], v2[0][2]




def angular2rad(float(angle), *args):
    
    
    pref = pm.currentUnit(query=True, angle=True)
    if ("deg"== pref):
        angle = angle * 0.0174532925

    return angle




def getExpressionForPointBlast(str(_cam), vec(camShape), str(sel), *args):
    
    
    obj = sel[0]
    #get camera aspect ratio
    aspectRatio = pm.camera(_cam, query=True, aspectRatio=True)

    #get camera horizontal and vertical film aspect
    hfa = pm.camera(_cam, query=True, horizontalFilmAperture=True)
    vfa = pm.camera(_cam, query=True, verticalFilmAperture=True)

    #set expression String
    expr = "camShape = world2screen(\""+_cam + "\", \"" + obj + "\"), \n"
    expr+= (_cam + ".horizontalPan = (camShape.x * " + hfa + "/2),\n ")
    expr+=(_cam + ".verticalPan = (camShape.y * " + vfa + ") /2 ),\n")

    return expr




def world2screen(str(cam), str(selection), *args):
    

    # get objects Position
    pos = pm.xform(selection, query=True, worldSpace=True, translation=True)
    posVec_ws = pos[0], pos[1], pos[3]

    #get camers world inverse matrix
    cam_matrix = pm.getMatrix(cam + ".worldInverseMatrix")

    #multiply objects position with camera world inverse Matrix
    posVec_cs = mult_vectorMatrix(posVec_ws, cam_matrix)

    #get camera scale
    camScale = pm.camera(cam, query=True, cameraScale=True)

    #get lens squeeze Ratio
    lensSqueezeRatio = pm.camera(cam, query=True, lensSqueezeRatio=True)

    #get horizontal and vertical film View
    hfv = pm.camera(cam, query=True, horizontalFieldOfView=True)
    vfv = pm.camera(cam, query=True, verticalFieldOfView=True)

    #convert to radians
    hfv = angular2rad(hfv)
    vfv = angular2rad(vfv)

    #set x, y dont divide by 0
    if (posVec_cs != 0 && tan(hfv) != 0 && camScale !=0):
        if (lensSqueezeRatio != 0):
            pntX = ((posVec_cs.x / (-posVec_cs.z)) / tan(hfv/2)) / camScale / lensSqueezeRatio

        else:
            pntX = posVec_cs

        pntY = ((posVec_cs.y / (-posVec_cs.z)) / tan(vfv/2)) / camScale)

    else:
        pntX = posVec_cs.x
        pntY = posVec_cs.y

    return pntX, pntY, 1.0    




def zoomrate():
    #get Cameras in the scene
    panelwf = pm.getPanel(withFocus=True)
    whichCam = pm.modelPanel(panelwf, query=True, camera=True)
    whichCamShape = pm.ls(whichCam, dag=True, allPaths=True, shapes=True)

    cameras = pm.ls(cameras=True)

    #create a window
    winname = ("CPWin")
    if pm.window(winname, query=True, exists=True):
        pm.deleteUI(winname)
    changewindow = pm.window(winname, title="PanCam Tool", widthHeight=(350,250), resizeToFitChildren=True, sizeable=True)
    pm.columnLayout()
    pm.frameLayout(label="Zoom Options",width= 350)
    pm.columnLayout()
    pm.optionMenuGrp(whichCam, label="Camera To Zoom",columnAlign= (1,'left'))
    pm.menuItem(label=whichCamShape[0])
    for i in cameras:
        pm.menuItem(label = i)

    pm.setParent('..')
    x = pm.floatSliderGrp(label="X",field=True,step=0.000001,minValue=-1.0,maxValue=1.0)

    y = pm.floatSliderGrp(label="Y",field=True,step=0.000001,minValue=-1.0,maxValue=1.0)

    z = pm.floatSliderGrp(label="Z",field=True,step=0.000001,minValue=-1.0,maxValue=1.0)

    pm.checkBox(pointBlastOption, label="camPan On/Off", value=0, changeCommand="pointblast")
    pm.columnLayout()
    pm.button(reset, label="Reset",width= 100,height = 20,command=reSet)

    changewindow.show()

    return x, y, z


    


x, y, z = zoomrate()






I’m using Maya 2018 and when i execute I’m just getting error. Error: line 1: SyntaxError: file line 1: invalid syntax

Are you executing it in a Mel script Editor tab or python?

python tab. actually I’m using VScode and saved it as a python file and just using send code to Maya. On the basic level I wanted to check the window whether it is as needed. that part the UI part was running just fine and then after I added the rest of the code mostly the matrix and the vector part since then I’m getting a error.

It’s because you’re defining functions and calling functions in the definitions you can’t do this

def foo(bar(x), y):
   return x + y

you can’t call bar(x) like that from the arguments.

Using a linter in vscode with the python tools will help you catch issues like this since this is purely a syntax issue.


image

Thank you so much for clearing my confusion. I was trying to mention the type of variable needed like a string or float but thats not needed in python so I cleared the similar issue in the other definitions also where needed. As you mentioned I have a linter in vscode I have IntelliSense and the description it says linter is provided still errors are not being displayed in vscode. after the corrections I’m getting this syntax error ```

Error: line 1: invalid syntax

Traceback (most recent call last):

File “”, line 1, in

File “C:/Users/Nikhil/AppData/Local/Temp/MayaCode.py”, line 189

if (posVec_cs != 0 && tan(hfv) != 0 && camScale !=0):

^

SyntaxError: invalid syntax

can you suggest a linter

python uses and not &&

I’m stuck to get the point in world space to screen, I referred to examples but in all the examples camera is the selection and the point we have to specify manually, I want to change this so that i get the camera from modelpanel and the position of the selection is given to the function. but the code works only if I manually specify the camera in Quotes. can someone help me understand this.

panelcam = pm.getPanel(withFocus=True)
_cam = pm.modelEditor(panelcam, query=True, camera=True)
print (_cam)
_camshape = pm.ls(_cam, dag=True, allPaths=True, shapes=True)
print (_camshape)
ip = pm.listConnections(_camshape, type = "imagePlane")[0]
imageName = ip.split('>')[+1]
print(imageName)
obj = pm.ls(selection=True)
if len(obj)==0:
    print("select at least 1 object")
print(obj)
pos = pm.xform(obj[0], query=True, worldSpace=True, translation=True)
print(pos)

def worldSpace2Screen(camera, worldPoint):
    resWidth = pm.getAttr(imageName + ".coverageX")
    print(resWidth)
    resHeight = pm.getAttr(imageName + ".coverageY")
    print(resHeight)
    selList = camera
    dagPath = om.MDagPath()
    selList.getDagPath(0,dagPath)
    dagPath.extendToShape()
    camInvMtx = dagPath.inclusiveMatrix().inverse()

    fnCam = om.MFnCamera(dagPath)
    mFloatMtx = fnCam.projectionMatrix()
    projMtx = om.MMatrix(mFloatMtx.matrix)

    mPoint = om.MPoint(worldPoint[0], worldPoint[1], worldPoint[2]) * camInvMtx * projMtx
    x = (mPoint[0] / mPoint[3] / 2 + 0.5) * resWidth
    y = (mPoint[1] / mPoint[3] / 2 + 0.5) * resHeight

    return x,y


print(worldSpace2Screen(_cam, pos))

Not an answer for the last question, but I could see that you are often using the non pythonic

pm.setAttr(camera + ".zoom", 1)

This ignores completely the big advantag of pymel where you work with objects. You and so fancy things like this one:

camera.zoom = 1

Hey thank you so much to bring to my notice. I have just started to learn coding and so I tend to make a lot of syntax errors. so for the safe side I refer to pymel documention and examples. if there are any more such fancy things explained in a website, forum please let me know. I’ll definitely go through it and learn as much possible.

import pymel.core as pm
import maya.OpenMaya as om
import maya.OpenMayaUI as omUI





panelcam = pm.getPanel(withFocus=True)
_cam = pm.modelEditor(panelcam, query=True, camera=True)
print (_cam)
_camshape = pm.ls(_cam, dag=True, allPaths=True, shapes=True)
print (_camshape)
ip = pm.listConnections(_camshape, type = "imagePlane")[0]
imageName = ip.split('>')[+1]
print(imageName)
camHFA = pm.getAttr(_cam.horizontalFilmAperture)
camVFA = pm.getAttr(_cam.verticalFilmAperture)
print(camHFA, camVFA)
hMaxOffset = camHFA/2
vMaxOffset = camVFA/2
print(hMaxOffset, vMaxOffset)
sel = pm.ls(selection=True)
if len(sel)==0:
    print("select at least 1 object")
obj = sel[0]
print(obj)


def worldSpace2Screen(selection):
    resWidth = pm.getAttr(imageName + ".coverageX")
    print(resWidth)
    resHeight = pm.getAttr(imageName + ".coverageY")
    print(resHeight)
    pos = pm.xform(selection, query=True, worldSpace=True, translation=True)
    print(pos)
    view = omUI.M3dView.active3dView()
    dagCam = om.MDagPath()
    view.getCamera(dagCam)
    curCam = om.MFnDagNode(dagCam.transform()).name()
    print(curCam)
    fnCamera = om.MFnCamera(dagCam)
    #dagCam.pop()
    cameraDir = fnCamera.viewDirection(om.MSpace.kWorld)
    projxMtx = om.MMatrix()
    view.projectionMatrix(projxMtx)
    viewMtx = om.MMatrix()
    view.modelViewMatrix(viewMtx)
    mPoint = om.MPoint(pos[0], pos[1], pos[2]) * viewMtx * projxMtx
    x = (mPoint[0] / mPoint[3] / 2 + 0.5) * resWidth
    y = (mPoint[1] / mPoint[3] / 2 + 0.5) * resHeight

    return x, y, 1.0


print(worldSpace2Screen(obj))

_cam.panZoomEnabled = 1

expr = "camSpace = (worldSpace2Screen(\"" + obj + "\")\n" 
expr += (_cam + ".horizontalPan = (camSpace.x * " + str(camHFA) + "/2" + "\n")
expr += (_cam + ".verticalPan = (camSpace.y * " + str(camVFA) + ") /2")

pm.expression(name= (_cam+"_pointblastExp"), string = expr, object="", alwaysEvaluate=True, unitConversion="all")

I’m trying to get the expression to get set the object selected to center to the camera but I’m getting an error. please can you help me out figuring out the issue. The error is
Error: line 1: persp.horizontalPan = (camSpace.x * 1.41732/2

Line 1.19: Syntax error

Traceback (most recent call last):

File “”, line 1, in

File “C:/Users/Nikhil/AppData/Local/Temp/MayaCode.py”, line 65, in

pm.expression(name= (_cam+"_pointblastExp"), string = expr, object="", alwaysEvaluate=True, unitConversion=“all”)

File “C:\Program Files\Autodesk\Maya2018\Python\lib\site-packages\pymel\internal\factories.py”, line 957, in newFuncWithReturnFunc

res = beforeReturnFunc(*args, **kwargs)

File “C:\Program Files\Autodesk\Maya2018\Python\lib\site-packages\pymel\internal\pmcmds.py”, line 134, in expression_wrapped

res = new_cmd(*new_args, **new_kwargs)

RuntimeError: persp.horizontalPan = (camSpace.x * 1.41732/2

Line 1.19: Syntax error

I’m not seeing anyone else point this out, but you’ve got a different error on line 90:

if (len(sel)=0)

Should be like this

if len(sel) == 0

Also keep in mind it’s not necessary to use ( ) around every if statement like in MEL.

There’s also places where you’re strong-typing your parameters in your function definitions, which isn’t necessary in Python

def getMatrix(str(attr), *args)):

Should look like this

def getMatrix(attr, *args):

And

def mult_vectorMatrix(vector(v), matrix(m), *args):

Should be

def mult_vectorMatrix(v, m, *args):

And so on…

Yes alot of silly syntax mistakes are there in the script. so i need to practice more with the coding. but I have added a version in the previous reply in which I been able to get a decent output just getting stuck with the creation of expression.
Thank You so much all for helping me out to correct the script and notifying me of the mistakes, helped me understand more.

hey I have break the script in parts the UI is implemented but the logic and expression I want to understand first, so to center the camera pan to the selected object we have to get the screen value of the obj selected and then give that value to the horizontal and vertical pan, but the screen value recieved is in pixels and the pan value accepts only in inches. this i tried to convert the x,y values into inches by multiplying x with 0.0104166667, but it is not working. please explain me this?so far I have got this.

import pymel.core as pm
import maya.OpenMaya as om
import maya.OpenMayaUI as omUI





panelcam = pm.getPanel(withFocus=True)
_cam = pm.modelEditor(panelcam, query=True, camera=True)
print (_cam)
_camshape = pm.ls(_cam, dag=True, allPaths=True, shapes=True)
print (_camshape)
ip = pm.listConnections(_camshape, type = "imagePlane")[0]
imageName = ip.split('>')[+1]
print(imageName)
camHFA = pm.getAttr(_cam.horizontalFilmAperture)
camVFA = pm.getAttr(_cam.verticalFilmAperture)
print(camHFA, camVFA)
hMaxOffset = camHFA/2
vMaxOffset = camVFA/2
print(hMaxOffset, vMaxOffset)
cameraShape = _camshape[0]
print(cameraShape)
focalLen = pm.camera(cameraShape, query=True, focalLength=True)
print(focalLen)
sel = pm.ls(selection=True)
if len(sel)==0:
    print("select at least 1 object")
obj = sel[0]
print(obj)


def worldSpace2Screen(selection):
    resWidth = pm.getAttr(imageName + ".coverageX")
    print(resWidth)
    resHeight = pm.getAttr(imageName + ".coverageY")
    print(resHeight)
    pos = pm.xform(selection, query=True, worldSpace=True, translation=True)
    print(pos)
    view = omUI.M3dView.active3dView()
    dagCam = om.MDagPath()
    view.getCamera(dagCam)
    curCam = om.MFnDagNode(dagCam.transform()).name()
    print(curCam)
    fnCamera = om.MFnCamera(dagCam)
    #dagCam.pop()
    cameraDir = fnCamera.viewDirection(om.MSpace.kWorld)
    projxMtx = om.MMatrix()
    view.projectionMatrix(projxMtx)
    viewMtx = om.MMatrix()
    view.modelViewMatrix(viewMtx)
    mPoint = om.MPoint(pos[0], pos[1], pos[2]) * viewMtx * projxMtx
    x = (mPoint[0] / mPoint[3] / 2 + 0.5) * resWidth
    y = (mPoint[1] / mPoint[3] / 2 + 0.5) * resHeight

    return x, y, 1.0


camspace = worldSpace2Screen(obj)
camspacex, camspacey, camspacez = camspace
print(camspacex, camspacey, camspacez)

Hcam = (camspacex* camHFA)/2
Vcam = (camspacey* camVFA)/2
print(Hcam, Vcam)
#cameraShape.panZoomEnabled = 1
#cameraShape.horizontalPan = 0.212
#cameraShape.verticalPan = 0.212
pm.setAttr(cameraShape+".panZoomEnabled",1)
pm.setAttr(cameraShape+".horizontalPan",Hcam)
pm.setAttr(cameraShape+".verticalPan",Vcam)





@haggi_krey I tried the syntax which you mentioned but it doesnt affect the camera.

Sorry, too long paused from pymel, it should be more like this:

c = pm.PyNode("persp1Shape")
c.setFilmTranslateH(50)

Thank you I will test it definitely. can you check my previous code and guide me what am I missing, I have camera in scene a object in the view, I get the screen space coordinates of the point, but when i assign it to panzoom horizontal and vertical Pan it doesnt snap the object to the center of the view? Please can you explain me the value or what I’m doing wrong.
image resolution I have is 3200,1800 point coordinate in screen space is (1125.070, 1020.54638,1.0)
what calculation am I missing out to assign the value to the horizontal and vertical Panof the camera?

The only thing I can spot without digging in closely is

Hcam = (camspacex* camHFA)/2

When you divide by an integer, the result is going to round to an integer instead of giving an exact result.

Everywhere you are dividing values, try using floats instead of integers. I’ve spotted at least 6 places in your script:

Hcam = (camspacex* camHFA) / 2.0
Vcam = (camspacey* camVFA) / 2.0

I do want to point out that this is no longer the case in python3, and you can replicate the behavior by using from __future__ import division as the first import in a module.

2 Likes