Automatic lightmaps arrangement in Maya -----> export !

I have a very good news for the people who’ve had enough boring painful work to set the lightmap textures in Maya (i.e. using layered texture), which costs you several clicks to do these steps:

  • select object
  • open color channel
  • change blend mode
  • create new texture layer
  • select that layer
  • open layer’s color channel
  • create render node (file)
  • browse for texture
  • select the file
  • select object to edit UVs-textures link
    (in relationship editor)
  • select file/UV
  • select UV/file
    …that’s 12 clicks per object. My record for doing that is 10 seconds per object (excluding the time to select the correct texture file, say 3 or 5 more seconds). Let’s assume it’s 14 secs average, then for 20 objects, it costs 280 secs, or 5 minutes ? (let’s spend the remaining 20 secs for taking a breath)
    :laughing: :laughing:
    Now we don’t have to manually create the new texture layer for lightmap, set the blend mode to “multiply”, link the new UV to the lightmap texture, and so on. It’s history !!!
    It’s now can be done under a second, or more, depends on your objects counts, and only need a single click !!! :smiley:
    I don’t know if this has been supported in later versions, I’m still using v6.5, and I haven’t found any other simple way to do this. Read the explanation for yourself in the script’s header and the comments.

[size=117]MAIN SCRIPT PART[/size] [last edited 1/21/08]

/* Lightmap textures automatic-arrangement */

string $aboutLMAAScript ="\n\
This script performs automatic lightmap textures arrangement, after the necessary\n\
lightmap textures and it's UV set successfully generated.\n\
For a guide, go to : https://discourse.panda3d.org/viewtopic.php?t=2428\n\n\
This script does these things to each processed geometry :\n\
<1>. creates a new texture layer for the lightmap texture\n\
         WARNING :\n\
         by default, the new texture layer file object will be named \"fileLightmapXX\",\n\
         please do NOT change this name, or else the texture relocation ability will NOT work.\n\
<2>. creates the necessary shading network to allow the new texture layer to take effect\n\
<3>. [*] For texture assembling, it \"predicts\" the generated lightmap texture filename,\n\
              based on these priority patterns :\n\
              - 1st : [shadingEngine]-[object instance or transform node][meshName]\n\
              - 2nd : [shadingEngine]-[object instance or transform node]\n\
              This step searches the textures in your /lightMap directory.\n\
              To let this step works effectively, make sure to empty your /lightMap directory,\n\
              before rendering the lightmaps, so that there won't be other textures that\n\
              may have the same 1st priority namespace pattern.\n\
              The more important thing is you should NOT change any geometry name and\n\
              the rendered lightmap texture name, after rendering process until\n\
              running this script.\n\
         [*] For texture relocation, it reads the location directly from\n\
              the texture layer file object named \"fileLightmapXX\", as mentioned previously\n\
<4>. sets the 2nd top layer's (directly beneath lightmap layer) blend mode to \"multiply\"\n\
<5>. links the UV named \"lightmap\" to the lightmap texture\n\
<6>. last but not least :\n\
        Nobody needs to adjust the lightmap texture's UV, right ?\n\
        So, set the bottom texture's UV to be the current/active UV.\n\n\
THE PROCESS WILL BE APPLIED TO SELECTED GEOMETRIES, OR\n\
TO ALL GEOMETRIES IF NOTHING IS SELECTED.\n\n\
Author : Joni Hariyanto\n\
mail : ynjh.jo A gmail * com\n";

/* !!!!!!!!!!  WARNING  !!!!!!!!!!
HERE, YOU HAVE TO SUPPLY THE EXACT NAME OF THE UV SET USED TO OVERRIDE
THE LIGHTMAP TEXTURES GENERATION, OR ELSE, THIS SCRIPT WOULD NEVER WORK !!! */
string $defaultLightmapUVname= "lightmap";

string $undeterminedLMAATargetLoc = "somewhere on the disk";

