How to write shaders with OIV 10

Introduction

Starting with its version 10, Open Inventor® provides a complete shader API to access various state values from shaders. Most of GLSL built in uniforms (e.g, gl_ModelViewMatrix) have a corresponding Open Inventor method (e.g, OivModelViewMatrix()). However, GLSL functions such as cos, mix, greaterThan, and so on,   are still available.
 
Note:
Even if some of the built in GLSL values will continue to work, you should no longer use them.
 
Table of conntent


Converting existing shaders

A script is provided in OIVHOME\src\Inventor\tools\GLSLConverter\GLSLConverter.py to help converting existing shaders.

It's a simple python script that can be used to replace GLSL built-in uniforms with OIV shader API calls. It provides a simple way to port shaders that work in Open Inventor 9.x to shaders working in Open Inventor 10.
 
Usage: python GLSLConverter.py filename [--remove-original]
 
Where filename is the path to a file needing to be converted. It can also be a folder in which case the script will look for every file which name ends in '.glsl' to apply the single-file operation on it. Please note that the conversion process renames the original file filename.origin and the parsed file is saved under filename.
With the '--remove-original' option, filename.origin file is automatically removed by the script.

Note that only built-in uniforms exposed in the Open Inventor Shader API are replaced and others uniforms have to be handled in another way.

The script will automatically do the built-in variable's conversion and add //!oiv_include directive if needed.


GLSL Version

By default, Open Inventor builds GLSL shader in 410 compatibility so it's not mandatory to specify #version 410 compatibility in your shader. But if you need a more recent version or some specific extensions, you'll have to specify it in your shader.

If you specify a version anterior to 410, Open Inventor will override it and compile in 410 anyway.

Even if a shader is built in compatibility, it's a good practice to respect GLSL 410 specification. Otherwise you'll have lots of message saying: "Warning deprecated...".

Here is a list of common errors and how to fix them to avoid issues:

  • Using varying keyword instead of in/out:
    • In vertex shader: replace varying float value; by out float value;
    • In fragment shader: replace varying float value; by in float value
  • Using gl_TexCoord[0] to pass texcoord from vertex to fragment shader intead of using in/out varying
  • Using texture2D/3D function instead of generic texture.

Built-in uniforms conversion

If your shader use GLSL built in uniforms like gl_ModelViewMatrix, you should replace these calls with corresponding Open Inventor calls and add the following include at the top of your shader:
 
//!oiv_include <Inventor/oivShaderState.h>

 
Here is the list of correspondence between built in GLSL and Open Inventor available methods:

Matrices

 

Material

 

Lighting

 

Misc

 


Vertex attributes conversion

If your shader use GLSL built in vertex attributes like gl_Vertex, you should replace these calls with corresponding OIV calls and add the following include at the top of your shader:
 
//!oiv_include <Inventor/oivShapeAttribute.h>

 
Correspondence between built in GLSL and Oiv methods:

Vertex attributes

 


Manage transparency

To properly handle transparency, your fragment shader should contains the following function calls:

These methods are accessible by including the <Inventor/oivDepthPeeling_frag.h> header in your shader:

Exemple:

//!oiv_include <Inventor/oivDepthPeeling_frag.h>

void main()
{
 if ( OivDepthPeel(gl_FragCoord.xyz) )
  {
    Vec4 color = vec4(1, 0, 0, 0.5);
    OivDepthPeelingOutputColor(color);
   }
}

You should also specify SoShaderProgram::generateTransparency = TRUE to indicate that your shader will override current SoMaterial transparency.


Geometry shader

Layout of input and output primitives should be manually specified in geometry shader. Your geometry shader should contains header like :

  • layout(input_primitive​) in; where input_primitive is one of
    • points
    • lines
    • triangles

    depending on type of node you use. For example, when applying geometry shader to an SoPointSet, input_primitive should be points.

  • layout(output_primitive, max_vertices = vert_count​) out; vert_count is number of vertices you want to emit and output_primitive is one of
    • points
    • line_strip
    • triangle_strip

    depending on type of primitive you want to emit.

Ex: If your geometry shader take as input a point and generate a quad formed by two stripped triangles, to create some kind of billboard, your header will look like:

  • layout(points) in;
  • layout(triangle_strip, max_vertices = 4) out;