OGRE Manual v1.7 ('Cthugha'): Declaring Vertex/Geometry/Fragment Programs

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 3.1.4 Declaring Vertex/Geometry/Fragment Programs

In order to use a vertex, geometry or fragment program in your materials (See section 3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass), you first have to define them. A single program definition can be used by any number of materials, the only prerequisite is that a program must be defined before being referenced in the pass section of a material.
The definition of a program can either be embedded in the .material script itself (in which case it must precede any references to it in the script), or if you wish to use the same program across multiple .material files, you can define it in an external .program script. You define the program in exactly the same way whether you use a .program script or a .material script, the only difference is that all .program scripts are guaranteed to have been parsed before all .material scripts, so you can guarantee that your program has been defined before any .material script that might use it. Just like .material scripts, .program scripts will be read from any location which is on your resource path, and you can define many programs in a single script.
Vertex, geometry and fragment programs can be low-level (i.e. assembler code written to the specification of a given low level syntax such as vs_1_1 or arbfp1) or high-level such as DirectX9 HLSL, Open GL Shader Language, or nVidia's Cg language (See section High-level Programs). High level languages give you a number of advantages, such as being able to write more intuitive code, and possibly being able to target multiple architectures in a single program (for example, the same Cg program might be able to be used in both D3D and GL, whilst the equivalent low-level programs would require separate techniques, each targeting a different API). High-level programs also allow you to use named parameters instead of simply indexed ones, although parameters are not defined here, they are used in the Pass.
Here is an example of a definition of a low-level vertex program:

    vertex_program myVertexProgram asm
    {
        source myVertexProgram.asm
        syntax vs_1_1
    }

As you can see, that's very simple, and defining a fragment or geometry program is exactly the same, just with vertex_program replaced with fragment_program or geometry_program, respectively. You give the program a name in the header, followed by the word 'asm' to indicate that this is a low-level program. Inside the braces, you specify where the source is going to come from (and this is loaded from any of the resource locations as with other media), and also indicate the syntax being used. You might wonder why the syntax specification is required when many of the assembler syntaxes have a header identifying them anyway - well the reason is that the engine needs to know what syntax the program is in before reading it, because during compilation of the material, we want to skip programs which use an unsupportable syntax quickly, without loading the program first.
The current supported syntaxes are:

vs_1_1
  This is one of the DirectX vertex shader assembler syntaxes.
  Supported on cards from: ATI Radeon 8500, nVidia GeForce 3
vs_2_0
  Another one of the DirectX vertex shader assembler syntaxes.
  Supported on cards from: ATI Radeon 9600, nVidia GeForce FX 5 series
vs_2_x
  Another one of the DirectX vertex shader assembler syntaxes.
  Supported on cards from: ATI Radeon X series, nVidia GeForce FX 6 series
vs_3_0
  Another one of the DirectX vertex shader assembler syntaxes.
  Supported on cards from: ATI Radeon HD 2000+, nVidia GeForce FX 6 series
arbvp1
  This is the OpenGL standard assembler format for vertex programs. It's roughly equivalent to DirectX vs_1_1.
vp20
  This is an nVidia-specific OpenGL vertex shader syntax which is a superset of vs 1.1. ATI Radeon HD 2000+ also supports it.
vp30
  Another nVidia-specific OpenGL vertex shader syntax. It is a superset of vs 2.0, which is supported on nVidia GeForce FX 5 series and higher. ATI Radeon HD 2000+ also supports it.
vp40
  Another nVidia-specific OpenGL vertex shader syntax. It is a superset of vs 3.0, which is supported on nVidia GeForce FX 6 series and higher.
ps_1_1, ps_1_2, ps_1_3
  DirectX pixel shader (ie fragment program) assembler syntax.
  Supported on cards from: ATI Radeon 8500, nVidia GeForce 3
  NOTE: for ATI 8500, 9000, 9100, 9200 hardware, this profile can also be used in OpenGL. The ATI 8500 to 9200 do not support arbfp1 but do support atifs extension in OpenGL which is very similar in function to ps_1_4 in DirectX. Ogre has a built in ps_1_x to atifs compiler that is automatically invoked when ps_1_x is used in OpenGL on ATI hardware.
ps_1_4
  DirectX pixel shader (ie fragment program) assembler syntax.
  Supported on cards from: ATI Radeon 8500, nVidia GeForce FX 5 series
  NOTE: for ATI 8500, 9000, 9100, 9200 hardware, this profile can also be used in OpenGL. The ATI 8500 to 9200 do not support arbfp1 but do support atifs extension in OpenGL which is very similar in function to ps_1_4 in DirectX. Ogre has a built in ps_1_x to atifs compiler that is automatically invoked when ps_1_x is used in OpenGL on ATI hardware.
ps_2_0
  DirectX pixel shader (ie fragment program) assembler syntax.
  Supported cards: ATI Radeon 9600, nVidia GeForce FX 5 series
ps_2_x
  DirectX pixel shader (ie fragment program) assembler syntax. This is basically ps_2_0 with a higher number of instructions.
  Supported cards: ATI Radeon X series, nVidia GeForce FX 6 series