global proc automaticLightmapsArrangement(
       string $LMloc, int $removeOrigTex, int $isAssembling, string $origLMloc)
{
global string $defaultLightmapUVname;
int $error=0;
$startTime = `timerX`;
print "\n\n\n\n##############################################\n";
print "Automatic lightmaps arrangement started.......\n";
print "##############################################\n\n";

string $defaultLightMapsLocation;
if (size($origLMloc)==0)
   $defaultLightMapsLocation = (`workspace -q -fn`+"/lightMap/");
else
   $defaultLightMapsLocation = ($origLMloc+"/");

int $copyLightmaps;
string $lightMapsLocation;
if (size($LMloc)==0)
   {
   $lightMapsLocation = $defaultLightMapsLocation;
   $copyLightmaps=0;
   $removeOrigTex=0;
   }
else
   {
   $lightMapsLocation = ($LMloc+"/");
   $copyLightmaps=1;
   }

// get the amount of the existing uvChoosers
string $uvCs[] = `lsType "uvChooser"`;
$numUVchoosersInScene = size($uvCs);

// list selected geometries
string $sel[] = `ls -dag -type geometryShape -sl`;
string $numObjects = (size($sel)+" selected");
// if nothing is selected, list all geometries
int $selectionSize = size($sel);
if($selectionSize==0)
  {
  $sel =`ls -geometry`;
  $selectionSize = size($sel);
  if($selectionSize==0)
     $selectionSize=1; // just a hack so progressBar likes it
  $numObjects = "all";
  }

window -title "progress" -titleBar 0 -height 1 -sizeable 1 -rtf 1 processProgress;
   columnLayout -columnAlign "center" -columnOffset "both" 5 -adjustableColumn 1;
      separator;
      progressBar -maxValue $selectionSize -width 355 processPB;
      separator;
showWindow processProgress;

for ($g in $sel)
  {

  // get the shading engine of current geometry
  string $conn[] = `listConnections -type "shadingEngine" $g`;
  string $shadingEngine = $conn[0];

  /* first, check if the geometry has "surfaceShader" attribute.
     The actual geometries have it, but the historical ones do not,
     so if it doesn't exist, step ahead to the next geometry. */
  if (!(`attributeExists "surfaceShader" $shadingEngine`))
     {
     progressBar -edit -step 1 processPB;
     continue;
     }

  print ("GEOMETRY      : "+$g+"\n");

  string $lightmapFilename[];
  if ($isAssembling)
     {
     // search for possible texture's lightmap file
     string $fullpathParent = firstParentOf($g);
     int $size = size($fullpathParent);
     string $transformNode = fileExtension(substituteAllString($fullpathParent, "|", "."));
     if (size($transformNode)==0)
        $transformNode = `substring $fullpathParent 2 $size` ;
     string $possibleFilenames[];
     clear($possibleFilenames);
     $possibleFilenames[0]=$shadingEngine+"-"+$transformNode+$g+".*";
     $possibleFilenames[1]=$shadingEngine+"-"+$transformNode+".*";
     for ($fnIdx = 0; $fnIdx < 2; $fnIdx++)
        {
        $lightmapFilename=`getFileList -folder $defaultLightMapsLocation -filespec $possibleFilenames[$fnIdx]`;
        if (size($lightmapFilename)>0) break;
        }

     print ("transformNode : "+$transformNode+"\n");

     // if no texture filename match
     if (size($lightmapFilename)==0)
        {
        print "WARNING : NO POSSIBLE TEXTURE FILE FOUND FOR THIS GEOMETRY\n....skipped....\n";
        print "=========================================================\n";
        progressBar -edit -step 1 processPB;
        $error=1;
        continue;
        }

     }

  print (" SHADING ENGINE  : "+$shadingEngine+"\n");

  // get the material of current geometry
  string $mats[] = `listConnections -source true -destination false ($shadingEngine+".surfaceShader")`;
  string $material = $mats[0];
  print (" MATERIAL        : "+$material+"\n");

  // get the layeredTexture material of current geometry
  string $materialConn[] = `listConnections -type "layeredTexture" $material`;
  string $layeredTexture = $materialConn[0];
  int $numLayeredTexture = `getAttr -size ($layeredTexture+".inputs")`;
  $inputColorChannel = $layeredTexture + ".inputs[" + $numLayeredTexture + "].color";
  print (" LAYERED TEXTURE : "+$layeredTexture+"\n");
  print ("        contains : "+$numLayeredTexture+" texture(s)\n");

  string $newTextureFile,$newPlace2dTexture;
  if ($isAssembling)
     {
     // check if current geometry is already using the lightmap texture
     int $alreadyLightmapped=0;
     string $layeredTextureFiles[] = `listConnections -type "file" $layeredTexture`;
     for ($ltf in $layeredTextureFiles)
       {
       string $fn = getAttr ($ltf+".fileTextureName");
       $shortFileName = basename( $fn,"" );
       if ($shortFileName==$lightmapFilename[0]) // check if textures filename match
          {
          print ("Geometry is already using this texture file :\n"+$fn+"\n");
          print "....skipped....\n";
          print "=========================================================\n";
          $alreadyLightmapped=1;
          }
       }
     // proceed to the next geometry if it is
     if ($alreadyLightmapped)
        {
        progressBar -edit -step 1 processPB;
        continue;
        }

     // create new texture layer to hold the lightmap texture, and create the necessary shading network
     $newTextureFile = `shadingNode -asTexture file`;
     string $ntf = $newTextureFile;
     $fileIdx = `substring $ntf 5 255`;
     $newTextureFile = `rename $newTextureFile ("fileLightmap"+$fileIdx)`;
     $newPlace2dTexture = `shadingNode -asUtility place2dTexture`;
     connectAttr -f ($newPlace2dTexture+".coverage")        ($newTextureFile+".coverage");
     connectAttr -f ($newPlace2dTexture+".translateFrame")  ($newTextureFile+".translateFrame");
     connectAttr -f ($newPlace2dTexture+".rotateFrame")     ($newTextureFile+".rotateFrame");
     connectAttr -f ($newPlace2dTexture+".mirrorU")         ($newTextureFile+".mirrorU");
     connectAttr -f ($newPlace2dTexture+".mirrorV")         ($newTextureFile+".mirrorV");
     connectAttr -f ($newPlace2dTexture+".stagger")         ($newTextureFile+".stagger");
     connectAttr -f ($newPlace2dTexture+".wrapU")           ($newTextureFile+".wrapU");
     connectAttr -f ($newPlace2dTexture+".wrapV")           ($newTextureFile+".wrapV");
     connectAttr -f ($newPlace2dTexture+".repeatUV")        ($newTextureFile+".repeatUV");
     connectAttr -f ($newPlace2dTexture+".offset")          ($newTextureFile+".offset");
     connectAttr -f ($newPlace2dTexture+".rotateUV")        ($newTextureFile+".rotateUV");
     connectAttr -f ($newPlace2dTexture+".noiseUV")         ($newTextureFile+".noiseUV");
     connectAttr -f ($newPlace2dTexture+".vertexUvOne")     ($newTextureFile+".vertexUvOne");
     connectAttr -f ($newPlace2dTexture+".vertexUvTwo")     ($newTextureFile+".vertexUvTwo");
     connectAttr -f ($newPlace2dTexture+".vertexUvThree")   ($newTextureFile+".vertexUvThree");
     connectAttr -f ($newPlace2dTexture+".vertexCameraOne") ($newTextureFile+".vertexCameraOne");
     connectAttr ($newPlace2dTexture+".outUV")              ($newTextureFile+".uv");
     connectAttr ($newPlace2dTexture+".outUvFilterSize")    ($newTextureFile+".uvFilterSize");
     connectAttr -force ($newTextureFile+".outColor")        $inputColorChannel;

     // the texture must be physically exist before calling setAttr file.fileTextureName
     relocateLightmapTexture( $copyLightmaps, $removeOrigTex,
                              $defaultLightMapsLocation, $lightMapsLocation,
                              $lightmapFilename[0] );

     // set texture's filename
     setAttr ($newTextureFile + ".fileTextureName") -type "string" ($lightMapsLocation+$lightmapFilename[0]);
     print ("Lightmap texture applied : "+$lightmapFilename[0]+"\n");

     // set the bottom- or 2nd top-layer's blend mode to "multiply", or 6
     setAttr ($layeredTexture + ".inputs[" + ($numLayeredTexture-1) + "].blendMode") 6;

     // UV linking
     $uvChooserName = ("uvCh_lightmap"+$numUVchoosersInScene);
     $numUVchoosersInScene+=1;
     createNode uvChooser -name $uvChooserName;
     connectAttr ($uvChooserName+".outVertexUvOne") ($newPlace2dTexture+".vertexUvOne");
     connectAttr ($uvChooserName+".outVertexUvTwo") ($newPlace2dTexture+".vertexUvTwo");
     connectAttr ($uvChooserName+".outVertexUvThree") ($newPlace2dTexture+".vertexUvThree");
     connectAttr ($uvChooserName+".outVertexCameraOne") ($newPlace2dTexture+".vertexCameraOne");
     connectAttr ($uvChooserName+".outUv") ($newPlace2dTexture+".uvCoord");
     $numUVset = `getAttr -size ($g+".uvSet")`;
     for ($uvIdx = 0; $uvIdx < $numUVset; $uvIdx++)
        {
        if (`getAttr ($g+".uvSet["+$uvIdx+"].uvSetName")` == $defaultLightmapUVname)
           connectAttr ($g+".uvSet["+$uvIdx+"].uvSetName") ($uvChooserName+".uvSets[0]");
        }

     // set the UVset to be active
     /* I won't need to adjust the lightmap's UV in the future, so
        I'd like to have the very bottom UV layer to be active. */
     $wantedUVsetName = `getAttr ($g+".uvSet[0].uvSetName")`;
     setAttr ($g+".currentUVSet") -type "string" $wantedUVsetName;

     }

  else // ONLY NEED TO UPDATE FILE REFERENCE

     {
     string $existingLMtexturePath="";
     string $existingLMtex;
     $numUVset = `getAttr -size ($g+".uvSet")`;
     for ($uvIdx = 0; $uvIdx < $numUVset; $uvIdx++)
        {
        if (`getAttr ($g+".uvSet["+$uvIdx+"].uvSetName")`==$defaultLightmapUVname)
           {
           // uvSet - uvChooser connection
           $uvCs = `listConnections -type "uvChooser" ($g+".uvSet["+$uvIdx+"].uvSetName")`;
           for ($uvC in $uvCs)
               {
               // uvChooser - place2dTexture connection
               $p2dTs=`listConnections($uvC+".outUv")`;
               for ($p2dT in $p2dTs)
                   {
                   // place2dTexture - file connection
                   string $fs[]=`listConnections ($p2dT+".outUV")`;
                   for ($f in $fs)
                       {
                       // look for "Lightmap" in the file object name
                       if ( `gmatch $f "*Lightmap*"` && size($existingLMtexturePath)==0 )
                          {
                          $existingLMtex=$f;
                          $existingLMtexturePath = `getAttr ($f+".fileTextureName")`;
                          break;
                          }
                       }
                   if (size($existingLMtexturePath)>0)
                      break;
                   }
               if (size($existingLMtexturePath)>0)
                  break;
               }
           }
        }
     if (size($existingLMtexturePath)==0)
        {
        print "<ERROR> Could not find lightmap texture file object in layeredTexture material.\n";
        print "<fact_1> In order to relocate the texture and updating the file reference,\n";
        print "         it is necessary to have it applied first.\n";
        print "<suggestion_1> If you haven't applied it yet, please press \"ASSEMBLE NOW\" button.\n";
        print "<fact_2> Lightmap texture file object must be named at least \"Lightmap\", without quotes.\n";
        print "<suggestion_2> In order to properly identify whether it is a lightmap texture,\n";
        print "               please DO NOT change it's name, which was generated by this script too.\n";
        print ".... skipped from texture relocation ....\n";
        print "=========================================================\n";
        progressBar -edit -step 1 processPB;
        $error=1;
        continue;
        }

     // override the texture location for duplication and/or deletion
     $defaultLightMapsLocation = (dirname($existingLMtexturePath)+"/");
     // the lightmap texture filename
     string $LMfilename = basename( $existingLMtexturePath,"" );
     // the texture must be physically exist before calling setAttr file.fileTextureName
     relocateLightmapTexture( $copyLightmaps, $removeOrigTex,
                              $defaultLightMapsLocation, $lightMapsLocation,
                              $LMfilename );
     setAttr ($existingLMtex+".fileTextureName") -type "string" ($lightMapsLocation+$LMfilename);
     print ("---> lightmap texture file reference updated to :\n      "+
           ($lightMapsLocation+$LMfilename)+"\n");
     }

  progressBar -edit -step 1 processPB;
  print "=========================================================\n";
  }  // END OF ITERATION

select -clear;
deleteUI processProgress;

print ("\n");
if ($error)
   warning "COULD BE BAD NEWS :( . Please open Script Editor for details.\n";
else
   print ("Automatic lightmaps arrangement of "+$numObjects+" object(s) COMPLETED in "+`timerX -st $startTime`+" seconds !\n");

}

