This is another small script to make an easy transition from Maya to After Effects. You can import Maya .ma files into After Effects, but one unit in Maya is one pixel in After Effects and the result is a very small (and hard to tweak) composition. Also, After Effects is very touchy about the kinds of .ma files it will import, and only accepts files with uniform keyframe times.
What this script does, is do all of the hard work for you. All you have to do is select the objects you need to export and tell it to go, almost.
In the first tab, you select the cameras to export and press the button. Then, you select the objects to export and press the button. This will load all of the things to export into memory.
In the second tab, you set the scene scale and keyframe times. The scale is the value that will depend on your scene. Like I said earlier, one unit in Maya is one pixel in After Effects. Usually, your scene will need to be scaled by 100+. A good way to find a nice value for this, is to look at your maximum values for your keys. If they’re something like (10, 2, 4), you would want a very high export value to get those numbers in the hundreds, if not thousands. If they’re something like (829, 200, 25), you probably only want to scale up by 5, if any scale at all is needed. You can export many times with different scales and see what works best for you. The keyframe times value will insert a keyframe every X frames. You can make this as accurate as you need it. I usually just use 1.
In the third tab, you set the timeframe of the scene and let the magic happen. The first button will scale everything up by the amount before. The second button will bake out all of the cameras you selected. The third button will bake out locater NULLs from the objects. This is important, because After Effects only cares about locators with NULL in their name, and will place an After Effects NULL Object wherever there is a Maya NULL Locator. The last button will select everything that it has baked, allowing you to Export Selected as a .ma for use with After Effects. Then, you can revert to your previous save to get back to your original scene.
NOTE: This script requires PyMEL. To use this script, you should paste the following into the Python section of the Script Window, and then execute the code. Or you could drag the selected code in the Python tab to the Shelf to create a shelf item for it.
## This script requires pymel ## This script offers a way of exporting ## a scene nicely to Adobe After Effects ## To do this, it has to scale everything ## so the values are easier to use in AE, ## and bake the animation to 1 frame intervals ## so AE can read them ## Import pymel and the random module from pymel.core import * ## ---- VARIABLES ---- ## originalCamerasList = [] originalCameras = [] originalObjectsList = [] originalObjects = [] exportList = [] ## ---- FUNCTIONS ---- ## def getOriginalCameras(*Args): ## Gets the selection originalCamerasListSelected = ls(selection=True) ## For each object in selection for selected in originalCamerasListSelected: ## Try to get it's shape node, if it has one and it's a camera try: if selected.getShape().nodeType() == "camera": ## Add it to our camera list originalCamerasList.append(selected) ## If that errored, it doesn't have a shape node except: print "Camera: "+selected+" has no shape node or is a shape node." ## Sort the list and then make a readable string for the bar originalCamerasList.sort() # But first, add it to a separate list that gets overwritten each time global originalCameras originalCameras = originalCamerasList[:] originalCamerasString = ', '.join( [str(x) for x in originalCamerasList] ) ## Get rid of the camera selection list so we don't keep adding to it each time del originalCamerasList[:] ## Set the bar with the readable list originalCamerasLabel.setText(originalCamerasString) def getOriginalObjects(*Args): ## Gets the selection originalObjectsListSelected = ls(selection=True) ## For each object in selection for selected in originalObjectsListSelected: ## Try to get it's shape node, if it has one and it's not a camera try: if selected.getShape().nodeType() != "camera": ## Add it to our object list originalObjectsList.append(selected) ## If that errored, it doesn't have a shape node except: print "Object: "+selected+" has no shape node or is a shape node" ## Sort the list and then make a readable string for the bar originalObjectsList.sort() ## But first, add it to a separate list that gets overwritten each time global originalObjects originalObjects = list(originalObjectsList) originalObjectsString = ', '.join( [str(x) for x in originalObjectsList] ) ## Get rid of the object selection list so we don't keep adding to it each time del originalObjectsList[:] ## Set the bar with the readable list originalObjectsLabel.setText(originalObjectsString) def scaleEverything(*Args): ## Make an array for the scale value exportScaleValue = [exportScale.getValue(), exportScale.getValue(), exportScale.getValue()] ## Empty the selection select(clear=True) ## Select the cameras for cam in originalCameras: select(cam, add=True) ## Select the objects for obj in originalObjects: select(obj, add=True) ## Group the selected objects exportScaleGroup = group(name="exportScale") ## Scale the group by the amount given exportScaleGroup.setScale(exportScaleValue) def bakeCameras(*Args): for cam in originalCameras: print "Baking Camera: "+str(cam) ## Gets the name of the old camera newCamName = str(cam.name())+"__AE" ## Create a new camera newCam = createNode('camera') ## Name the new camera the new name rename(newCam.getParent(), newCamName) ## Get all the old camera settings and apply to new cam newCam.setFocalLength(cam.getFocalLength()) newCam.setFStop(cam.getFStop()) newCam.setShutterAngle(cam.getShutterAngle()) newCam.setFocusDistance(cam.getFocusDistance()) ## Constrain the new camera to the old camera so we get the ## Locally scaled values in world space for baking pC = parentConstraint(cam, newCam.getParent()) sC = scaleConstraint(cam, newCam.getParent()) ## Format the in/out time range timeRange = (inFrame.getValue(), outFrame.getValue()) ## Bake the animation of the new camera bakeResults(newCam.getParent(), sampleBy=exportKeysAmount.getValue(), time=timeRange, simulation=True) ## Remove the constraints delete(pC, sC) ## Add object to export list global exportList exportList.append(newCam.getParent()) def bakeObjects(*Args): for obj in originalObjects: print "Baking Object: "+str(obj) ## Gets the name of the old object newLocName = str(obj.name())+"__AE__NULL" ## Create a new locator newLoc = spaceLocator() ## Name the new locator the new name rename(newLoc.getParent(), newLocName) ## Constrain the new locator to the old object so we ## get the locally scaled values in world space for baking pC = parentConstraint(obj, newLoc) sC = scaleConstraint(obj, newLoc) ## Format the in/out time range timeRange = (inFrame.getValue(), outFrame.getValue()) ## Bake the animation of the new locator bakeResults(newLoc, sampleBy=exportKeysAmount.getValue(), time=timeRange, simulation=True) ## Remove the constraints delete(pC, sC) ## Add object to export list global exportList exportList.append(newLoc) def export(*Args): ## Clear selection select(clear=True) ## Loop through the exported list generated from our baking global exportList for each in exportList: ## Select each object select(each, add=True) informBox("DONE!", "All objects prepared for exporting have been selected, you may now: File > Export Selected and save as a Maya Ascii for After Effects", ok="Sweet!") ## ---- GUI SECTION ---- ## ## Makes a flow layout to arrange two columns side by side gui = window(title="After Effects Exporter", width=190, height=230, sizeable=False) mainLayout = formLayout() tabs = tabLayout(height=230, width=190) formLayout(mainLayout, edit=True, attachForm=((tabs, 'top', 0), (tabs, 'left', 0), (tabs, 'bottom', 0), (tabs, 'right', 0))) stepOne = rowColumnLayout(numberOfColumns=1, columnWidth=(1, 190), parent=tabs) text(parent=stepOne, label="Select the cameras you want sent to After Effects:", height=40, wordWrap=True, align="left") originalCamerasLabel = textField(parent=stepOne, editable=False, text="NONE", width=125) button(parent=stepOne, command=getOriginalCameras, label="GET CAMERAS") separator(height=10, parent=stepOne) text(parent=stepOne, label="Select the objects you want sent to After Effects:", height=40, wordWrap=True, align="left") originalObjectsLabel = textField(parent=stepOne, editable=False, text="NONE", width=125) button(parent=stepOne, command=getOriginalObjects, label="GET OBJECTS") stepTwo = rowColumnLayout(numberOfColumns=1, columnWidth=(1, 190), parent=tabs) text(parent=stepTwo, label="Set the scale for everything. Keep in mind, one unit in Maya is one pixel in After Effects.", height=70, wordWrap=True, align="left") exportScale = intField(width=60, value=1000, parent=stepTwo) separator(height=10, parent=stepTwo) text(parent=stepTwo, label="Set the keyframe bake amount. This will make keyframes every X frames.", height=70, wordWrap=True, align="left") exportKeysAmount = intField(width=60, value=1, parent=stepTwo) stepThree = rowColumnLayout(numberOfColumns=1, columnWidth=(1, 190), parent=tabs) text(parent=stepThree, label="Set the time range to bake and export:", height=40, wordWrap=True, align="left") inFrame = intField(width=60, value=1, parent=stepThree) outFrame = intField(width=60, value=48, parent=stepThree) separator(height=40, parent=stepThree) button(parent=stepThree, label="Scale Everything", command=scaleEverything) button(parent=stepThree, label="Bake Cameras", command=bakeCameras) button(parent=stepThree, label="Bake Objects", command=bakeObjects) button(parent=stepThree, label="Export", command=export) tabLayout(tabs, edit=True, tabLabel=((stepOne, "Step 1"), (stepTwo, "Step 2"), (stepThree, "Step3"))) gui.show()
This article is very good!
thanks, 😉
Not a good post because there is nothing telling you what to do with that text.
I copied and pasted it into MEL and got ‘syntax error’ – NOT ALL OF US ARE SCRIPTERS – THINK!
So would it be better off if this post didn’t exist? Have you ever used a script of any kind for Maya? You don’t need to be a scripter to know how to use this script, because it works just like any other script.
For one, right before the script (and the first line of the script) is a statement saying that this requires PyMEL.
I’m going to assume that you didn’t install PyMEL, because you’re also pasting the script into a MEL script window which will not work because this script is not written in MEL, it’s written in Python and requires PyMEL.
After that, you can use this script in any way that you would use another script. You could save it as a Python .py file in your Maya Python Scripts directory or paste it directly into the Python Script window. Either way, you can also turn it into a shelf button.
And just for you, I’ve updated the note just above the script for anyone who doesn’t know how to run a Maya script.
yyyyyyyyyyyyyes. ahhh thank you
p.s. Those with Maya 2013 and up should NOT install pymel I believe. It is already included in Maya 2013. Manually installing Pymel – like I did :S – cause a loop in the application, and I had to reinstall Maya. If you are in this situation and you need to reinstall, make sure you delete everything in your Maya2013/bin foler before reinstalling (delete the wrong pymel files). Thanks again for this script, it really helps.
Cameron, great script…maybe you could post just the .py file too? As it is I have to remove the line numbers in order for it work properly. Thanks!
one question/comment though. The camera zoom information doesn’t seem to export correctly. Any thoughts?
Hi Dave,
1) Whenever you hover over the code section there’s a small box that appears in the top right. There are the options to view the original file.
2) Unfortunately, this script only prepares the camera and objects in a way that After Effects wants it. There are quite a few camera settings that are not transferred, but that is an issue with After Effects and not the script. Basically, anything other than focal length, and maybe film back, probably isn’t transferred.
I went ahead and wrote a mel script (for those still on older versions of Maya or are not familiar with how to import py files) that does this and more. Focal length is respected as well. Writes a javascript to do the importing and cleanup of the weird naming convention. give me thumbs up on
http://www.creativecrash.com/maya/script/camera-and-object-positions-to-after-effects
THANKS MAN! Im working on a full Javascript import to handle lights as well thanks for sharing your pyMEL
Hi Cameron,
I have used this script in the past but its been so long I can’t get it to work again. I am using Maya 2014 and it is telling me that there is an error in the syntax. From what I understand pymel should have come preloaded with this version of maya. Is there anything that I should be taking a look at to get this to work? Thanks in advance.
Hi Kyle,
It will be hard to help unless you can provide the output so I can see where the errors are. Alternatively, I just approved a previous comment that I clearly forgot about (right before this one) which has a link to a similar script written in MEL, which you could try if you’re still not successful.