HogBox TitleBar

Creating Custom materials


Advanced materials allow users to create their own custom material types based off of GLSL shaders. The user has to create a GLSL vertex and fragment shader file, then create a HFX file telling EdDidIt how to use the shaders. Examples of these can be found in the 'advanced_,materials' included in the EdDidIt installs.

The content of a HFX file are contaied within <SHADER> Tags. This lets EdDidIt know that the file is indeed a HFX file.

<SHADER>
</SHADER>

Within the shader tags you need to set how many texture channels are used, the name of the vertex and fragment shaders, then list any uniforms or samplers used. An example of a basic HFX file would look like the following

<SHADER>
    
#the number of texture channels (including cubemaps)
    
<MAX_2DCHANNELS> 2
    
#the location of the GLSL vertex program
     <VERTEX_PROGRAM> shaders/normalMapping.vert
    
#the location of the GLSL fragment shader
     <FRAGMENT_PROGRAM> shaders/normalMapping.frag
    
#sampler2D in the Shader named 'normalMap' bind it to channel 0
     <TEX_2D> 0 normalMap
    
#sampler2D in the Shader named 'diffuseMap' bind it to channel 1
    
<TEX_2D> 1 diffuseMap
    
#Uniform named 'lightFallOff' that is of type float
    
<UNIFORM> lightFallOff <FLOAT> 0.0 <MIN> 0.0 <MAX> 1.0
</SHADER>


This may seem a little confusing so lets look at each tag individually.


<MAX_2DCHANNELS> INT

Max 2d channel isn't named very well, as it is actually total number of texture channels needed, including cube maps. So for example a simple shader using only a diffuse texture would have


<MAX_2DCHANNELS> 1

but if the shader had a diffuse texture and a cubemap you would set this to 2. This tag should only appear once in any HFX file.


<VERTEX_PROGRAM> STRING

This lets you specify the path of you vertex program. The path is reative to the location of the HFX file.


<FRAGMENT_PROGRAM> STRING

This lets you specify the path of you fragment program.The path is reative to the location of the HFX file.


<TEX_2D> INT STRING

Tex_2D allows you to specify the name and channel of a sampler2D used in your shader. The INT is the channel and should be from 0 to MAX_2DCHANNELS. The STRING is the name of the sampler in the shader. So for example, if we have a shader containing the sampler declaration.

uniform sampler2D normalMap;

We need to add

<TEX_2D> 0 normalMap

To our HFX file, in order for EdDidIt to know about the sampler.


<TEX_CUBE> INT STRING

You can also use cube maps in you materials. They work almost the same as TEX_2D but you must use this tag <TEX_CUBE> instead. So for example if you shader contained something like the following.

uniform samplerCube SpecularEnvMap;

You would need to add the following to the HFX file.

<TEX_CUBE> 1 SpecularEnvMap



<UNIFORM> STRING UNITYPE DEFAULTVAL <MIN> FLOAT <MAX> FLOAT

The uniform tag is very flexible and allows you to specify most uniform types for editing. Any uniforms Specified will have GUI elements created to allow the user to change the value of that unifom.

It starts with the <UNIFORM> tag followed by the name of the uniform. After this come the UNITYPE. This is in fact another tag specifying the variable type. Accepted tags are.

<INT> #integer value
<FLOAT> #floating point value
<VEC2> #2d vector
<VEC3> #3d vector
<VEC4> #4d vector

Once a UNTYPE is specified a default value is set according to the value type. This is then follow by a minimum and maximum values. The min and max are mainly to aid the creation of the GUI.

So if you had a uniform such as the following in your shader

uniform float SpecularPercent;

You would need to add the following to your HFX file in order to edit it.

<UNIFORM> SpecularPercent <FLOAT> 1.0 <MIN> 0.0 <MAX> 1.0

Another example

uniform vec3 DiffuseColor;
<UNIFORM> DiffuseColor <VEC3> 0.5 0.5 0.5 <MIN> 0 <MAX> 1