global proc relocateLightmapTexture(
       int $copyLightmaps, int $removeOrigTex,
       string $defaultLightMapsLocation, string $lightMapsLocation,
       string $LMFilename )
{
  if ( dirname($defaultLightMapsLocation+"x")==dirname($lightMapsLocation+"x") )
     return;
  // copy lightmap texture ?
  if ($copyLightmaps)
     {
     sysFile -copy ($lightMapsLocation+$LMFilename)
                   ($defaultLightMapsLocation+$LMFilename);
     print ("Lightmap texture copied from :\n  "+($defaultLightMapsLocation+$LMFilename)+"\n    to :\n  "+($lightMapsLocation+$LMFilename)+"\n");
     }
  // remove original lightmap texture ?
  if ($removeOrigTex)
     {
     sysFile -delete ($defaultLightMapsLocation+$LMFilename);
     print ("Original lightmap texture deleted from :\n  "+$defaultLightMapsLocation+"\n");
     }
}

[size=117]GUI PART for Windows platform :[/size] [last edited 1/10/08]

/////////////////////////////////////////////////////////
//                                                     //
//                       GUI PART                      //
//                                                     //
/////////////////////////////////////////////////////////
if (`window -q -exists lightmapsAutoArrangementGUI`)
   window -edit -visible 1 lightmapsAutoArrangementGUI;
