LuxMaya - LuxRender Wiki
Luxrender GPL Physically Based Renderer


Personal tools

From LuxRender Wiki

Jump to: navigation, search


Adding a new shader

  • Make a new suitably-named file in luxPlugin/Lux/LuxNodes/ShaderNodes

We'll use the mirror shader as a template as it has only 1 attribute.

  • Copy the contents of into your new shader file.
  • Rename the class and comments as appropriate.
  • For each attribute/parameter that the shader has, create an OpenMaya.MObject() for it in __init__ (just like
  • Set self.luxType to the Lux material name.
  • For each attribute/parameter that you want in the shader, add a line in shaderInitializer(). The shaders have some helper functions for various data types, inherited from LuxNode via ShaderNode:
    • makeColor( string longName, string shortName, float defaultR, float defaultG, float defaultB)
    • makeFloat( string longName, string shortName, float default, bool input)
    • makeInteger( string longName, string shortName, int default, bool input)
    • makeBoolean( string longName, string shortName, bool default, bool input)
    • Some other data types are possible, use the existing shaders as examples.
--> BEWARE that color attributes automatically create six sub-attributes with names [longName]R, [longName]G, [longName]B, [shortName]r, [shortName]g, [shortName]b. THESE MUST NOT CONFLICT EITHER <--
The same is true for Point attributes, but with X, Y, Z, x, y, z instead of RGB, rgb.

Now you need to set up the Maya attribute->Lux parameter translation table. This is the last part of the shader's __init__()

  • The keys of self.attributes are the Lux names for the attributes, and the value is a Shader*Attribute object initialised with the name of the Maya attribute (ie, the longName you gave in shaderInitializer() )
  • Be sure to add imports for the various Shader*Attribute classes you need, there are 5:
    • ShaderColorAttribute
    • ShaderFloatAttribute
    • ShaderEnumAttribute
    • ShaderStringAttribute
    • ShaderBoolAttribute
      • Some of these can take optional args in the constructor, refer to for details.

Next, we register this shader fragment in the luxshader Node (

  • Add an import at the file top.
  • Add an object in __init__
  • Add a case to compute(), to get a suitable color from your new shader. Refer to the MObject() object in the new shader's __init__, and it needs to be a makeColor()/ShaderColorAttribute().
  • Add an object to nodeInitializer().
  • Add all the new shader's MObject()'s to luxshader using luxshader.addAttribute() (~ lines 226 - 308).
  • Add the new shader's color attribute as an AttributeAffects() (~ lines 316 - 328).
  • Add the new shader's name to the iMaterialType Enum (~ line 168)

You new shader will now work within Maya although it won't have it's own section in the Attribute Editor yet, or export.

Edit src/Mel/AEluxshaderTemplate.mel:

  • Use existing shaders as examples. You basically just create a section for the material and add it's attributes using longName.
  • The 2nd half of the file does the control en/disable on material switch, you need to know the shader's Enum value for this.

Now we need to make the exporter aware of the new material. Edit luxPlugin/Lux/LuxExportModules/

  • Add an import at the file top.
  • Add a case to the luxshader factory ~ lines 123 - 148. Again, use the shader's Enum value from

Adding a new sampler/integrator/filter/etc

The easy bits are adding the settings to the lux_settings node and modifying the exporter:

  • Open up luxPlugin/Lux/LuxCommands/
  • Change (+=1) the version const on line 26. This will ensure old scenes get the new settings.
  • Add the name of the new integrator to the END of the Enum options string (line 185).
    • Options are separated by colon :
    • dv = the default value, 0 based index.
  • Add any settings that the integrator takes, that aren't already present. Eg, most integrators use maxdepth and there is only one maxdepth setting that is shared by all of them.
  • There are various data types that you can use:
    • addLong()
    • addShort()
    • addFloat()
    • addEnum()
    • addBool()
    • addString()
  • Use a unique name for the longName (ln)

Open up luxPlugin/Lux/LuxExportModules/ This file reads the values you just created and put them in the scene file.

  • find def doSurfaceIntegrator().
  • You should be able to follow by example, this file is quite easy to understand.

The hard part: Updating the GUI. Open up luxPlugin/LuxCommands/

  • The integrator settings are in the renderFrame tab group. find def renderFrame(). (~ line 786)
  • Add the new integrator name to the mOptionmenu ~ lines 876 - 881. These need to be in the same order as the lux_settings Enum.
  • Add a tab for the integrator controls, ~ line 893. The key in this dict is a function in this class. If at all possible you should copy one of the existing functions and modify as necessary.
  • In this example I will copy self.renderSurfaceIntegratorPath(). find def self.renderSurfaceIntegratorPath() ~ line 1352

This method defines a new frame for controls, and one or more rows in that frame. Each row has 2 columns, on the left for the control name, on the right for the control itself.

  • We start a new row with self.newRow().
  • pass it the first arg returned (of 2) from self.newFrame().
  • The first object in the row is the text label.
  • pass it a string and the value returned by newRow()
  • The second object in the input control. Use one appropriate for the data type:
    • cmds.intField( parent, int min, int max, int default )
    • self.addTextField( parent )
    • self.addCheckBox( parent, string label, bool default )
    • self.addFloatField( parent, float min, float max, float value )

Lastly we connect the input control to the lux_setting that you first created:

  • call cmds.connectControl( control, string lux_setting )


    • control is the value returned by the control creator function (intField/addTextfield etc)
    • lux_setting is the full name of the setting you created, complete with the "lux_settings." node prefix.
  • This new method should return the 2nd arg (of 2) returned by self.newFrame()


luxbatch's doIt() method is what is called directly when pressing the "Big Export Button". Basically luxbatch has 2 modes of operation.

Export all files, then run a batch file

  • check that lux_settings exists so that we can write the render settings
  • check whether we are exporting an animation or not, and setting the appropriate frame range to export
  • export each frame in sequence to known file names, and collecting a list of those names
  • dump those file names into a batch file/bash script along with lux[render|console] and various other process options/commands
  • execute the batch/bash script

This method is disadvantaged in that all frames are written to disk first, which can potentially use a large amount of space, however the render process will run entirely in the background so that you can continue to use Maya (or even quit Maya completely).

Export and render sequentially

  • check that lux_settings exists so that we can write the render settings
  • check whether we are exporting an animation or not, and setting the appropriate frame range to export
  • export a frame to a temp folder, erasing any previous data that was there
  • render the frame
  • loop until all frames have been rendered

This method has a disadvantage in that the Maya UI will be frozen while lux renders. It is designed to be used "headless" in console mode, and the aim is to not consume vast amounts of disk space. Only 1 exported frame exists on disk at any one time.