Getting Started With Ogre CG Materials         Step by step guide for setting up some very basic CG materials in Ogre

Example 1: Plain Texture

This is a working example of how to create a very simple shader. The shader just applies a single texture to an object. No lighting is performed.

First, create a .material file. The filename is unimportant, but make sure it's in a directory that the game is scanning for media. In the example applications, this is configured in 'resources.cfg'. Add the following material definition to the material file.

Make sure you have this line in the plugins.cfg file : Plugin=Plugin_CgProgramManager.

// CG Vertex shader definition
vertex_program PlainTexture_VS cg            
{
        // Look in this source file for shader code
    source GameObjStandard.cg
        // Use this function for the vertex shader            
    entry_point main_plain_texture_vp    
        // Compile the shader to vs_1_1 format    
    profiles vs_1_1                    

    // This block saves us from manually setting parameters in code
        default_params                    
    {
                // Ogre will put the worldviewproj into our 'worldViewProj' parameter for us.
        param_named_auto worldViewProj worldviewproj_matrix        
                // Note that 'worldViewProj' is a parameter in the cg code.
    }
}

// CG Pixel shader definition
fragment_program PlainTexture_PS cg            
{
        // Look in this source file for shader code
    source GameObjStandard.cg        
        // Use this function for the pixel shader    
    entry_point main_plain_texture_fp    
        // Compile to ps_1_1 format    
    profiles ps_1_1                    
}

material PlainTexture
{
        // Material has one technique
    technique                    
    {
                // This technique has one pass
        pass                    
        {
                        // Make this pass use the vertex shader defined above
            vertex_program_ref PlainTexture_VS    
            {
            }
                        // Make this pass use the pixel shader defined above
            fragment_program_ref PlainTexture_PS    
            {
            }
            texture_unit
            {
                                // This pass will use this 2D texture as its input
                texture Ten.png 2d        
            }
        }
    }
}


This material made references to another file which contains the CG pixel and vertex shaders. Create a file 'GameObjStandard.cg' (also in a media directory) and add the following block. This time the name of the file is important, as the material file refers specifically to it.

void main_plain_texture_vp(
        // Vertex Inputs
        float4 position        : POSITION,    // Vertex position in model space
        float2 texCoord0    : TEXCOORD0,    // Texture UV set 0

        // Outputs
        out float4 oPosition    : POSITION,    // Transformed vertex position
        out float2 uv0        : TEXCOORD0,    // UV0

        // Model Level Inputs
        uniform float4x4 worldViewProj)
{
    // Calculate output position
    oPosition = mul(worldViewProj, position);

    // Simply copy the input vertex UV to the output
    uv0 = texCoord0;
}

void main_plain_texture_fp(
        // Pixel Inputs
        float2 uv0        : TEXCOORD0,    // UV interpolated for current pixel
             
        // Outputs
        out float4 color    : COLOR,    // Output color we want to write
             
        // Model Level Inputs
        uniform sampler2D texture)        // Texture we're going to use
{
    // Just sample texture using supplied UV
    color = tex2D(texture, uv0);
}


The keyword uniform identifies the parameters you will have to supply in the material file.

  • Some parameters can be supplied by the Ogre Engine (param_named_auto), like a light position.
  • Some parameters can be supplied by your material file (param_named) like a texture map.
  • Some parameters can be supplied by your application (custom).




Finally, in the game code, you need to set the material on the entity. To do so, you'll want a line of code something like the following:

pOgreEntity->setMaterialName( "PlainTexture" );

The texture should render on the object. If the material failed to compile properly, it will render white.

Example 2: Texture with modulated color

Now let's say that we want to tweak our simple shader by modulating the texture with another color, and also specify an alpha value for the object.