else
   {
   print "WINDOW CREATED\n";
   global string $copyModeText="COPY lightmap textures to : ";
   global string $moveModeText="MOVE lightmap textures to : ";
   window -width 420 -mnb 0 -mxb 0 -rtf 1 -title "Lightmaps  Auto-Arrangement"
          -menuBar 1
          -retain lightmapsAutoArrangementGUI;
      menu -label "Help" -helpMenu true;
         menuItem
           -label "About this script"
           -command "window -edit -visible 1 helpAboutLMAAScript"
           ;

      columnLayout -adjustableColumn 1 -columnAttach "both" 5;

      text
         -label "\nWELCOME !\nYou should run this script if you already had :\n\n\
    1. used layeredTexture material, exactly as described here :    \n\
https://discourse.panda3d.org/viewtopic.php?t=2428\n\
2. rendered/baked the light/shadow to textures\n\
    3. (optional) backed up your scene, in case something going wrong    \n\n\
   NOTE : the process will be applied to selected geometries, or    \n\
   to all geometries if nothing is selected.   \n"
         introText;

      separator;

      checkBox
         -label "override lightmap original location (only needed for assembling)"
         -align "left"
         -onCommand "button -edit -enable 1 browseOrigLMFolderButton"
         -offCommand "button -edit -enable 0 browseOrigLMFolderButton"
         overrideLMlocCB;

      rowLayout
         -numberOfColumns 3
         -adjustableColumn 2
         -columnWidth3  85 300 15
         -columnAlign  1 "center"
         -columnAttach 1 "right" 3
         ;
         button
            -label "browse"
            -enable 0
            -command "pickOrigLMFolder"
            browseOrigLMFolderButton;
         textField
            -editable 0
            -enable 1
            -text (`workspace -q -fn`+"/lightMap")
            origLMlocationTF;
         text -label "--->";

      setParent ..; // go back 1 layout level

      separator;

      checkBox
         -label $copyModeText
         -align "left"
         -changeCommand "copyStatusChanged"
         -value 1
         relocateCB;

         columnLayout -columnAttach "left" 20;

            radioCollection locationRC;
               radioButton
                  -label "current file location"
                  -align "left"
                  -select
                  -enable `checkBox -q -value relocateCB`
                  currentFile;
               radioButton
                  -label "other location"
                  -align "left"
                  -enable `checkBox -q -value relocateCB`
                  -onCommand "button -edit -enable 1 browseFolderButton"
                  -offCommand "button -edit -enable 0 browseFolderButton"
                  otherLocation;

         setParent ..; // go back 1 layout level

      rowLayout
         -numberOfColumns 3
         -adjustableColumn 2
         -columnWidth3  85 300 15
         -columnAlign  1 "center"
         -columnAttach 1 "right" 3
         ;
         button
            -label "browse"
            -enable 0
            -command "pickTargetFolder"
            browseFolderButton;
         textField
            -editable 0
            -enable 1
            -text $undeterminedLMAATargetLoc
            locationTF;
         text -label "--->";

      setParent ..; // go back 1 layout level

      columnLayout -columnAttach "left" 20;

         checkBox
            -label "remove original textures"
            -align "left"
            -value 0
            -enable `checkBox -q -value relocateCB`
            -onCommand "checkBox -edit -label $moveModeText relocateCB"
            -offCommand "checkBox -edit -label $copyModeText relocateCB"
            removeTexCB;

      setParent ..; // go back 1 layout level

      separator;

      columnLayout -adjustableColumn 1 -rowSpacing 2 -columnOffset "both" 5;

         button
            -label "ASSEMBLE NOW"
            -height 50
            -command "assembleNow 1" // WILL ASSEMBLE
            -ann "If you're ready to apply the lightmap textures, go ahead !"
            ;
         button
            -label "ONLY RELOCATE TEXTURES and UPDATE FILES REFERENCE"
            -command "assembleNow 0" // WILL NOT ASSEMBLE
            -enable `checkBox -q -value relocateCB`
            -ann "Relocates the lightmap textures around, plus updating their file reference in the layeredTexture material"
            relocateNupdateOnlyBtn;
         button
            -label "remove this window and reset settings"
            -command "deleteUI \"lightmapsAutoArrangementGUI\""
            ;
   showWindow lightmapsAutoArrangementGUI;
   }


global proc copyStatusChanged()
{
  if (`checkBox -query -value relocateCB`) {
     radioButton -edit -enable 1 currentFile;
     radioButton -edit -enable 1 otherLocation;
     if (`radioButton -query -select otherLocation`)
        button -edit -enable 1 browseFolderButton;
     checkBox -edit -enable 1 removeTexCB;
     button -edit -enable 1 relocateNupdateOnlyBtn;
     }
  else {
     radioButton -edit -enable 0 currentFile;
     radioButton -edit -enable 0 otherLocation;
     button -edit -enable 0 browseFolderButton;
     checkBox -edit -enable 0 removeTexCB;
     button -edit -enable 0 relocateNupdateOnlyBtn;
     }
}