Notice that with a VEC3 uniform the default value has become three values 0.5 0.5 0.5. This rule follows across all types. So a vec2 requires two values and an INT only accepts and integer.

The min and max values are always single numbers, these control the min and max values of the slider bars etc created to edit the uniform.


An Example

Now we have seen what the tags do lets see a full example. Below is the source for a simple normal mapping shader. We will then see the HFX file required to use these shaders.

--Vertex shader--

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoord;
attribute vec3 tangent;

void main(void)
{
     gl_Position = ftransform();
     texCoord = gl_MultiTexCoord0.xy;

     vec3 n = normalize(gl_NormalMatrix * gl_Normal);
     vec3 t = normalize(gl_NormalMatrix * tangent);
     vec3 b = cross(n, t);

     vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
     vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex;

     lightVec.x = dot(tmpVec, t);
     lightVec.y = dot(tmpVec, b);
     lightVec.z = dot(tmpVec, n);

     tmpVec = -vVertex;
     eyeVec.x = dot(tmpVec, t);
     eyeVec.y = dot(tmpVec, b);
     eyeVec.z = dot(tmpVec, n);
}

--Frag shader--

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoord;

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

uniform float lightFallOff;

void main (void)
{
     float distSqr = dot(lightVec, lightVec);
     float att = clamp(1.0 - lightFallOff * sqrt(distSqr), 0.0, 1.0);
     vec3 lVec = lightVec * inversesqrt(distSqr);

     vec3 vVec = normalize(eyeVec);

     vec4 base = texture2D(diffuseMap, texCoord.xy);

     vec3 bump = normalize( texture2D(normalMap, texCoord.xy).xyz * 2.0 - 1.0);

     vec4 vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;

     float diffuse = max( dot(lVec, bump), 0.0 );

     vec4 vDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * diffuse;

     float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), gl_FrontMaterial.shininess );

     vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular * specular;

     vec3 color = vec3(( vAmbient*base +
          vDiffuse*base +
          vSpecular) * att);
     gl_FragColor = vec4(color,gl_FrontMaterial.ambient.a);
}

In the above shader we have a vertex shader containing no editable uniforms and a fragment shader containing two 2D textures and a single float based uniform. The HFX file to use these two shaders would look like the below.

--HFX File--

<SHADER>
     <MAX_2DCHANNELS> 2
     <VERTEX_PROGRAM> shaders/normalMapping.vert
     <FRAGMENT_PROGRAM> shaders/normalMapping.frag
     <TEX_2D> 0 normalMap
     <TEX_2D> 1 diffuseMap
     <UNIFORM> lightFallOff <FLOAT> 0.0 <MIN> 0.0 <MAX> 1.0
</SHADER>

Using the HFX file

Once you have created your file, for example normalMapping.HFX, you need to ensure your shaders are in the correct location to be found. On Windows the path used in the HFX for shaders is relative to the loaction of the HFX file itself. So if your HFX is located at'c:/myfolder/myFile.HFX' and referances 'shaders/normalMap.frag', normalMap.frag will need to be loacted at 'c:/myfolder/shaders/normalMap.frag'

IMPORTANT NOTE, sorry Mac users but a bug at the moment means you always have to load your shaders from a 'shaders' folder contained inside the application package and use the path 'saders' (e.g. 'shaders/myFrag.frag' ). Then place your shader files in the 'shaders' folder inside the EdDidIt bundle. This can be done by Ctrl Clicking the EdDidIt application and Selecting 'Show Package Contents'. You can then navigate to the shaders folder, 'Contents/Resources/shaders' and place your shader files there.

Now to use your HFX file, open a model in EdDidIt. Select the MATS (materials) tab. Then click the ADV button in the bottom right of the tab.

You will now be prompted to load your HFX file. Navigate to the folder you saved it to and Open it. If all goes well a new material will be added to the materials list (it will be added to the top so be sure to scroll the list down).

Once you select your Material you will be able to select and load textures via the 'Texture Units' section. Uniforms are presented via the uniforms combobox.

See the Materials edititing tutorial for more information about the use of these GUI regions.