Colors and modulation basics:

  • In shaders, color values are normally in the range 0..1. A pure red would be R=1, G=0, B=0.
  • A color can be stored in a float3, or a float4 with the fourth component containing alpha information.
  • The RGB components can be accessed as either .r, .g, .b, .a or .x, .y, .z, .w
  • Modulate means multiply. Let's take an example:
    • Lets say that reading the texture with the tex2D returns (R=1, G=0.5, B=0)
    • Lets say we then modulate that with a pink (R=1, G=0.25, B=0.25)
    • This gives an output of (1*1, 0.5*0.25, 0*0.25) = (1, 0.125, 0)
    • The result is that the source texture gets a pink tone to it. Note that modulating with numbers in the range 0..1 only makes things darker, and modulating low numbers together goes to black quickly.




First, define a new material. The key important notes are:

  • The vertex shader doesn't need to do anything different than before, so we're going to use the same one as the material before. We don't need to define a new 'vertex program', though a better naming than 'PlainTexture_VS' would have been more appropriate :-)
  • There's going to be a new pixel shader, so we define a new 'fragment program' block in the material file. It's the same as the last one except it has a different 'entry point' and it defines a default value for our new 'colorModulate' parameter.
  • The material 'pass' block now has a line 'scene_blend alpha_blend'. This means that the pixel shader alpha channel output will be used to blend the color with what's already in the frame buffer. An alpha output of 0 would cause the object to be invisible, and a value of 1 would make it entirely solid.
  • The 'fragment_program_ref' references the name of our new 'fragment program' block.



fragment_program TextureModColor_PS cg
{
    source GameObjStandard.cg
    
    // Different entry point for pixel shader
    entry_point main_tex_mod_col_fp
    
    profiles ps_1_1

    default_params
    {
        // Specify a default value for a new parameter
        // Note that we don't need to specify whether it's a pixel of vertex shader parameter
        param_named colorModulate float4 1 0 0 0.5        
    }
}

material TextureModColor
{
    technique
    {
        pass
        {
            // Makes the pixel shader alpha output be used for alpha blending
            scene_blend alpha_blend            
            
            vertex_program_ref PlainTexture_VS
            {
            }
            fragment_program_ref TextureModColor_PS
            {
            }
            texture_unit
            {
                texture Ten.png 2d
            }
        }
    }
}


Now add the following new pixel shader to your CG file. The key noteworthy changes from the first pixel shader are:

  • There's a new 'colorModulate' function. Note how the parameter name matches the default value set in the material.
  • After the texture sample, we modulate the texture with the new parameter.
  • The last line explicitly puts the alpha value from the parameter into the alpha channel of the output variable.
    • Actually this isn't strictly needed in my case. My texture doesn't have an alpha channel, so the texture sample just puts a 1 into the alpha channel. Then the modulate for the alpha channel operation makes gives color.a = 1 * colorModulate.a, which is the same as color.a = colorModulate.a. I'll leave the line in though as it demonstrates that you can assign values into RGBA too...



void main_tex_mod_col_fp(
            float2 diffuse        : TEXCOORD0,
             
            out float4 color    : COLOR,
             
            uniform float4 colorModulate,    // Added the color parameter
            uniform sampler2D texture)
{
    color = tex2D(texture, diffuse);        // Sample the texture
    color = color * colorModulate;            // Multiply the pixel color by colorModulate
    color.a = colorModulate.a;            // Set the output alpha to be colorModulate.w
}

Programmatic control of color parameter

So far the material we've defined applies a default color modulation and alpha value to the object. We can control this value dynamically from code on a per entity (or rather sub entity) basis. First we need to add a line to the 'fragment program ref' block in the material:

fragment_program_ref TextureModColor_PS
            {
                param_named_auto colorModulate custom 1
            }

This means that our parameter 'colorModulate' can be set from code by setting parameter '1'.

Now we add some lines to your test application at some point after the material is attached to the object. For example:

// Init material
    mEntity->setMaterialName( "TextureModColor" );

#define COLOR_MODULATE_PARAM_INDEX 1
    SubEntity* pSub = mEntity->getSubEntity(0);
    pSub->setCustomParameter(COLOR_MODULATE_PARAM_INDEX, Vector4(0.f, 0.f, 1.0f, 0.2f));

Further Reading/Learning


Alias: Getting_Started_With_Ogre_CG_Materials