global proc assembleNow(int $isAssembling)
{
  global string $undeterminedLMAATargetLoc;
  string $origLMloc=`textField -q -text origLMlocationTF`;
  int $removeOrigTex= `checkBox -q -value removeTexCB`;
  if (`checkBox -query -value relocateCB`) // IF MUST BE RELOCATED
     {
     string $locChoice = `radioCollection -query -select locationRC`;
     switch($locChoice) {
        case "currentFile":
           string $sceneFilePath = dirname(`file -q -sceneName`);  // scene location
           if (size($sceneFilePath)>0)
              {
              print ("will be moved to current file location : "+$sceneFilePath+"\n");
              window -edit -visible 0 lightmapsAutoArrangementGUI;
              // GO ASSEMBLE THE TEXTURES NOW !!!
              automaticLightmapsArrangement($sceneFilePath,  // pass scene location
                   $removeOrigTex, $isAssembling, $origLMloc);
              }
           else
              {
              warning "PLEASE SAVE YOUR SCENE. How could I possibly know where to copy it to ?  MAGIC ?\n";
              confirmDialog -title "" -messageAlign "center" -message "Lightmap duplication location not yet determined !\nPlease save your scene first ;)";
              }
           break;
        case "otherLocation":
           string $loc = `textField -q -text locationTF`;
           if ($loc==$undeterminedLMAATargetLoc)
              {
              warning "YOU HAVEN'T SET THE LOCATION YET\n";
              confirmDialog -title "" -messageAlign "center" -message "Lightmap duplication location not yet determined !\nPlease select a location.";
              // let user pick a folder
              pickTargetFolder();
              // if user canceled folder picking, don't do anything, otherwise
              // GO FOR IT, BABY !!!
              if (`textField -q -text locationTF`!=$undeterminedLMAATargetLoc)
                 assembleNow($isAssembling);
              }
           else
              {
              print("will be moved to other location : "+$loc+"\n");
              window -edit -visible 0 lightmapsAutoArrangementGUI;
              // GO ASSEMBLE THE TEXTURES NOW !!!
              automaticLightmapsArrangement($loc,  // pass the prefered location
                   $removeOrigTex, $isAssembling, $origLMloc);
              }
           break;
        }
     }
  else  // IF MUST NOT BE RELOCATED
     {
     window -edit -visible 0 lightmapsAutoArrangementGUI;
     print "lightmap textures won't be moved around\n";
     // GO ASSEMBLE THE TEXTURES NOW !!!
     automaticLightmapsArrangement("",  // pass blank string
          0, 1, $origLMloc);
     }
}


global proc pickTargetFolder()
{
   global string $undeterminedLMAATargetLoc;
   string $sceneFilePath = dirname(`file -q -sceneName`);  // scene location
   if (size($sceneFilePath)>0)
      {
      string $lastLoc=`textField -q -text locationTF`;
      if ($lastLoc!=$undeterminedLMAATargetLoc)
         workspace -dir $lastLoc; // points the browser to the last selected location
      else
         workspace -dir $sceneFilePath; // points the browser to scene location
      }
   fileBrowserDialog -mode 4 -fileCommand "gotTargetFolder" -actionName "Pick a target location";
   // restore the workspace
   workspace -dir $sceneFilePath;
}

global proc gotTargetFolder(string $destination, string $fileType)
{
   textField -edit -fileName $destination locationTF;
}

global proc pickOrigLMFolder()
{
   string $sceneFilePath = dirname(`file -q -sceneName`);  // scene location
   workspace -dir `textField -q -text origLMlocationTF`;  // points the browser to the last picked location
   fileBrowserDialog -mode 4 -fileCommand "gotOrigLMFolder" -actionName "Where are your lightmaps ?";
   // restore the workspace
   workspace -dir $sceneFilePath;
}

global proc gotOrigLMFolder(string $destination, string $fileType)
{
   textField -edit -fileName $destination origLMlocationTF;
}

[size=117]For other platforms :[/size]
I haven’t had enough experiment using the cross-platform command. Meanwhile, use :

// GO ASSEMBLE THE TEXTURES NOW !!!
automaticLightmapsArrangement("",   // pass blank string
     0, 1, "");

Usage instruction :
to run it, first, combine those 2 code parts together, you could append the gui part at the end of the main part.

I’ve tested it on several “crazy” scenes, and it works perfectly, no bugs at all, and beautifully powerful !!

[EDIT 3/4/07]
if there is no possible lightmap texture filename in lightMap directory, the process would continue to the next geometry, instead of throwing an error.

Godspeed !

this seems very useful indeed! thanks for this. I haven’t tried it out yet, but I’m sure it will come in handy in the near future.

You could try it with my [experimental scene] (use your own textures), xtract this [lightmaps] to your maya\projects\default\lightMap.
If you get this error :

run the MEL script again.
This used to happen for the 1st time it run after opening Maya. I don’t know what causes this, Maya’s namespace is still foggy for me. Do you know what’s going on ?

A question :
does [THIS] still happen in v8 ? Let me know if you find other easy way.

Just a simple guide about the pipeline :

[size=134]1. LAYERED TEXTURE MATERIAL[/size]

[EDIT] 1/13/08:
I’ve created another MEL script to automate this material setup, plus applying the base texture after it, for each geometry.
Read the header for explanation :