ps_3_0
  DirectX pixel shader (ie fragment program) assembler syntax.
  Supported cards: ATI Radeon HD 2000+, nVidia GeForce FX6 series
ps_3_x
  DirectX pixel shader (ie fragment program) assembler syntax.
  Supported cards: nVidia GeForce FX7 series
arbfp1
  This is the OpenGL standard assembler format for fragment programs. It's roughly equivalent to ps_2_0, which means that not all cards that support basic pixel shaders under DirectX support arbfp1 (for example neither the GeForce3 or GeForce4 support arbfp1, but they do support ps_1_1).
fp20
  This is an nVidia-specific OpenGL fragment syntax which is a superset of ps 1.3. It allows you to use the 'nvparse' format for basic fragment programs. It actually uses NV_texture_shader and NV_register_combiners to provide functionality equivalent to DirectX's ps_1_1 under GL, but only for nVidia cards. However, since ATI cards adopted arbfp1 a little earlier than nVidia, it is mainly nVidia cards like the GeForce3 and GeForce4 that this will be useful for. You can find more information about nvparse at http://developer.nvidia.com/object/nvparse.html.
fp30
  Another nVidia-specific OpenGL fragment shader syntax. It is a superset of ps 2.0, which is supported on nVidia GeForce FX 5 series and higher. ATI Radeon HD 2000+ also supports it.
fp40
  Another nVidia-specific OpenGL fragment shader syntax. It is a superset of ps 3.0, which is supported on nVidia GeForce FX 6 series and higher.
gpu_gp, gp4_gp
  An nVidia-specific OpenGL geometry shader syntax.
  Supported cards: nVidia GeForce FX8 series

You can get a definitive list of the syntaxes supported by the current card by calling GpuProgramManager::getSingleton().getSupportedSyntax().

### Specifying Named Constants for Assembler Shaders

Assembler shaders don't have named constants (also called uniform parameters) because the language does not support them - however if you for example decided to precompile your shaders from a high-level language down to assembler for performance or obscurity, you might still want to use the named parameters. Well, you actually can - GpuNamedConstants which contains the named parameter mappings has a 'save' method which you can use to write this data to disk, where you can reference it later using the manual_named_constants directive inside your assembler program declaration, e.g.

    vertex_program myVertexProgram asm
    {
        source myVertexProgram.asm
        syntax vs_1_1
    	manual_named_constants myVertexProgram.constants
    }

In this case myVertexProgram.constants has been created by calling highLevelGpuProgram->getNamedConstants().save("myVertexProgram.constants"); sometime earlier as preparation, from the original high-level program. Once you've used this directive, you can use named parameters here even though the assembler program itself has no knowledge of them.

### Default Program Parameters

While defining a vertex, geometry or fragment program, you can also specify the default parameters to be used for materials which use it, unless they specifically override them. You do this by including a nested 'default_params' section, like so:

    vertex_program Ogre/CelShadingVP cg
    {
    	source Example_CelShading.cg
    	entry_point main_vp
    	profiles vs_1_1 arbvp1

    	default_params
    	{
    		param_named_auto lightPosition light_position_object_space 0
    		param_named_auto eyePosition camera_position_object_space
    		param_named_auto worldViewProj worldviewproj_matrix
    		param_named shininess float 10
    	}
    }

The syntax of the parameter definition is exactly the same as when you define parameters when using programs, See Program Parameter Specification. Defining default parameters allows you to avoid rebinding common parameters repeatedly (clearly in the above example, all but 'shininess' are unlikely to change between uses of the program) which makes your material declarations shorter.

### Declaring Shared Parameters

Often, not every parameter you want to pass to a shader is unique to that program, and perhaps you want to give the same value to a number of different programs, and a number of different materials using that program. Shared parameter sets allow you to define a 'holding area' for shared parameters that can then be referenced when you need them in particular shaders, while keeping the definition of that value in one place. To define a set of shared parameters, you do this:

    shared_params YourSharedParamsName
    {
    	shared_param_named mySharedParam1 float4 0.1 0.2 0.3 0.4
    	...
    }

As you can see, you need to use the keyword 'shared_params' and follow it with the name that you will use to identify these shared parameters. Inside the curly braces, you can define one parameter per line, in a way which is very similar to the param_named syntax. The definition of these lines is:
Format: shared_param_name <param_name> <param_type> [<[array_size]>] [<initial_values>]
The param_name must be unique within the set, and the param_type can be any one of float, float2, float3, float4, int, int2, int3, int4, matrix2x2, matrix2x3, matrix2x4, matrix3x2, matrix3x3, matrix3x4, matrix4x2, matrix4x3 and matrix4x4. The array_size option allows you to define arrays of param_type should you wish, and if present must be a number enclosed in square brackets (and note, must be separated from the param_type with whitespace). If you wish, you can also initialise the parameters by providing a list of values.
Once you have defined the shared parameters, you can reference them inside default_params and params blocks using shared_params_ref. You can also obtain a reference to them in your code via GpuProgramManager::getSharedParameters, and update the values for all instances using them.

## High-level Programs

