Tuesday, December 18, 2007

How to design a Material System

Here is my take on how a good meta-material / material systems should be written and how the art workflow works:
I just came across the latest screenshots of Mass Effect that will ship soon:

http://masseffect.bioware.com/gallery/

The thing I found remarkable is the material / meta-material system. Skin looks like skin and then cloth has a completely different look and leather looks really like leather. Combined with great normal maps Mass Effects looks like the game with the best looking characters up-to-date.

The best way to a material / meta-material system is very close to what was done in Table-Tennis. I described the system in ShaderX4 some time before I joined Rockstar.
The idea is to dedicate to each material a specific *.fx file and also name the file accordingly. So you end up with eye.fx, skin.fx, metal.fx, brushed_metal.fx, leather.fx, water.fx etc. ... so you will want to end up with probably 15 - 20 *.fx files (they would holds different techniques for shadowed / unshadowed etc.). This low number of files makes shader switching a non-issue and also allows to sort objects according to their shaders, if this is a bottleneck.
The *.fx files can be called meta-material (this naming convention was inspired by a similar system that was used in the Medal of Honor Games, as long as they were based on the Quake 3 engine).
The material files hold the data while each of the meta-material files only hold code. So we differ between code (*.fx file) and data (*.mtl or something different). One of the things that can be done to reduce the data updates is to shadow the constant data and only update the data that changes. In pseudo-code this would be:
- draw eyes from first character in the game
- apply the eye.fx file
- load the data for this file from the material file
- draw the eyes from the second character in the game
- eye.fx is still applied, so we do not have to do it again ... shader code just stays in the Graphics card and does not need to be reloaded
- load the data file for this pair of eyes and load only data into the graphics card that has changed by comparing the shadowed copy of the data from the previous draw call with the one that needs to be loaded now

- move on like this for all eyes

- then move on with hair ...

The underlying idea of the data shadowing and the sorting by shaders is, to reduce the amount of changes that need to be done if you want to apply very detailed and very different surfaces to a character. In other words if you setup a game with such a meta-material / material system there is a high chance that you can find a performance difference between sorting for shaders or sorting for any other criteria.

For me the key elements of having a truly next-gen looking shader architecture for a next-gen game are:
- having a low number of *.fx files to reduce shader switching + good sorting of objects to reduce shader switching
- letting the artist apply those *.fx files and change the settings, switching on and off features etc.
- tailoring the low number of shaders very much to specific materials, so that they look very good (the opposite approach was taken in DOOM III were everything consists of metal and plastic and therefore the same lighting/shader model is applied to everything)
The low number of *.fx files and the intelligence we put into the creation of the effect files should give us a well performing and good looking game and we are able to control this process and predict performance.

6 comments:

Tom said...

What sort of infomation do you put in your mtl files? What about RenderState( alpha, zbuffer, colorwrite, etc)? Do those go in the .mtl or .fx file?
-teaspoon

Wolfgang Engel said...

This depends on your engine. Putting render states into your material file would require that you shadow those in high level code. You would only put render states into your material file that really influence your material. All the other render states should stay at the engine level. Otherwise you will create an unnecessary administrative overhead.

Maciej Sawitus said...

I agree with your points about material system having to be as optimized as possible, but having fixed set of .fx files (uber-shader style) is in some way limiting. I'm thinking specifically about shader graphs concept (for example, used by Unreal Engine 3). I found it generally useful feature to be able to create arbitrary effects by visually connecting "shader/material blocks" into shader graph. The issue with that approach is - on the other hand - that it may lead to uber-shader graphs created by artists which don't understand many things. It's usually ok to have a single "technical artist" on a project who understands things a bit better though. As it often happens, no solution seems to be ideal...

Wolfgang Engel said...

Maciej,
how do you pack different lighting models in this system. You want for the material metal for example a Ashikhmin-Shirly model and for cloth maybe a Oren-Nayar ... how to you show the difference with your system and even more how do you tell artists which lighting model fits to which material?
All those systems assume that you use Blinn-Phong that is not really cool anymore ... so you limit the whole game to Blinn-Phong this way?

Maciej Sawitus said...

Of course limiting the game to just Blinn-Phong would be bad. But there is few ways to design shader graph based material system that allows for various lighting models. One of my design proposals is to - for each "standard" surface lighting property (ambient, diffuse, specular) - expose available lighting models to the artist. From material editor UI point of view it's just a drop-down list. For example, for diffuse you could choose whether it's lambert, oren-nayar, ashikhmin or none (no diffuse contribution). For specular you could choose between phong, ashikhmin, cook-torreance or none. Depending on which lighting models were chosen for each surface lighting component, an artist has to supply different "inputs". An example of "input" is surface albedo color needed for lambert diffuse lighting or specular power for phong lighting. An input can be as simple as a constant value but can also be more complex shader graph. Also, to answer your question as to how to tell the artist which lighting model fits which material - I honestly don't have any other idea than to teach the artists a bit about lighting models. Of course math theory is not necessary, just practical side like what kind of visual properties each lighting model has.

alariq said...

farther more, you can hide names which can sound confusing for the artists(Ashikhmin-Shirly,Oren-Nayar, etc.) and substitute them by Metal, Plastic, Cloth etc..