Anyone want to help write a killer time-saving script?


#1

I’m in dire need of a script that automates the process of creating Matte Passes, but I lack the programing knowledge to put something like that together. If anyone here is up for it, you’ll be doing the Maya community one giant favor.

        Here is what it would entail:

[ol]
[li]For each unique selected object in the scene create a new “Contribution_Map” for the current Render layer.[/li][li]Create a new Matte Passes for each selected object. Change the name of the matte pass to the name of the object with a “Matte_” in front.[/li][li]For each Matte Pass Attributes, change the data to 8-bit and channels to 1.[/li][li]Add the Matte Passes to the corresponding Contribution Map.[/li][/ol]It would be really nice if the created Contribution Maps where renamed to match the objects as well, but it’s not 100% necessary.

        This would let us easily render out an EXR that has selectable channels like this in your favorite composting application.  For example:

            Matte_Eyes
            Matte_Teeth
            Matte_Shirt
            Matte_Face
     
       As you can imagine automating this setup could literally save days of setup in complex scenes that require a large number of Matte passes.

#2

So I went ahead and copied the lines of code in the History for the setup of this with a basic sphere.
[u]

Create Dummy Sphere[/u]sphere -ch on -o on -po 0 -ax 0 1 0 -r 2.544182 -nsp 4
Rename Sphere rename “nurbsSphere1” “Circle”

Create 1st Contribution map
connectAttr -na defaultRenderLayer.passContributionMap passContributionMap1.owner;

Rename Contribution map to associate with Circle.
renderLayerEditorItemOnRename “defaultRenderLayer%passContributionMap1” “Circle_Contribution”

Add Circle to Contribution Map
connectAttr -na Circle.message Circle_Contribution.dagObjects;
Create Matte Pass createNode renderPass;
applyAttrPreset “renderPass1” “C:/Program Files (x86)/Autodesk/Maya2009/presets/attrPresets/renderPass/matte.mel” 1;
rename “renderPass1” “matte”;
Rename Matte Pass rename matte “matte_Circle” ;
Connect to Contribution Map connectAttr -nextAvailable defaultRenderLayer.renderPass matte_Circle.owner;
connectAttr -nextAvailable matte_Circle.message Circle_Contribution.renderPass;


#3

So here is a start at my poor scripting attempt. So far I’ve been able to create the Matte Pass with the correct name and a contribution map for each object selected. Also note you have to define the directory of the matte.mel pass.

      I'm having trouble doing everything else from putting the objects in the corresponding pass contribution maps to linking the contribution maps the the matte Passes.  I really could use some help with this.
renderLayerEditorDeleteLayer RenderLayerEditor Matte;
           createRenderLayer -name "Matte" -number 1 -noRecurse `ls -selection`;
           
           int $i;
           
           string $rename[] = `ls -sl`;
           int $selSize = `size $rename`;
           
           for ($i =0; $i <$selSize ; $i++){
           renderLayerEditorCreateContMap RenderLayerTab Matte 0;
           
           /// Create Matte Pass (working)
           
           createNode renderPass;
           applyAttrPreset "renderPass1" "C:/Program Files (x86)/Autodesk/Maya2009/presets/attrPresets/renderPass/matte.mel"  1;
           rename "renderPass1" ("Matte_"+$rename[$i]);
           
           
           }
     Also I'm thinking this could be better if it went through materials instead.  Create a new Contribution map and Matte Pass for each material using it's name, then placing the geometry with the shader applied to the corresponding matte pass.   Shaders with no geometry would get no Matte pass.  I have absolutely no idea how to do a shader call like that though.

It would let you just run the script and poof, all your Matte Passes are finished. Run it again and it will update the scene. But something like that is definitely way outside my scripting ability. This is hard enough for me as is.


#4

I am oh so very close, but I still need to work out a few things. The workflow so far is as follows; Select the Materials you want to create Matte Passes for and run the script… all done. This is what I need help with:

  1. How would I create a delete command that searches for all nodes with “Matte_” in the name?
  2. How do I create a variable from the following code:
    hyperShade -objects ($Material[$i]+“SG”);
    I need to use it to put the resulting selected objects into the corresponding contribution map.

Here is the code:

renderLayerEditorDeleteLayer RenderLayerEditor Matte;
createRenderLayer -name "Matte" -number 1 -noRecurse `ls -selection`;

int $i;

string $Material[] = `ls -sl`;
int $selSize = `size $Material`;