/*****************************************************************************

A QUICK SETUP OF NEW LAYERED TEXTURE MATERIAL


For each geometry, this script does these things, sequentially :
1. <FOR NON-TEXTURED GEOMETRY> :
      assigns a new lambert material, set the outcolor to layeredTexture

   <FOR ALREADY-TEXTURED GEOMETRY> :
      creates layeredTexture, redirects the texture file connection
      from material's color channel to the 1st layer's color channel,
      and <PROCESS NEXT GEOMETRY>.
      So the original texture will be the layeredTexture's base texture. :D

   <FOR ALREADY-LAYEREDTEXTURED GEOMETRY> :
      If the 1st layer's color channel had NOT been connected to a texture file,
         a new file reference and it's shading network will be created.
      If the 1st layer's color channel had been connected to a texture file,
         but the file reference is still empty, jump to <NEXT STEP (2)>

2. and eventually asks the user to choose the base texture


So, I only need to focus on UV layout (if hasn't been done),
instead of wasting my time for setting up materials & base textures,
which is 14 seconds (my best time :S) per geometry,
excluding the time to choose the base texture.

It's 21st century now, and say I have a lot of geometries,
when would it all done ?  Next century ?  WT* ???
I'm afraid I can't live that long.

THE PROCESS WILL BE APPLIED TO SELECTED GEOMETRIES, OR
TO ALL GEOMETRIES IF NOTHING IS SELECTED.

NOTE :
I decided not to use this command :
  AEfileTextureBrowser ("AEassignTextureCB "+$newTextureFile+".fileTextureName")
for opening the file picker dialog, since it is not loaded during Maya startup.
It's loaded the 1st time you select Maya's browse-for-file button.
So, if I run this script before selecting any of the browse-for-file button,
it would simply crash.
I use fileDialog (cross-platform file picker command) instead,
and supply a list of texture file extensions myself,
which is the list of extensions supported by Panda3D.
So, should this list grow, you would have to update it yourself.


Author : Joni Hariyanto
mail : ynjh.jo A gmail * com
******************************************************************************/


global proc createNewLayeredTextureMaterial()
{
print "\n\n\n#################################################\n\
NEW LAYERED TEXTURE MATERIAL SETUP STARTED...\n\
#################################################\n\n";
// list selected geometries
string $sel[] = `ls -dag -type geometryShape -sl`;
// if nothing is selected, list all geometries
if(size($sel)==0)
  $sel =`ls -geometry`;

// maximize the 3d viewport for better view, similar to pressing Ctrl-space
setAllMainWindowComponentsVisible(0);


for ($g in $sel)
  {
  // get object's transform
  string $fullpathParent = firstParentOf($g);
  int $size = size($fullpathParent);
  $transformNode = fileExtension(substituteAllString($fullpathParent, "|", "."));
  if (size($transformNode)==0)
     $transformNode = `substring $fullpathParent 2 $size`;

  string $conn[] = `listConnections -type "shadingEngine" $g`;
  string $shadingEngine = $conn[0];

  /* first, check if the geometry has "surfaceShader" attribute.
     The actual geometries have it, but the historical ones do not,
     so if it doesn't exist, step ahead to the next geometry. */
  if (!(`attributeExists "surfaceShader" $shadingEngine`))
     continue;

  print ("GEOMETRY      : "+$g+"\n");

  string $mats[] = `listConnections -source true -destination false ($shadingEngine+".surfaceShader")`;
  string $material = $mats[0];
  print (" MATERIAL        : "+$material+"\n");

  // get the layeredTexture material of current geometry
  string $materialConn[] = `listConnections -type "layeredTexture" $material`;
  if (size($materialConn)>0) // GEOMETRY ALREADY HAVE LAYERED TEXTURE MATERIAL
     {
     string $layeredTexture = $materialConn[0];
     print "GEOMETRY ALREADY HAVE LAYERED TEXTURE MATERIAL\n";
     print (" LAYERED TEXTURE : "+$layeredTexture+"\n");

     $inputColorChannel = $layeredTexture + ".inputs[0].color";
     string $LTbaseTexFile[]= `listConnections -type "file" $inputColorChannel`;
     if (size($LTbaseTexFile)>0)  // the 1st layer color channel is already connected to a file
        {
        $layer0filename = `getAttr ($LTbaseTexFile[0]+".fileTextureName")`;
        if (size($layer0filename)>0) // the 1st layer texture file is already specified
           {
           print ("  the 1st layer is already used by this file :\n   "+$layer0filename+"\n");
           print "....skipped....\n";
           print "=========================================================\n";
           }
        else  // the 1st layer texture file has NOT specified yet
           {
           print ("  the 1st layer is set for a texture file, but it has not specified yet\n");
           select $g; // select geometry, to let me see which one is currently textured
           fitPanel -selected; // set view focus on selected geometry
//            refresh; // force refresh the 3d viewport
           // let me browse for base texture
           $layer0filename = browseFileTexture($LTbaseTexFile[0]);
           if (size($layer0filename)>0) // user picked a texture
              print ("  good, you just set it to this file :\n    "+$layer0filename+"\n");
           else  // user didn't pick a texture
              print ".... God knows why you didn't pick a texture ....\n";
           print "=========================================================\n";
           }
        }
     else   // the 1st layer color channel is NOT connected to a file
        {
        print "  the 1st layer's color is empty. You should pick a texture.\n";
        // create new texture layer and let user pick a texture
        $layer0filename = createNewTexLayerNpickTex($g, $inputColorChannel);
        if (size($layer0filename)>0) // user picked a texture
           print ("  good, you just set it to this file :\n    "+$layer0filename+"\n");
        else  // user didn't pick a texture
           print ".... God knows why you didn't pick a texture ....\n";
        print "=========================================================\n";
        }
     continue;
     }

  string $existingFiles[] = `listConnections -type "file" ($material+".color")`;
  string $existingTextureFile = "";
  int $alreadyHasTexture=0;
  // Is there already a texture file connected to color channel ?
  if (size($existingFiles)>0)  // there IS already applied texture
     {
     $existingTextureFile = $existingFiles[0];
     $alreadyHasTexture=1;
     $existingTextureFileName = `getAttr ($existingTextureFile+".fileTextureName")`;
     print "GEOMETRY ALREADY HAVE TEXTURE APPLIED :\n  ";
     print ($existingTextureFile+" : "+$existingTextureFileName+"\n");
     }
  else  // CREATE NEW MATERIAL, if there is not already applied texture
     {
     createAndAssignShader lambert $transformNode;
     string $newSEconn[] = `listConnections -type "shadingEngine" $g`;
     $shadingEngine = $newSEconn[0];
     string $newMaterial[] = `listConnections -source true -destination false ($shadingEngine+".surfaceShader")`;
     $material = $newMaterial[0];
     print ("NEW MATERIAL CREATED : "+$material+"\n");
     }

  // create layeredTexture and connect it to the new material's color channel
  $layeredTexture = `shadingNode -asTexture layeredTexture`;
  connectAttr -force ($layeredTexture+".outColor") ($material+".color");
  $inputColorChannel = $layeredTexture + ".inputs[0].color";

  if ($alreadyHasTexture)
     {
     // let's preserve the existing texture as the layeredTexture's base texture,
     // connect it to color channel of the layeredTexture's base texture
     connectAttr -force ($existingTextureFile+".outColor") $inputColorChannel;
     print "---> the existing texture file now used for layeredTexture's base texture\n";
     }
  else // there is not already applied texture
     {
     // create new texture layer and let user pick a texture
     createNewTexLayerNpickTex($g, $inputColorChannel);
     }

  print "=========================================================\n";

  } // END OF ITERATION

// clear the last selected geometry
select -clear;
toggleAllMainWindowComponentsVisible;
print "\n\n";
print "DONE ASSIGNING NEW LAYERED TEXTURE MATERIAL.\n";
}