Support for high level vertex and fragment programs is provided through plugins; this is to make sure that an application using OGRE can use as little or as much of the high-level program functionality as they like. OGRE currently supports 3 high-level program types, Cg (3.1.5 Cg programs) (an API- and card-independent, high-level language which lets you write programs for both OpenGL and DirectX for lots of cards), DirectX 9 High-Level Shader Language (3.1.6 DirectX9 HLSL), and OpenGL Shader Language (3.1.7 OpenGL GLSL). HLSL can only be used with the DirectX rendersystem, and GLSL can only be used with the GL rendersystem. Cg can be used with both, although experience has shown that more advanced programs, particularly fragment programs which perform a lot of texture fetches, can produce better code in the rendersystem-specific shader language.
One way to support both HLSL and GLSL is to include separate techniques in the material script, each one referencing separate programs. However, if the programs are basically the same, with the same parameters, and the techniques are complex this can bloat your material scripts with duplication fairly quickly. Instead, if the only difference is the language of the vertex & fragment program you can use OGRE's 3.1.8 Unified High-level Programs to automatically pick a program suitable for your rendersystem whilst using a single technique.

### Skeletal Animation in Vertex Programs

You can implement skeletal animation in hardware by writing a vertex program which uses the per-vertex blending indices and blending weights, together with an array of world matrices (which will be provided for you by Ogre if you bind the automatic parameter 'world_matrix_array_3x4'). However, you need to communicate this support to Ogre so it does not perform skeletal animation in software for you. You do this by adding the following attribute to your vertex_program definition:

    	includes_skeletal_animation true

When you do this, any skeletally animated entity which uses this material will forgo the usual animation blend and will expect the vertex program to do it, for both vertex positions and normals. Note that ALL submeshes must be assigned a material which implements this, and that if you combine skeletal animation with vertex animation (See section 8. Animation) then all techniques must be hardware accelerated for any to be.

### Morph Animation in Vertex Programs

You can implement morph animation in hardware by writing a vertex program which linearly blends between the first and second position keyframes passed as positions and the first free texture coordinate set, and by binding the animation_parametric value to a parameter (which tells you how far to interpolate between the two). However, you need to communicate this support to Ogre so it does not perform morph animation in software for you. You do this by adding the following attribute to your vertex_program definition:

    	includes_morph_animation true

When you do this, any skeletally animated entity which uses this material will forgo the usual software morph and will expect the vertex program to do it. Note that if your model includes both skeletal animation and morph animation, they must both be implemented in the vertex program if either is to be hardware acceleration. Note that ALL submeshes must be assigned a material which implements this, and that if you combine skeletal animation with vertex animation (See section 8. Animation) then all techniques must be hardware accelerated for any to be.

### Pose Animation in Vertex Programs

You can implement pose animation (blending between multiple poses based on weight) in a vertex program by pulling in the original vertex data (bound to position), and as many pose offset buffers as you've defined in your 'includes_pose_animation' declaration, which will be in the first free texture unit upwards. You must also use the animation_parametric parameter to define the starting point of the constants which will contain the pose weights; they will start at the parameter you define and fill 'n' constants, where 'n' is the max number of poses this shader can blend, i.e. the parameter to includes_pose_animation.

    	includes_pose_animation 4

Note that ALL submeshes must be assigned a material which implements this, and that if you combine skeletal animation with vertex animation (See section 8. Animation) then all techniques must be hardware accelerated for any to be.

### Vertex texture fetching in vertex programs

If your vertex program makes use of 3.1.10 Vertex Texture Fetch, you should declare that with the 'uses_vertex_texture_fetch' directive. This is enough to tell Ogre that your program uses this feature and that hardware support for it should be checked.

    	uses_vertex_texture_fetch true

### Adjacency information in Geometry Programs

Some geometry programs require adjacency information from the geometry. It means that a geometry shader doesn't only get the information of the primitive it operates on, it also has access to its neighbors (in the case of lines or triangles). This directive will tell Ogre to send the information to the geometry shader.

    	uses_adjacency_information true

### Vertex Programs With Shadows

When using shadows (See section 7. Shadows), the use of vertex programs can add some additional complexities, because Ogre can only automatically deal with everything when using the fixed-function pipeline. If you use vertex programs, and you are also using shadows, you may need to make some adjustments.
If you use stencil shadows, then any vertex programs which do vertex deformation can be a problem, because stencil shadows are calculated on the CPU, which does not have access to the modified vertices. If the vertex program is doing standard skeletal animation, this is ok (see section above) because Ogre knows how to replicate the effect in software, but any other vertex deformation cannot be replicated, and you will either have to accept that the shadow will not reflect this deformation, or you should turn off shadows for that object.
If you use texture shadows, then vertex deformation is acceptable; however, when rendering the object into a shadow texture (the shadow caster pass), the shadow has to be rendered in a solid colour (linked to the ambient colour for modulative shadows, black for additive shadows). You must therefore provide an alternative vertex program, so Ogre provides you with a way of specifying one to use when rendering the caster, See section Shadows and Vertex Programs.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated by Steve Streeting on December, 31 2009 using texi2html