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. :)