global proc string createNewTexLayerNpickTex(string $geometry, string $inputColorChannel)
{
   // create new texture file and setup shading network
   $newTextureFile = `shadingNode -asTexture file`;
   $newPlace2dTexture = `shadingNode -asUtility place2dTexture`;
   connectAttr -f ($newPlace2dTexture+".coverage")        ($newTextureFile+".coverage");
   connectAttr -f ($newPlace2dTexture+".translateFrame")  ($newTextureFile+".translateFrame");
   connectAttr -f ($newPlace2dTexture+".rotateFrame")     ($newTextureFile+".rotateFrame");
   connectAttr -f ($newPlace2dTexture+".mirrorU")         ($newTextureFile+".mirrorU");
   connectAttr -f ($newPlace2dTexture+".mirrorV")         ($newTextureFile+".mirrorV");
   connectAttr -f ($newPlace2dTexture+".stagger")         ($newTextureFile+".stagger");
   connectAttr -f ($newPlace2dTexture+".wrapU")           ($newTextureFile+".wrapU");
   connectAttr -f ($newPlace2dTexture+".wrapV")           ($newTextureFile+".wrapV");
   connectAttr -f ($newPlace2dTexture+".repeatUV")        ($newTextureFile+".repeatUV");
   connectAttr -f ($newPlace2dTexture+".offset")          ($newTextureFile+".offset");
   connectAttr -f ($newPlace2dTexture+".rotateUV")        ($newTextureFile+".rotateUV");
   connectAttr -f ($newPlace2dTexture+".noiseUV")         ($newTextureFile+".noiseUV");
   connectAttr -f ($newPlace2dTexture+".vertexUvOne")     ($newTextureFile+".vertexUvOne");
   connectAttr -f ($newPlace2dTexture+".vertexUvTwo")     ($newTextureFile+".vertexUvTwo");
   connectAttr -f ($newPlace2dTexture+".vertexUvThree")   ($newTextureFile+".vertexUvThree");
   connectAttr -f ($newPlace2dTexture+".vertexCameraOne") ($newTextureFile+".vertexCameraOne");
   connectAttr ($newPlace2dTexture+".outUV")              ($newTextureFile+".uv");
   connectAttr ($newPlace2dTexture+".outUvFilterSize")    ($newTextureFile+".uvFilterSize");
   // connect the texture file to color channel of the layeredTexture's base texture
   connectAttr -force ($newTextureFile+".outColor") $inputColorChannel;

   select $geometry; // select the geometry, to highlight which one is currently textured
   fitPanel -selected; // set view focus on selected geometry
//    refresh; // force refresh the 3d viewport
   // let me browse for base texture
   return browseFileTexture($newTextureFile);
}

global proc string browseFileTexture(string $texFileObject)
{
   $pickedTexFile = `fileDialog -dm "*.als; *.bmp; *.img; *.jpg; *.jpeg;\
        *.pbm; *.pgm; *.pic; *.pix; *.png; *.pnm; *.ppm; *.rgb; *.rgba; *.sgi; *.soft;\
        *.tga; *.tif; *.tiff"`;
   setAttr ($texFileObject+".fileTextureName") -type "string" $pickedTexFile;
   return $pickedTexFile;
}


createNewLayeredTextureMaterial();

[size=134]2. RENDERING/BAKING THE LIGHT/SHADOW[/size]
Before proceed, backup your Maya file, in case something going wrong.

Lighting/Shading >> Batch bake (mental ray) [option box]

Check “Keep original shading network” to avoid new material assignment after baking.
Make sure to leave the lightmap textures prefix blank, since the MEL script doesn’t know anything about it. The texture name search only uses the object’s name.
Set UV set name override to “lightmap” without quotes. It must match with the name in the MEL script (near the top, look for warning).

3. Once you’re ready to assemble the lightmap textures, if you have saved the MEL script to the shelf, click the icon on the shelf.
movie (1.78 MB)

this still happens in 8, I’m not sure why but I guess it doesn’t matter too much :slight_smile:

