Showing posts with label Maya. Show all posts
Showing posts with label Maya. Show all posts

Maya- find node names that are not unique

Sometimes you can end up in situations where Maya Nodes don't have unique names. Usually this won't cause issues until you are doing global changes (like the hack amazing workaround where you remove namespaces on export)

Shawn Miller put me onto this handy little snippet to identify nodes that don't have Unique names:

string $allDagNodes[] = `ls -sn -dag`;
for ($node in $allDagNodes)
if (`gmatch $node "*|*"`)
print ($node+" is not uniquely named");

Thanks Shawn!

Maya Name Helpers

Hey, who likes well organized files? This guy. Who like manually renaming hundreds of objects? Nobody I've met.

I've found one of the best ways to help my art teams keep their content organized it to make it easier for them to manage their object names. I've wrapped up some of the most useful little scripts into this handy tool on Gumroad.

- Written for Maya 2019
- Batch rename multiple assets at once.
- Easily add, remove or replace elements in names.
- Quickly add or remove prefixes and suffixes.
- Easily convert between camelCase and underscore_naming
- Docks with the Maya GUI.
- Works on nodes, materials, objects. Pretty much anything you can select via the GUI.

Maya: Animation Event Definition Tool

I've been working on a new set of tools to define animation event data in Maya and export it into Unity for consumption by the AssetPostProcessor. This has been kind of a cool learning experience, because before now I really didn't have much to do with the Animation pipe, which has been an entirely manual process for the animators.

Previously clips were cut up and events were defined by hand in Unity once the .fbx files had been exported from Maya. This wasn't such a bad thing, except that the tools in Unity for defining events were very un-intuitive. The aim of doing all this was to allow the animators the ability to work in a tool they were familiar with, and get the AssetPostProcessor to do most of the boring legwork on the Unity side.

The Maya interface. 
The Maya tool is pretty simple right now, and responsive enough that the animators don't hate me. Navigating to different clips or events will move to that time range on the slider. The event list is directly correlated to events called by the engineers in engine, so they are only available as pre-set items in a drop down.

The data is stored in the scene as attributes on empty nodes. On export time, the data is compiled into dictionaries that are then written into a .JSON file named after the .fbx.

The end result is something like this:

Data for an 'Attack' animation. The first clip is the entire duration, the next three are the intro, loop and outro. In the anim events the unit fires it's weapons three times, once on frame 5, then on 9 and 13. 'Index' is used for the muzzle position on a unit or turret, as those are the only entities in game making use of the system. I would prefer to be using named bones for more flexibility. 
Once this animation is out there, the engineering team pull it into the AssetPostProcessor and generate the required clips and event metadata from the contents. 

All in all, the Maya side is pretty basic at the moment, and implemented on a project that currently has pretty basic animation requirements. Even so, the idea of feeding data into the AssetPostProcessor is something that really appeals to me, and the .JSON format has been pretty easy to write to from Python. 

Eventually I would like to be able to define custom VFX events on named bones, and mark up non-event related data like whether you want an asset to automatically generate lightmap UV's on an imported model or not. There is a lot of potential there. 

Maya- Bake Vertex colors to Texture using Mental Ray.

This is a technique to get the Vertex colors from your model baked to a texture using a Mental Ray bakeset.

One method of getting vertex colors from a mesh to a texture is using the Paint Vertex Color tool's 'export' option under 'attribute maps'. This is pretty good for higher poly models, but falls apart on low poly models that might have vertex colors assigned per face rather than per Vert. On these models, the results will look muddy, as there are not enough verts to carry the info.

The other draw back of the Paint Vertex Color tool's export option is that it has no texture padding built in, so whatever colors you get out will be riddled with seams.

I like to use the Mental Ray bake sets to get lighting and color information from Maya to Photoshop. Although it doesn't handle vertex color straight off the shelf, its pretty easy to set it up by making a shader that reads the model's vertex colors.

On left- Sharp details preserved, padding enabled. On right, fuzzville. 
So, to set it up:

  • Make a new material and assign it to your model. I prefer lambert because I'm only after flat color. 
  • In hypershade, make a MentalRayVertexColors node. 

  • Click on the MentalRayVertexColors node. Under cpvSets in the attribute editor, click the button that adds a new item. 
  • Back in the HyperShade, bring up the shading graph of your material, and connect the MeshShape output of your object to the mentalrayVertexColorsNode input. 
  • Find the colorSet->colorSet[0]->colorSet[0].colorName attribute to the cpvSets->cpvSets[0] input.
That one. Over there. 
  • Now, you can use your Mental Ray bake set to bake out your colors by setting it to bake light and color. Did I mention there is padding as well? Well, there is, and its awesome.
  • This also lets you render your vertex colors in the Mental Ray Renderer, which is a cool bonus.  



Your final shading node should look something like this. Mind boggling.  

Model Monkey: Now with Configs!

I've decided to use ini files to make it easier to port my Maya exporter across different projects with as little fuss as possible, using the standard Python ConfigParser module. The last time I really played around with .ini files was to mess with Command and Conquer Red Alert, and that was some time ago. It's really awesome that the .ini file format is still worth using today.

