|
Introduction
Real-time
shaders are used more and more by game developers to provide a greater
sense of realism. They allow the creation of complex lighting and
advanced visual effects. DCC Tools such as 3ds Max, Maya and XSI
provide a preview of real-time shaders in their viewport. And softwares
such as RT/Shader Ginza, RenderMonkey and FX Composer are tools for
creating real-time shaders that could be imported and used within DCC
tools.
The
goal of this article is to show how to use DirectX Shaders in 3ds Max
for video game development. It covers all the production process: from
implementation and integration to export. This article could be for
anybody working with 3ds Max, from technical directors to tools
developers. It's recommended that the reader have a basic knowledge of
developing tools for 3ds Max – MAXScript, Max SDK and DirectX Shaders -
in order to get the most out of this.
DirectX shaders in 3ds Max
DirectX shaders definition
DirectX
shaders are shaders in DirectX Effect format. 3ds Max allows developers
to create shaders effects and scene effects. There are three scene
effects types: pre effects, post effects and environment effects. This
article will focus especially on shaders effects. For example, with a
DirectX Shader you can view in realtime, in the viewport, a shader used
in your game, for example a normal mapping shader.
Advantages of DirectX shaders
Using
a DirectX shader material, artists can view the same result in 3ds Max
viewport as in the game engine. You can integrate DirectX shaders in
your production workflow even if your game engine is not using standard
DirectX effects. Indeed, it's possible to export the effects to your
specific shader effect format. Also, if you are developing a game not
using shaders, you can use DirectX shaders in order to display in Max
viewport a specific lighting effects used in the game for example.
DirectX
Shaders can help a lot of artists. They provide immediate a feedback.
So, real-time DirectX shaders save a lot of time and the gain of
productivity in production can be significant.
Drawbacks of DirectX shaders
DirectX
shaders are slow in 3ds Max, especially when they are applied on a lot
of objects and used in a large scene. Also, they are bugged. You can
sometimes get strange bugs, for example, a texture color not the same
in the viewport and in the source file. I hope these bugs will be
solved in the future and it's possible to configure 3ds Max in order to
speed up the display of DirectX shaders in the viewport. Now, let's
take a look at the development of DirectX shaders effects for 3ds Max.
FX Effect format for 3ds Max
Max
ships with two Effect parser; default Max parser and DXSAS 0.8. If you
are not satisfied with these parsers, you can write your own parser and
extend the effect support.
When developing a DirectX Effect Shader, to choose the correct Effect parser to load you can use this code:
string ParamID = "0x0"; // Load default Max parser
or
string ParamID = "0x0001"; // Load DXSAS parser
This
line is used by 3ds max to load the correct parser. This line has to be
mentioned at the beginning of the effect file, as the first instruction.
Also, macros are defined when the effect is compiled. Here is the list:
_3DSMAX_, 3DSMAX, _MAX_ and MAX
These macros are very handy when sharing effects between the game engine, 3ds Max and other DCC tools.
In
order to view the shader parameter in the DirectX 9 Shader material UI,
you have to use some semantic annotations. For example, in order to
create a spinner in the UI you can try this code:
float OffsetScale <
string UIType = "FloatSpinner";
string UIName = "Offset Scale";
float UIMin = -1.0f;
float UIMax = 1.0f;
> = {0.1f};
In
this example, the annotations are “UIType”, “UIName”, “UIMin”, “UIMax”.
They tell 3ds Max to create a spinner for a float value with a caption
“Offset Scale” and a value limited to the range -1.0 - 1.0.
Another example showing the use of a semantic:
float4 PS(VS_OUT In) : COLOR0
{
// Pixel Shader code here
}
In
the previous example, the semantic is “COLOR0”, it describes the value
returned by the pixel shader. Indeed, the pixel shader returns a float4
read as a color. Now, let's take a look at the integration of DirectX shaders in 3ds Max.
How to integrate DirectX shaders in 3ds Max?
Default DirectX 9 Shader material
DirectX
9 Shader material enables the artists to shade objects in 3ds Max
viewports loading DirectX 9 shaders coded in DirectX effect format. The
advantage of this material is that it can be easily exported with 3ds
Max SDK and 3DXI. But
this material is not very handy for the artists because they have to
browse and load an effect file each time they create a new DirectX 9
Shader. Also, the auto UI created by the parser is not perfect and
ergonomic.
Scripted materials
DirectX
9 Shader material can be extended via MAXScript. With scripted
materials, the UI generated is customized, be sure to validate data and
check for errors. They are easy to manage and update. An extended
DirectX 9 Shader scripted material encapsulates the effect parameters.
So, when developing this kind of script, remember to create a parameter
in the paramblock for each effect parameter.
Example of a basic scripted plug-in which extends DirectX 9 Shader material:
FX_DEFAULTPATH = “$maps\\fx\\"
FX_TEXTURE = "Texture.fx"
plugin material MyExtendFX
name:"MyExtendFX"
classID:#( 645812,447325 )
extends:DirectX_9_Shader replaceUI:true version:1
(
parameters MainParams rollout:RollParams
(
DiffuseMap type:#bitmap
)
rollout RollParams "Material Parameters"
(
button btnDiffuseMap "None"
)
on create do
(
-- Setup initial material
delegate.effectfile = DEFAULTPATHFX + FX_TEXTURE
)
)
When extending the DirectX 9 Shader, you can access, get and set the properties of this material using the “delegate” variable.
The delegate variable holds:
- The properties of the DirectX 9 Shader
- The parameters defined in the effect
We can write a parameter in the effect like that:
bool g_DiffuseMapEnable <
string UIName = "Diffuse Map Enable";
> = false;
And in the material parameter block, use this parameter as follows:
-- Set DiffuseMap activation value
on DiffuseMapEnable set val do
delegate.g_DiffuseMapEnable = val
In
the material parameter block, we can set the color, boolean, integer
etc. values but not the bitmaps. We can only set the bitmaps values in
the rollout part.
To set the bitmaps you can try:
Effect code:
texture g_ Diffuse Texture <
string UIName = "Diffuse Map";
int Texcoord = 0;
int MapChannel = 1;
>;
Scripted material code (in the rollout bloc):
-- When pressing btn DiffuseMap button
on btn DiffuseMap pressed do
(
bmp = selectbitmap caption: "Diffuse Map"
if(bmp != undefined) do
(
delegate.g_ Diffuse Texture = bmp -- Set effect bitmap
btnDiffuseMap.text = bmp.filename -- Change caption text
DiffuseMap = bmp -- Set Paramblock value
)
)
Write your own material with the SDK
Using
3ds Max SDK, you can develop your own DirectX hardware shader material
with the SDK. This solution isn't very easy but it is feasible. Using
some classes from the SDK and DirectX SDK, it's possible to create such
a plug-in.
In
fact, there's two ways to create a DirectX shaders with the SDK: a
Material or a DirectX Manager plugin. In my opinion, I think the
Material plug-in is better because it's a true material, contrary to a
DirectX Manager plug-in which is part of the Standard material, and the
is easier for a graphic artist to use in Max. Now, let see how to
export DirectX effect shaders.
Exporting DirectX shaders
With the SDK
3ds
Max SDK lets us access DirectX 9 Shader materials and scripted
materials. We can get bitmap, light and effect properties. To get all
DirectX 9 Shader and scripted materials extending DirectX 9 Shader
material that are in the scene, you can use this code:
// Get scene materials
Interface* ip = GetCOREInterface();
MtlBaseLib* lib = ip->GetSceneMtls();
if (!lib)
return 0;
// Loop over the scene materials
const int NumMtls = lib->Count();
for( int i = 0; i < NumMtls; i++ ) {
// Get current material
MtlBase* mtl = static_cast<MtlBase*>( (*lib)[ i ] );
if (!mtl)
continue;
// DxMaterial or extend ?
IDxMaterial* dxMtl =
(IDxMaterial*)mtl->GetInterface(IDXMATERIAL_INTERFACE);
if( dxMtl)
ProcessDxMaterial(dxMtl);
}
When processing the DxMaterial, to access the material properties you can use:
// Get informations from the DirectX Shader material
// Get number of bitmaps used
unsigned int NumberOfBmps = dxMtl -> GetNumberOfEffectBitmaps ();
This
code works with a DirectX 9 Shader material or an extend of this
material. Then, you can get the effect parameters using it parameter
block at index 0:
// GetParamBlock() work only on the material pointer
IParamBlock2* pblock = mtl ->GetParamBlock(0);
This
time, the previous code works only with DirectX 9 Shader. Running this
code on an extend DirectX 9 Shader, the value returned is the scripted
material parameter block and not the effect parameters.
With 3DXI
3DXI
(known as IGame) is a high level API for 3ds Max SDK. With this API you
can easily and quickly extract data from Max. 3DXI is very interesting
in order to parse an effect file used in a DirectX Shader. In 3DXI, in
order to loop over the scene materials you have to use the root
materials. To recognize a DirectX 9 Shader material, the 3DXI material
class provides the function GetIGameFX() returning the 3DXI effect
representation of this material.
To get all DirectX 9 Shader materials that are in the scene, you can use this code:
// Init IGame
IGameScene* pIgame = GetIGameInterface();
pIgame->InitialiseIGame(false);
pIgame->SetStaticFrame(0);
unsigned int i = 0;
// Loop over scene materials
for(i = 0; i < pIgame->GetRootMaterialCount(); i++)
{
// Get this root material
IGameMaterial* mtl = pIgame->GetRootMaterial(i);
if(!mtl)
return;
// DxMaterial ?
IGameFX* fx = mtl->GetIGameFX();
if(fx)
ProcessEffect(fx)
}
To loop over the effect technique and passes you can try this code:
unsigned int i = 0, j = 0;
// Loop over the technique of the effect
for(i = 0; i < fx->GetNumberOfTechniques(); i++)
{
// Get current technique
IGameFXTechnique* tech = fx->GetIGameFXTechnique(i);
ProcessFXTechnique(tech);
// Loop over the passes of the current technique
for(j = 0 ; j < tech->GetNumberOfPasses(); j++)
{
// Get current pass
IGameFXPass* pass = tech-> GetIGameFXPass(j);
ProcessFXPass(pass);
}
}
3DXI
is an interesting library for import/export in constant development.
DirectX shaders support is moving along more and more.
With MAXScript
If
you only want to export some basic effect properties and informations,
you can use MAXScript. In script, we can access bitmaps properties and
some common informations. To access DirectX 9 Shader material
properties you can use the following MAXScript code:
-- Loop over scene materials
for mtl in sceneMaterials do
(
-- DxMaterial?
if(Classof mtl == DirectX_9_Shader) do
(
-- Get current technique
CurrentTechnique = mtl.technique
EffectFile = mtl.effectfile
-- Get used bitmap(s) in the effect
for i = 1 to mtl.numberofbitmaps() do
(
bmp = mtl.geteffectbitmap i
BmpFileName = bmp.filename
)
)
)
This small script shows how to access current effect filename, the index of the technique used and the bitmaps' filenames.
Conclusion
In
conclusion, DirectX shaders can be integrated easily in 3ds Max. The
development of a DirectX shaders effect for Max isn't difficult. We can
integrate Direct shaders as an entire material with scripted materials
or with the SDK and export them using the SDK and 3DXI DirectX shaders
support in 3ds Max is extended more and more. So, if you are not yet
using DirectX shaders in Max, I think it's time to think about it.
Resources
Sparks website: http://sparks.discreet.com/
Some interesting DirectX shaders effects from Ben Cloward website: http://www.monitorstudios.com/bcloward/resources.html
Some DirectX shaders effects: http://ypuechweb.free.fr/download.html
Very good forum about tools development: http://dl3d.free.fr/phpBB2/index.php
Forum about shader development: http://ypuechweb.free.fr/phpBB2/index.php
_____________________________________________________
|