I copied over your test files and placed the lightmaps into projects/default/lightMap/ , and replaced your color maps for my own, but it still throws the error:

if my version of Maya is not installed to the c: drive would that be the cause?

Actually, that substring error wasn’t what I asked. There is a link to discourse.panda3d.org/viewtopic.php?t=1702.

About the total failure, I’m not sure, unless you can tell me the result for this :

print `workspace -q -fn`+"/lightMap/";

It should points to your projects\default\lightMap.
What’s your OS ?

Do you mind posting some of the geometries name from ScriptEditor ?

Using that scene, you should only load it, copy the lightmaps to \lightMap, assign your own color texture to each objects’ layeredTexture’s color, and run the MEL.

Windows XP

…I don’t know if that means the textures should be renamed with “Shape” appended to each name or what.

oh, and I believe Maya 8 still has that same issue with the UV texture editor window…

so, does

print(`workspace -q -fn`+"/lightMap/");

point to your \lightMap ?

Where did you copy the scene ?

this is mine :
[size=75]GEOMETRY : pConeShape1
transformNode : pCone1
SHADING ENGINE : lambert4SG
MATERIAL : lambert4
LAYERED TEXTURE : layeredTexture3
contains : 1 texture(s)
Lightmap texture applied : lambert4SG-pCone1.jpg

GEOMETRY : pCylinderShape1
transformNode : pCylinder1
SHADING ENGINE : lambert3SG
MATERIAL : lambert3
LAYERED TEXTURE : layeredTexture2
contains : 1 texture(s)
Lightmap texture applied : lambert3SG-pCylinder1.jpg

GEOMETRY : pPlaneShape1
transformNode : pPlane1
SHADING ENGINE : lambert5SG
MATERIAL : lambert5
LAYERED TEXTURE : layeredTexture4
contains : 1 texture(s)
Lightmap texture applied : lambert5SG-pPlane1.jpg

GEOMETRY : polySurfaceShape1
transformNode : polySurface1
SHADING ENGINE : lambert7SG
MATERIAL : lambert7
LAYERED TEXTURE : layeredTexture6
contains : 1 texture(s)
Lightmap texture applied : lambert7SG-polySurface1.jpg

GEOMETRY : polySurfaceShape2
transformNode : polySurface2
SHADING ENGINE : lambert6SG
MATERIAL : lambert6
LAYERED TEXTURE : layeredTexture5
contains : 1 texture(s)
Lightmap texture applied : lambert6SG-polySurface2.jpg

GEOMETRY : polySurfaceShape3
transformNode : polySurface3
SHADING ENGINE : lambert8SG
MATERIAL : lambert8
LAYERED TEXTURE : layeredTexture7
contains : 1 texture(s)
Lightmap texture applied : lambert8SG-polySurface3.jpg

GEOMETRY : polySurfaceShape4
transformNode : polySurface4
SHADING ENGINE : lambert9SG
MATERIAL : lambert9
LAYERED TEXTURE : layeredTexture8
contains : 1 texture(s)
Lightmap texture applied : lambert9SG-polySurface4.jpg

GEOMETRY : polySurfaceShape5
transformNode : polySurface5
SHADING ENGINE : lambert10SG
MATERIAL : lambert10
LAYERED TEXTURE : layeredTexture9
contains : 1 texture(s)
Lightmap texture applied : lambert10SG-polySurface5.jpg

GEOMETRY : polySurfaceShape6
transformNode : polySurface6
SHADING ENGINE : lambert11SG
MATERIAL : lambert11
LAYERED TEXTURE : layeredTexture10
contains : 1 texture(s)
Lightmap texture applied : lambert11SG-polySurface6.jpg

Automatic lightmaps arrangement of all object(s) COMPLETED in 0.12 seconds ![/size]

Thanks for this! Just what Ive needed.

I see now. I did something stupid - I replaced the existing lambert shaders with one, since I was using just one texture to replace all the different ones in your test scene. I thought I could get away with that since that is my normal workflow for doing stuff within Maya, but I understand now that each object will need its own shader and texture assigned.

It works without a hitch! I also tried viewing the different texture files within the UV texture editor window, and it appears the layered shader in the 3d view does not get lost - allowing you to view the color, the lightmap, or both combined. Therefore I would assume Maya 8 fixed whatever problems you have with 6.5 regarding the 3d view.

woooooh, 8 is cool then.

Liquid, what’s your OS ?

Guys, could you give me a favor ? Open your MEL reference, look for fileDialog. What are the options for that command ?

fileDialog is used to open OS’ native file browser, which in v6.5, the support is sooo poor (only 1 option, nothing I can do with it :S), so I have to use fileBrowserDialog which is only for Windows.
VJ, is v8 support for this still that poor ?

I’m still working on an additional GUI to allow me select the location where to copy/move the lightmap textures, and use that location in the layeredTexture’ file reference instead of \lightMap, so I don’t have to :

  1. save as MayaASCII,
  2. rename all \lightMap to my scene’s dir, and
  3. move those textures by myself

Ok, I figured you had to do something like that, since the textures wouldn’t be stored in the right path. Good to know… :slight_smile:

and:

Done.
I’ve also fixed the substring error, the variables must be explicitly typedef’ed.

fileDialog is still very limited.

[UPDATE] :

  1. added 1 more button, only for lightmap textures relocation. Now you’re free to relocate and update file reference in the material, simply using the interface. I’ve splitted the assembling and texture relocation process.
  2. added original location override for assembling process.

I’ve just added another script for easy material & base texture setup. See my 3rd post above, after the visual guide.

Hmmm… I don’t use Maya myself, but this seems to be usefull stuff.

I wonder if the scripts can’t be distributed as files? (Didn’t go too much into details) If so, maybe it can be added to Panda3D on the long run if it proves itself extremely usefull for a wide range of devs…

Regards, Bigfoot29

It’s just text file, like .py