3D to pixels in Maya

When looking to find the 2D bounding rect of an object I came across this:
http://www.185vfx.com/2003/03/convert-a-3d-point-to-2d-screen-space-in-maya/
Sadly, it is the only tagged tech, maya or mel, so no more goodies there.

Here’s a python version. I intended to do it with more API, but the heighFieldOfView of the MFnCamera does not return the same value as the cmds.camera(hfv=True), not even when you convert it to radians, or when you put it through a tan operation. Hence I have no idea how that value is formatted and can’t continue with it.

Updated the math library for this (somewhere in python, located all the way at the bottom), to include a boundingbox class and fixed matrix to vector multiplication (I mixed up rows and columns before according to how Maya formats matrices, which is how openGL formats them as well).

It returns a BoundingBox with two 2D vectors (min and max) that represent screenspace coordinates. Multiply it with the width of the image to get actual pixels. The aspect ratio is squared so the top of the image may not be 1 if the height is not equal to the width. If you multiply the outy with the image width, you’ll still get the proper pixels though.

import math

from maya.OpenMaya import *
from maya import cmds
from Vmath.boundingbox import BoundingBox

import Vmath.matrix
import Vmath.vec

PI = 3.14159
DEGTORAD = (PI/180)

def getScreenspaceBoundingRect(in_objstr, in_camstr):
    hfv = math.tan(cmds.camera(in_camstr, hfv=True, q=True)*0.5*DEGTORAD)
    vfv = math.tan(cmds.camera(in_camstr, vfv=True, q=True)*0.5*DEGTORAD)
    worldInverseMatrix = Matrix( 4, 4, cmds.getAttr('%s.worldInverseMatrix'%in_camstr) )
    ar = cmds.camera(in_camstr, q=True, ar=True)
    '''
    handle meshes
    '''
    path = getDagPathFromName(in_objstr)
    iter = MItMeshVertex( path )    
    bb = None
    while not iter.isDone():
        pt = iter.position(MSpace.kWorld)
        pt = worldInverseMatrix*Vec(pt.x,pt.y,pt.z)
        if pt[2]:
            ptx,pty = 0,0
            ptx = ((pt[0]/-pt[2])/hfv)*0.5+0.5
            pty = ((pt[1]/-pt[2])/vfv)*0.5+ar*0.5
            pty *= (1.0/ar)
            if not bb:
                bb = BoundingBox([ptx,pty],[ptx,pty])
            else:
                bb.extend([ptx,pty])
        iter.next()
    return bb


def getDagPathFromName(in_name):
    selector = MSelectionList()
    MGlobal.getSelectionListByName(in_name,selector)
    path = MDagPath()
    selector.getDagPath(0, path)
    return path

3 thoughts on “3D to pixels in Maya

  1. Hola.

    Heheh – My previous posting’s code got garbled. Here’s a second attempt.

    Nice stuff : http://trevorius.com/scrapbook/uncategorized/82/

    You mentioned on your page, that you were unsure about the data when attempting to ascertain h_fov & v_fov.

    I’ve used the following (C++) with Maya API for a number of years with no reported problems.

    C++ Pseudocode :

    double h_fov = “cameraShape.horizontalFilmAperture” * 0.5 / ( “cameraShape.focalLength” * 0.03937 );

    double v_fov = “cameraShape.verticalFilmAperture” * 0.5 / ( “cameraShape.focalLength” * 0.03937 );

    ———–

    This comes ‘as is’. Just to say it’s used as part of a Camera Frustum Visualiser node & correlates to Maya’s clipping planes pretty exactly.

    I think Apertures are in inches and focalLengths in millimeters (or some such tradtions-based-mish-mash).

    Short form : one millimeter is 0.03937 inches.

    Must have been the American/Canadian coders/engineers who cobbled Maya together out of Wavefront in the 90s.

    -EXAMPLE USAGE——-

    double fright = “camShape.farClip” * h_fov;
    double ftop = “camShape.farClip” * v_fov;

    double nright = “camShape.nearClip” * h_fov;
    double ntop = “camShape.nearClip” * v_fov;

    —————————————-

    Thanks Mr Trevor – your info is always good – so thanks heaps good chum.

    Noah

  2. Further to post 2 from me :

    MPoint farTopRightPosOfCameraFrustum = MPoint( fright, ftop, -“camShape.farClip”) * “camShape.worldMatrix”;

  3. Thanks for your reply, it’s very helpful. I indeed believe inches are a standard unit when talking real world cameras / lenses.

Leave a Reply

Your email address will not be published. Required fields are marked *