for ($i =0; $i <$selSize ; $i++){
renderLayerEditorCreateContMap RenderLayerTab Matte 0;

/// Create Matte Pass

createNode renderPass;
applyAttrPreset "renderPass1" "C:/Program Files (x86)/Autodesk/Maya2009/presets/attrPresets/renderPass/matte.mel"  1;
rename "renderPass1" ("Matte_"+$Material[$i]);

//Connect Matte to Contribution Map
connectAttr -nextAvailable Matte.renderPass ("Matte_"+$Material[$i]+".owner");
connectAttr -nextAvailable ("Matte_"+$Material[$i]+".message") ("passContributionMap"+($i+1)+".renderPass");

///Select Objects from Selected Material to eventually go into Contribution Map
hyperShade -objects ($Material[$i]+"SG");

//Code to add Objects into Contribution map missing.
}

#5

Mmmhh… Seems to be something like this no?:
http://www.fevrierdorian.com/blog/post/2009/02/26/fdMiaMaterialXCreateFB-Cr%C3%A9ez-automatiquement-vos-renderPass-pour-le-mia_material_x

If this can help :wink:

if(isValidString($nameToTest, "^Matte[_].*");

Not with “hyperShade”. It only “do things”.

It should be another way to do that. Good luck!


#6

Similar idea, much different purpose. That script breaks Mia_Materials down into the Metal Ray Output Passes. Deex’s Custom Shaders do a better job of that now. My script would instead create a unique Matte Pass for all objects under a common material.

The most common professional practice up till now is to create RGB Matte Passes manually through custom_color passes. In compositing you then extract the Red, Green, or Blue channel to get the Matte you need. Works better than other solutions like material/object ID’s because those cause horrible aliasing issues.

But say you have 100 different Materials in the scene you need individual control over in post. That’s 34 custom passes you have to manually assign, giving a Red, Green, or Blue, value to each different material. And that’s only the beginning of the nightmare. The compositor has to look through MattePasses 1-34 to find the object he needs. It’s like trying to find the one puzzle piece you need in a pile of 100. It’s enough to drive someone mentally insane. For example, watch this Pigeon Impossible podcase. Notice in the beginning that he had to create giant chart to keep track of the whole thing.

So what I’m trying to create is an automatic system that has 1 Matte for each pass, named by material for easy organization. It’s a real no-brainier solution.


#7

Ok, I think I’d understand. Cool idea!

Impressive! Others are very interesting! Thanks for share! :slight_smile:

I suppose ^^

And you have to have a very well-organized material-naming convention. Then one side the problem is the same…

I really like the idea but “yes-and-no”. As I said, it depend of your organisation :slight_smile: . If the person before you don’t have well-named his material you are in the shit. :smiley:

If this could be combine with namespace (of external references) it could be very interesting too!

Better! Create a “Matte Manager” to create and organise sets of RGBA matte (limited to 3 object by set) wich shader assignation is made just before rendering… (Mhhh… I will thing about that!)

I will follow your post and maybe, one day, start this system.


#8

Yeah, if you’re unorganized this isn’t going to work well for you. But in that case, what will?

I would rather do straight black and white Mattes instead of RGB Mattes. RGB Mattes are difficult to keep organized, would be harder to implement, and require the compositor to do more searching. B/W Mattes are easier to create from a scripting standpoint and are far easier to keep organized. The file size may be a tad larger, but it’s worth it.

Perhaps in the future I’ll also do something to create Group Mattes in addition to those based on material, but it’s not quite as necessary.


#9
if(isValidString($nameToTest, "^Matte[_].*");

Think you could show an example of defining the $nameToTest variable? All I need is for it to do this:

delete Matte_deeX_mia_material1;

But for everything named “Matte_” in the scene.


#10

Just found out I need to do the same thing, only searching for anything with “PassContributionMap” at the beginning of the name and deleting it.

Once I can figure that out, it will be a lot easier for me to troubleshoot. I found out a way to put the objects from material selection into contribution maps, but it’s not 100% working yet.


#11

Also found out the Node types through another mel script to list all node types:

renderPass
renderPassSet
passContributionMap

At least I would think. So I needs some help writting a protion of the scripts that looks through these nodes and delete’s them with “Matte_” and “PassContributionMap” in front.


#12

I thought about a plugin in your compositing soft wich, when you click with a special keyboard combination, it select the layer wich have a R alone, G alone, or B alone value. A bit like photoshop.

isValidString("Matte_deeX_mia_material1", "^Matte[_].*")
 // Result: 1 //
 isValidString("Woatte_deeX_mia_material1", "^Matte[_].*");
 // Result: 0 //

So if you list all object by tape with:

string $deeX_mia_material[] = `lsType deeX_mia_material`; //list all deeX_mia_material
 stringArrayRemoveAtIndex(size($deeX_mia_material)-1, $deeX_mia_material); //this remove the last entry: <done>

You can easely do a “for in” loop, test each name and delete if ok:

string $deeX_mia_materials[] = `lsType deeX_mia_material`; //list all deeX_mia_material
 stringArrayRemoveAtIndex(size($deeX_mia_materials)-1, $deeX_mia_materials); //this remove the last entry: <done>
 for($deeX_mia_material in $deeX_mia_materials) {
  if(isValidString($deeX_mia_material, "^Matte[_].*")) {
   delete $deeX_mia_material;
   print($deeX_mia_material+" -> Deleted
");
  }
 }

Another thing, you use some Maya function wich are not mel:

renderLayerEditorCreateContMap

You can search in documentation, this fonction doesn’t exist so be careful.
Last but not least:

createNode renderPass;
 rename "renderPass1" ("Matte_"+$Material[$i]);

Try to do not use rename command. Because you rename a “default” name wich can change if there already is renderPass.
Use this instead:

createNode -name ("Matte_"+$Material[$i]) renderPass;

So you name it directly to the creation and don’t let Maya give it a default name.
If you really whant to use rename command use that:

string $myRenderPass = `createNode renderPass`;
 rename $myRenderPass ("Matte_"+$Material[$i]);

So what ever name give Maya, you can use it. It’s also a good way.

Good luck!


#13

Here is where I stand now. Some things are working, but it falls apart when I add in important code:

renderLayerEditorDeleteLayer RenderLayerEditor Matte;
createRenderLayer -name "Matte" -number 1 -noRecurse `ls -selection`;

int $i;

string $Material[] = `ls -sl`;
int $selSize = `size $Material`;

for ($i =0; $i <$selSize ; $i++){


//Create Matte Pass

if(!`objExists ("Matte_"+$Material[$i])`)
			{

createNode -name ("Matte_"+$Material[$i]) renderPass;
setRenderPassType -type "MATTE" ("Matte_"+$Material[$i]);
connectAttr -nextAvailable Matte.renderPass ("Matte_"+$Material[$i]+".owner");
			}
			else
			{
			}



//Create Contribution 'Don't know why this works, but it does'



if(!`objExists ("Dummy_"+$Material[$i])`)
			{
renderLayerEditorCreateContMap RenderLayerTab Matte 0;
			}
			else
			{
					
delete ("passContributionMap"+($i+1));
			}





//// THIS IS WHERE THE PROBLEMS START ////

///Works... but only the first time you run the script for some reason
connectAttr ("Matte_"+$Material[$i]+".message") ("passContributionMap"+($i+1) +".renderPass");


/// Put objects in contribution Maps - Not working
hyperShade -objects ($Material[$i]+"SG");
$objects=`ls -sl`;
 editRenderLayerMembers -noRecurse Matte $objects[$i];
connectAttr -na ($objects[$i]+".message") ("passContributionMap"+($i+1) +".dagObjects");
}

Here are the problematic parts, if you take both of these out the Matte Pass, and contribution Maps will be created correctly.

  1. Attaching Matte Pass to Contribution map. Works perfect on the first run.

connectAttr ("Matte_"+$Material[$i]+".message") ("passContributionMap"+($i+1) +".renderPass");

But on the second Run it has an error because there is a previous connection. Oddly, it then creates a single contribution map.

  1. This is the part of the code that places objects from Materials into Contribution Maps.

hyperShade -objects ($Material[$i]+"SG");
$objects=`ls -sl`;
editRenderLayerMembers -noRecurse Matte $objects[$i];
connectAttr -na ($objects[$i]+".message") ("passContributionMap"+($i+1) +".dagObjects");
}

It works correctly for the very first shader. The second shader object does not show up in the contribution map. After that all other shaders and contribution maps that are suppose to be created don’t get made.


#14

Never mind I just fixed the problem #2 :slight_smile:

So that just leaves fixing problem #1 and the script will be 100% functional.


#15

You’re welcome… :rolleyes:


#16

Thank you so much Narann! Wouldn’t have been able to make it this far without your help.
:bowdown:

Still got that one nasty bug to work out, but I’m oh so very close now.


#17

Alright, I’m doing something wrong here either with the “isValidString”, or my “if” statement.

///Find and Delete Previous Contribution Maps
int $b;

for ($b=0; $b<500; $b++){
if (isValidString(("passContributionMap"+($b+1)), "([a-zA-Z]+)([a-zA-Z0-9_])*"))
{
}
else
{
delete ("passContributionMap"+($b+1));
}
}

#18

As I’d said, use “real name” is not a good option. Prefere list (with lsType) passContributionMap and use a “for in” loop.

“([a-zA-Z]+)([a-zA-Z0-9_])*”) << I don’t understand what you whant to do with that. isValidString use “regex” (http://www.regular-expressions.info/) This mean nothing at all.


#19

My bad I didn’t understand exactly how the isValidString works. Think I have a little better idea now of how . I take it the second part is the condition it needs to meet to return a value of 1 or 0? Either way I’m still having a hard getting the code right to find and delete existing contribution Maps.

Like I said earlier, I have no programming experience, in fact I can hardly believe I was able to get the rest of the script working.


#20

Got it:

isValidString(“passContributionMap1”, “^passContributionMap.*”);