There is a bug where you can add new file rules until the tool grows so long it is
bigger than the screen. Time to add a scroll bar...
Part of getting this to work includes creating a GUI interface to minimize the manual file editing that you might expect. Being my first major use of an .ini for a tool (I did use a teeny tiny .ini on Texture Monkey) I suddenly realized that I had to re-work a lot of my previous configuration code in order to make my tool flexible enough to be re-configurable without breaking into a million different lame parts.

BUT! It's working now, whoo! A couple of things have to be modified, but I can get info into the tool, change it, and get it back into the .ini again, rinse and repeat. In other words, I can now do what people have been doing for decades! Whoo etc. But hey, it works!


Maya Exporter: Tabs and Tools!

I've been chipping away at my Maya Exporter and have a few Photoshop functions tied into it now, along side the original exporter functionality.

Behind the scenes the Photoshop commands are built on Standard modules, using Subprocess and some string manipulation in order to get JavaScript commands to the Photoshop application. As the tool has expanded beyond it's initial export-only functionality, there has been a decent amount of clean up and re-factoring behind the scenes to make sure that it doesn't just turn into a mega-script.

Maya-side functions and Photoshop functions have been split into separate classes and files from the GUI, which has made keeping track of the code a lot easier.

The GUI is built using the Pyside QT Libraries, which comes standard with Maya 2014.

Next on the list, adding the option to load different project environments.

PySide and Maya2014

I've been working with PySide to make some tools for our Animation department. Part of that process involves a UI that is generated on the fly based on data read in from a spreadsheet.

It was important that each UI component had a unique and predictable object name so that I could access the information it contained and save it out later. In case anyone else needs to do it, or has a better way, here is an example of the process I use. 

Thanks to Nathan Horne and Chris Zurbrigg for their very useful examples!

# System
# System
import sys
import os

# GUI Modules
from PySide import QtCore, QtGui
import maya.OpenMayaUI as apiUI

# Allows converting pointers to Python objects
from shiboken import wrapInstance

def maya_main_window():
    main_win_ptr = apiUI.MQtUtil.mainWindow()
    return wrapInstance(long(main_win_ptr), QtGui.QWidget)

# Create out Dialog class, inheriting from QDialog
class Dialog(QtGui.QDialog):

    # Call the maya_main_window command to parent it
    def __init__(self, parent = maya_main_window()):

        super(Dialog, self).__init__(parent)

        # Create a list of rows and buttons
        self.rows = ["Row1", "Row2", "Row3"]
        self.buttons = ["Button1", "Button2", "Button3"]

        # And now set up the UI
        self.setup_ui()

    def setup_ui(self):

        self.main_layout = QtGui.QVBoxLayout()

        # Create a series of rows, and in each row, put our buttons
        for row in self.rows:

            self.row_Hbox = QtGui.QGroupBox()
            self.layout = QtGui.QGridLayout()

            for button in self.buttons:

                # Label the button with it's list name
                self.push_button = QtGui.QPushButton(button, self)

                # Give each button a unique object name
                self.b_name = row + "_" + button
                self.push_button.setObjectName(self.b_name)

                # Add a QLine Edit to each particular button
                self.q_line_name = self.b_name + "_TextEdit"
                self.my_line_edit = QtGui.QLineEdit()
                self.my_line_edit.setText("Hi! I'm " + self.q_line_name)
                
                # Also give it a unique name
                self.my_line_edit.setObjectName(self.q_line_name)

                # Offset each button in the layout by it's index number
                self.layout.addWidget(self.push_button, 0, self.buttons.index(button))

                # Offset each QLine Edit in the layout to be underneath each button
                self.layout.addWidget(self.my_line_edit, 1, self.buttons.index(button))                

                # Connect the button to an event
                self.push_button.clicked.connect(self.on_button_event)

            # Add the buttons to our layout
            self.row_Hbox.setLayout(self.layout)
            self.main_layout.addWidget(self.row_Hbox)

        # Set the layout and title
        self.setLayout(self.main_layout)
        self.setWindowTitle("Example Window")

    def on_button_event(self):

        sender = self.sender()
        print sender.objectName() + ' was pressed'

        # Get the text from the text line edit linked with the button
        self.line_edit_name = sender.objectName() + "_TextEdit"
        self.line_edit = self.findChild(QtGui.QLineEdit, self.line_edit_name)
        print self.line_edit
        print self.line_edit.text()

# Call our dialog   
dialog = Dialog()
dialog.show()

Tooling around- Maya Photoshop Bridge

My current little pet project to bridge Photoshop and Maya, from within the Maya environment.

The tool is in very early development stage, but currently supports project configuration and opening a selected model's source PSD from within the Maya environment.

Other neat time savers:

  • Exporting a selected model's UV map and using it to create a new PSD.
  • Calling Photoshop to export all of a model's maps from their source PSD. 
  • Renaming shaders based on their diffuse texture name.
  • linking associated known map types (eg- specular, gloss and normal) 
The tool is written entirely in Python/Pymel and uses the win32com module as a bridge. 

Various options to clean up scenes. 

The current texture tools. More to come!

Project options.