Table of contents
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
- How to use the CG compiler - How to check for errors in your CG code
- Definitely read the six or so pages on material scripts in the Ogre manual Ogre manual: material scripts
- Explore the nVidia site, it has lots of great examples and documentation on CG. Specifically, download and play with the nVidia FX Composer tool. It allows interactive development of shaders. http://developer.nvidia.com/page/tools.html
- More resources may be found in the Shaders section of CodeSnippets.