Saturday, March 7, 2020

Saturday, April 7, 2018

Wednesday, January 3, 2018

Sunday, August 20, 2017

Maya ShaderFX game hair

Maya 2018 added a game-hair shader option to ShaderFX:
(Audio in Japanese)

Wednesday, April 6, 2016

Sharing nodes in a team

When working in a larger group or company it can be useful to share nodes.
Not just share them, but also be able to share updates to shader networks more easily.

For example technical artists or programmers may want to make a set of shading nodes that artists can use that match with their game engine.

ShaderFX has this build into its group-nodes.

Here is an example of how to create your own custom shader nodes for your company and share them over the network with your team members.

With Maya closed, you can add a user variable to your system variables:



With this set, the next time you start up Maya, it will now pull its custom group nodes from this network folder.

(Note that I believe we added this system environment variable somewhere in 2016, but I cannot remember what extension)

Now lets build a set of custom nodes.
We will use the Custom Code node, since it allows technical artists and programmers to enter their own code more quickly instead of using lots of complicated shader graphs.

Enable "Advanced Mode" in shaderfx.
Add a custom code node.
Customize its code by selecting it and pressing "Edit".
(Here we just input and output a color, but please see the Maya help for more details on the Custom Code node)

Select the node and use "Create Group"

Select the left node of the group
Supply Class, Category and Sub menu name for the group.
Press Group / Save Group

This will save the node into your network path you provided for SHADERFX_CUSTOMGROUPPATH

If all went well, it will now show the new group node in the right-click menu:

Add it to the scene and connect any inputs it needs.
Save your Maya scene and close Maya.

Re-open Maya (could even open it on a team-members machine)
Create the Group node you created.
Open it and make some changes to it.

NOTE: make sure you create a valid node. If you break the node, your original Maya scene will give a shading error.

Save the edited group.
Re-open the Maya scene you saved previously.

Notice that now the scene has been updated to use your new node.
(See the new input we added and the object is now purple)

Wednesday, March 23, 2016

Primitive Variables

Some times you want to use the same shader graph for a bunch of different nodes, but have slightly different parameters for each of the objects used.

A deeper discussion can be found on various Renderman help pages (e.g.

A similar concept exists in Maya DG nodes called TripleSwitch.

In ShaderFX, we can do this using the Primitive Variable node for float values, or the TextureMap node for textures (string attributes).

You start by adding a custom attribute onto your Maya Shape node. Note that it is important the attribute ends up on the Shape and not on the transform node or any other node. So make sure you select the shape node before adding the custom attribute.

The name you use for the custom attribute, is the name we are also going to use on the "Primitive Variable" node inside ShaderFX.

(You have to switch ShaderfX into "Advanced Mode" to find the Primitive Variable node)

Now that we have the custom attribute on the shape node and we have added a shaderFX shader to the object and changed its graph to contain the Primitive Variable node, we can change the value of the custom attribute for each shape.

The quirky part is that this does not update "live" and does not support animation directly via the custom attribute.

So to see the update of the custom attribute into the shader, you use one of two methods:

Open ShaderFX and use Tools / Compute Graph to update the value.
Use MEL command:   shaderfx -sfxnode "ShaderfxShader1" -update;

Knowing this limitation, you can see it is mostly there to allow some custom floats or textures to replace parts of the shader graph per object. It is not meant to completely replace regular Maya attribute that get put into the shader.

However, you can get pretty creative.
For example, lets say you want to animate between 5 different colors between 100 objects.

You can add 5 "color nodes" in the shaderfx graph and lerp (or if-statement switch) between them based on the primitive variable value found on the shape node.

This means you no longer have to worry about animating or updating the shape node attribute constantly. The primitive variable becomes more a "node id" that you can use to take different shading paths in the shader graph.

Tuesday, February 9, 2016

Toon shader animation

Polycount user Hito's great animation using the toon shader from on post below:

Wednesday, October 28, 2015

Saturday, September 5, 2015

Stingray Vegetation Animation node

Vegetation Animation node in Stingray Engine (and Maya Stingray PBS node)

Great tutorial by Chris Perrella on how to use the Vegetation Animation shader node:

Monday, August 3, 2015

Stingray game engine

Transfer ShaderFX (Stingray PBS) graphs from Maya/Max directly to engine:

Wednesday, May 13, 2015

Matcap material tutorial

Want to know more about Matcap materials? check out this video by TGA Digital:

Video for new users

Never used ShaderFX before? Check out this getting started video by CADLearning showing the basic steps:

Thursday, April 9, 2015

Playing with mesh curvature in real-time

Boomer labs was show casing a cool new map plugin for 3dsMax that uses curvature.
Check it out here:

So I got inspired to play around with curvature in a real-time shader.

I knew about ddx and ddy and then found my way to a cool webGL shader by Evan Wallace.

Plugging this into ShaderFX inside 3dsMax and a few tweaks later we get:

I used a custom code node inside ShaderFX, so below is the code I ended up using.

I noticed that the curvature colors flip around on the other side of the world axis (so the back side of the model). I didn't have the time to figure out why that is yet.

float ComputeCurvature( float3 vertex, float3 normal, float strength) 
  float3 n = normalize(normal);

  float3 dx = ddx(n);
  float3 dy = ddy(n);
  float3 xneg = n - dx;
  float3 xpos = n + dx;
  float3 yneg = n - dy;
  float3 ypos = n + dy;
  float depth = length(vertex);
  float curvature = (cross(xneg, xpos).y - cross(yneg, ypos).x) * strength / depth;

  return curvature;

struct CurvatureCalcOutput 
 float curvature;
 float negative;
 float positive;
 float3 color;

CurvatureCalcOutput CurvatureCalcFunc(float3 vertex_pos, float3 normal, float strength) 
 CurvatureCalcOutput OUT; 

 OUT.curvature = ComputeCurvature(vertex_pos, normal, strength);
 OUT.positive = clamp(-OUT.curvature, 0, 1);
 OUT.negative = clamp(OUT.curvature, 0, 1);

 OUT.color = float3(0,1,0);

 OUT.color = lerp( OUT.color, float3(1,0,0), OUT.negative);
 OUT.color = lerp( OUT.color, float3(0,0,1), OUT.positive);

 return OUT; 

Saturday, March 28, 2015

bake/unwrap shader with lighting

Somebody asked me how to unwrap the rendered result of a shaderfx shader to a texture. This may seem like a strange request, because why would you want to bake your lighting into your texture?

 But I have actually had to do this myself once when porting a xbox 360 game over to low-end mobile devices. We were a very small team and could not redo all assets and we really only wanted a single texture per asset.

So, here is how to do the shaderfx part of it. Lets say we want to unwrap a rendered texture for this horse model:

What we need to do is go into Advanced mode, then enter into the "Material grp". Add a new "Vertex Shader UV space" group node. Replace ALL (!) the output of the existing Vertex Shader grp with this new node.

 It will then unwrap the 3d model in your 3d view. From here, you could use other tools to grab the view result and save it as an image.

If you want to save this file with the model unwrapped in the screen, you have to save a NEW grp for the Material grp you just changed. Otherwise, your changes won't stick after re-opening the file.
You can save the grp by renaming its Class property to something unique and then using "Save Grp".

(One tip might be to make the Maya viewport black before saving the image, or if you need to create a mask, make it bright purple so it is easy to select the background color in something like Photoshop)

Wednesday, February 11, 2015

Sunday, December 14, 2014

Thursday, December 4, 2014

Saturday, November 29, 2014

A very lovely 3d character with shaderfx by Thibaut Massart:

Monday, November 10, 2014

Setting up a render target can be tricky and only works when running in DX11 mode, but here is a graph example:

Note that to access some of the options you need to enable Settings / Advanced Mode

Make sure the Texture Component node and Texture Map both use the same UniqueName.
Select RenderTarget as type and set the size and format on the Texture Component node.

On the Pass node, there are a few settings you can define as well, most are optional depending on how you plan to use your targets.

Friday, November 7, 2014

Kostas Gialitakis created a physically based shader for ShaderFX inside Maya/3dsMax.
Get it here:

Monday, September 22, 2014

Friday, February 28, 2014

Wednesday, October 30, 2013


Setting up a for-loop with ShaderFX:

In this video we use an array node to provide 3 float2's for sampling the texture. You can of course also calculate some kind of UV offset based on the 'operator i'.

To use the 'operator i' inside your for-loop 'calculation', you select the 'String' node you used for the 'Operator'.

Set the 'Value Type' to 'Shader / Integer'.
This will change the 'As Value' output of the 'String' node to an integer you can now use in the rest of your node network inside the loop.

Tuesday, October 15, 2013


Paul Tosca's beautiful Nyra model in Maya's DX11 viewport:

Tuesday, October 8, 2013

Working with UV sets

Working with UV sets in Maya and ShaderFX can be a bit confusing.
Here is how it works.

On the Texture Map node, or UV set node, there are two options:
1. UV set index
2. UV Set Name

You use one or the other.
If you don't rename your UV sets in Maya, the default names of your UV sets will be:

0: map1
1: uvSet
2: uvSet1
3: uvSet2 ... etc

When you choose to use the UV set index on the ShaderFX nodes, it will attempt to find a UV set by those names. So when you specify index 2, it will try to find a UV set with the name: uvSet1.

Not very obvious, but the default naming of UV sets in Maya is weird (why is 0 called "map1" and then the rest called "uvSet..." is not clear to me).

If, however, you give your UV sets a custom name, then you must specify its exact name on the Texture Map or UV Set node in ShaderFX.

For example, had we called our second UV set "LightMapUVs" then we must enter that exact name in the "UV Set Name" on the ShaderFX node.

Friday, October 4, 2013


Using Transparency from textures or float values in ShaderFX is pretty easy, but you need to know to enable one or two settings on the Base Material node for it to work.

You connect your transparency value to the opacity socket on the Surface Shader (top).
Then enable the Opacity checkbox on the Base Material node.

UPDATE: in new versions of Maya/ShaderFX you no longer have to enable the Opacity checkbox. Simply plugging something into the opacity input will make the material transparent

You likely also want to disable the "Depth Write" checkbox so that transparent object do not block the rendering of objects behind them.

By default objects render double sided in the Maya view, if you do not want this, disable the "Double Sided" checkbox on the Shape node of the object.

You should get reasonable results, but keep in mind that Maya's viewport is not a game engine and so sometimes sorting is not perfect. There are some improvements you can get by switching to "Depth Peeling" transparency algorithm. This can be found in the Viewport 2.0 settings dialog.

Unfortunately in Maya LT this crashes, but I believe this will be fixed in SP 1.

Even with Depth Peeling things are not always sorting great. Hopefully we can improve this in the future.

Tuesday, October 1, 2013

V-Rex Maya 2014, Viewport 2.0 - DX11

This was too impressive not to post.
YOSUKE ISHIKAWA does such amazing real-time work:

Saturday, September 28, 2013

Empty group sockets

Sometimes when working with groups you end up with a few empty sockets inside the group and there is no button to remove these empty sockets (we may eventually add one).

But there is a way to get rid of them.

Empty sockets are removed during saving/Loading (saving and then loading the group or the scene).
So when you reload the group/scene the empty sockets will be gone, if the following conditions are met:

1. The label of the socket is empty (so it displays "any" as its label in the view)
2. There are no used sockets below it.
3. It is not the only empty socket (we always keep one empty socket)

Number 1 and 2 are are probably not that obvious, but the reason for it was if the user is in the middle of creating groups and saves a scene and goes home for the day, you don't want to loose your work and have to redo labeling or organizing your sockets.

In order to ensure a socket gets removed, you have to use the "Move Socket Up" button on any used sockets below it. (Which can also be a bit tedious to use at times, but it is what we have right now)

Here is the corrected group for which the unused sockets will get removed after save/load.
(Except for 1 'any' socket since we always keep one for users to add new connections)

Thursday, September 19, 2013

Sampling one texture with different settings

Some times you may want to sample a single texture with different settings, such as different UVs.

You can of course place down multiple "Texture Map" nodes and point them all to the same texture.
Then connect different UVs into each.

This works ok, but becomes a problem when you want to expose the texture path to the Attribute Editor as a parameter for artists to set when the node graph is closed. You really want  the artist to only have to supply the path to the texture once. 

When using Texture Map nodes, each would need to be visible to the AE in order for the path to be set. It would be strange for the artist to have to set the same texture in the shader multiple times. We can resolve this by constructing the sampling with your own set of nodes instead of using the Texture Map node.

To see these nodes, you should switch to "Advanced Mode" in the right-click menu.

You can look inside the Texture Map node for reference.

Here is an image with some explanation of how you can set this up:

The above example assumes you are using a regular 2D texture.
If you want to use a Cube texture, then you must also add a "Texture Type" node, set it to Cube and input it into each of the four nodes in the picture.

Tuesday, September 10, 2013

Working with Lights

A new video describing how you can work with lights inside Maya LT and ShaderFX

Friday, September 6, 2013

Valve DOTA2 hero in Maya LT using ShaderFX

I recreated Valve's DOTA2 hero shader using Maya LT and ShaderFX.
Download the DOTA2 ShaderFX graph here (v1.1)

** NOTE: we ship a more up to date version of this node with Maya that works with the new Maya Core Profile. I recommend you use it instead of the older version linked above **

I tried to stay true to the original shader code as much as possible.
To do that, I used a Custom Code node inside ShaderFX to paste Valve's original CGFX code into.

Then I decided to remove any CGFX specific semantics from the Shader.
By doing that, you can freely switch between OpenGL and DirectX11 with the same Maya LT scene and ShaderFX graph.

The only function I had to replace was a few calls to Tex2D().
I made those Tex2D calls "inputs" into the Custom Code node function and used the ShaderFX "Texture Map" node instead, which will automatically switch correctly between OpenGL and DX11.

It was about a day work to switch the code from the CGFX file over to a ShaderFX graph.
I had never seen the shader code before, so it took some time figuring out how it worked, but of course I had the benefit of knowing ShaderFX very well.

Another change I made was to add support for real-time shadows and point/spot/direction lights.
This was very easy, because I could re-use the "Light Contribution" group node in ShaderFX, which does all the magic for us.

I maintained the 1-light support for the shader.
Adding more lights would be easy, just bump up the "number of lights" property in the shader.
But the way I have structure the shader code in the custom code node, adding extra lights would mean we are not a very efficient shader anymore because every texture sample and calculation would be re-done inside the light loop.

For example, sampling the normal map texture would happen for every light!
Pretty waste full, but it can be fixed fairly easily if somebody wants to add extra lights.

It can be resolved by splitting the light dependent calculations and the rest of the calculations from the Custom Code node into two Custom Code nodes. Then use the "Inside Loop" and "After Loop" inputs on the "Socket Combiner" node. But my goal was to just reproduce as close as possible the original shader, so I did not do that work.

I love the graphics of Valve's DOTA2, it is a fantastic game. And seeing the models like this in Maya LT is quite rewarding. :)

Friday, August 30, 2013

ShaderFX custom code example

Here is an example of using the "Custom Code" node provided in ShaderFX to create a snow-layer effect.

We measure the angle between the vertex normal and the world UP (or "snow direction" if you wish) and blend in the white color on top of the rock texture.

We have a second custom code node that modifies the vertex position to give the snow some thickness.
Download Custom Code Snow ShaderFX graph

Example shaders in Maya LT

ShaderFX is a real-time shader editor build into Maya LT.
Below are some examples.

Matcap shader:
Download Matcap ShaderFX graph

Animated shader:
Download Animated Fire ShaderFX graph

Anisotropic and latlong reflections:
Download Anisotropic ShaderFX graph

ShaderFX is very customizable.
Most nodes are what I call "Group Nodes". Similar to e.g. compound nodes in XSI. For example you can go inside the Surface shader itself and poke around:

Blurring reflection maps based on procedural checker pattern:
Download Blurry Reflections ShaderFX graph

Blending normal maps with various options to blend:
Download Blending Normal Maps ShaderFX graph

Animated Surface Mask (Opacity Mask):
Download Surface Mask ShaderFX graph

An example of DirectX 11 tessellation and displacement:
Download Tessellation and Displacement ShaderFX graph

Mixing with vertex colors:
Download Vertex Colors ShaderFX graph

Wrinkle Map (sorry don't have a great face model/rig laying around):

The attribute on the locator drives the value in the shader.
In ShaderFX "Values nodes" (such as floats, colors, textures) have an option called "Input from Maya". When you enable this option, the value is exposed as a regular Maya Attribute in the dependency graph and can be connected to your rig:
Download Wrinkle Map ShaderFX graph

Translucency (Thickness map controls the density, in this case, a vein map):
Download Translucency ShaderFX graph