Introduction
Starting with version 10, Open Inventor® provides a GLSL shader API to access various state values from shaders. The classical GLSL built-in uniforms for OpenGL state (e.g. gl_ModelViewMatrix) now have a corresponding Open Inventor GLSL method (e.g. OivModelViewMatrix()). These methods are documented in the Reference Manual and in $OIVHOME/shaders/include/Inventor/oivShaderState.h. GLSL built-in constants (e.g. gl_MaxVertexAttribs) and GLSL built-in input/output variables (e.g. gl_FragCoord) are still available. GLSL functions such as cos, mix, greaterThan, and so on, are still available.
Note: Even if some of the built-in GLSL state variables continue to work, you should no longer use them.
Note: Some changes to existing GLSL shader code are mandatory.
Table of content
- Converting existing shader
- GLSL Version
- Vertex attributes conversion
- Built-in uniforms conversion
- Built-in varyings conversion
- Manage transparency
- Geometry shader
- PassThrough Helpers
Converting existing shaders
A script is provided in $OIVHOME\tools\source\Inventor\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 shaders in 410 compatibility mode. So it is 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 older than 410, Open Inventor will override it and compile in 410 anyway.
Even if a shader is built-in compatibility mode, it is good practice to respect the GLSL 410 specification. Otherwise you'll have a lot of messages 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.
Vertex attributes conversion
If your shader uses 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
- gl_Vertex can be replaced by OivVertexPosition()
- gl_Normal can be replaced by OivVertexNormal()
- gl_Color can be replaced by OivVertexColor()
- gl_MultiTexCoord[i] can be replaced by OivVertexTextureCoordinate(i)
- gl_TextureMatrix[i] can be replaced by OivTextureMatrix(i)
Note: Using custom vertex attributes inputs to retrieve vertex positions, normals, colors and texture coordinates will not work.
// This will not work anymore in Vertex Shader
layout(location=0) in vec3 VertexPosition;
Built-in uniforms conversion
If your shader uses 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:
- gl_ModelViewMatrixInverse can be replaced by OivModelViewMatrixInverse()
- gl_ModelViewMatrix can be replaced by OivModelViewMatrix()
- gl_NormalMatrix can be replaced by OivNormalMatrix()
- gl_ProjectionMatrix can be replaced by OivProjectionMatrix()
- gl_ModelViewProjectionMatrix can be replaced by OivModelViewProjectionMatrix()
- gl_FrontMaterial.ambient can be replaced by OivFrontMaterialAmbient()
- gl_FrontMaterial.diffuse can be replaced by OivFrontMaterialDiffuse()
- gl_FrontMaterial.specular can be replaced by OivFrontMaterialSpecular()
- gl_FrontMaterial.shininess can be replaced by OivFrontMaterialShininess()
- gl_FrontMaterial.emission can be replaced by OivFrontMaterialEmissive()
- gl_BackMaterial.ambient can be replaced by OivBackMaterialAmbient()
- gl_BackMaterial.diffuse can be replaced by OivBackMaterialDiffuse()
- gl_BackMaterial.specular can be replaced by OivBackMaterialSpecular()
- gl_BackMaterial.shininess can be replaced by OivBackMaterialShininess()
- gl_BackMaterial.emission can be replaced by OivBackMaterialEmissive()
- gl_LightSource[i].position can be replaced by OivLightSourcePosition(i)
- gl_LightSource[i].spotDirection can be replaced by OivLightSourceSpotDirection(i)
- gl_LightSource[i].spotExponent can be replaced by OivLightSourceSpotExponent(i)
- gl_LightSource[i].spotCutoff can be replaced by OivLightSourceSpotCutoff(i)
- gl_LightSource[i].spotCosCutoff can be replaced by OivLightSourceSpotCosCutoff(i)
- gl_LightSource[i].ambient can be replaced by OivLightSourceAmbient(i)
- gl_LightSource[i].diffuse can be replaced by OivLightSourceDiffuse(i)
- gl_LightSource[i].specular can be replaced by OivLightSourceSpecular(i)
- gl_LightSource[i].constantAttenuation can be replaced by OivLightSourceConstantAttenuation(i)
- gl_LightSource[i].linearAttenuation can be replaced by OivLightSourceLinearAttenuation(i)
- gl_LightSource[i].quadraticAttenuation can be replaced by OivLightSourceQuadraticAttenuation(i)
- gl_FrontLightProduct[i].ambient can be replaced by OivFrontLightProductAmbient(i)
- gl_FrontLightProduct[i].diffuse can be replaced by OivFrontLightProductDiffuse(i)
- gl_FrontLightProduct[i].specular can be replaced by OivFrontLightProductSpecular(i)
- gl_BackLightProduct[i].ambient can be replaced by OivBackLightProductAmbient(i)
- gl_BackLightProduct[i].diffuse can be replaced by OivBackLightProductDiffuse(i)
- gl_BackLightProduct[i].specular can be replaced by OivBackLightProductSpecular(i)
- gl_ClipPlane[i] can be replaced by OivClipPlane(i)
- ftransform() is replaced by OivModelViewProjectionMatrix() * OivVertexPosition();
Built-in varyings conversion
If your shader uses GLSL built in varyings like glTexCoord, glFrontColor, you should replace these calls with corresponding Open Inventor calls and add the following include at the top of your shader:
//!oiv_include <Inventor/oivShaderVariables.h>
Here is the list of correspondence between built in GLSL and Open Inventor available methods:
Vertex Shader
- gl_FogCoord can be replaced by OivFogFragCoord()
Tessellation Control Shader / Tessellation Evaluation Shader / Geometry Shader
- gl_in[i].gl_FrontColor can be replaced by OivFrontColor(i)
- gl_in[i].gl_BackColor can be replaced by OivBackColor(i)
- gl_in[i].gl_TexCoord[u] can be replaced by OivTexCoord(i, u)
- gl_in[i].gl_FogFragCoord can be replaced by OivFogFragCoord(i)
Fragment Shader
- gl_Color can be replaced by OivFragmentColor()
- gl_TexCoord[i] can be replaced by OivFragmentTexCoord(i)
- gl_FogFragCoord can be replaced by OivFogFragCoord()
Vertex Shader / Tessellation Evaluation Shader / Geometry Shader
- gl_FrontColor = c can be replaced by OivSetFrontColor(c)
- gl_BackColor = c can be replaced by OivSetBackColor(c)
- gl_TexCoord[u] = c can be replaced by OivSetTexCoord(u, c)
- gl_FogFragCoord = c can be replaced by OivSetFogFragCoord(c)
Tessellation Control Shader
- gl_out[gl_InvocationID].gl_FrontColor = c can be replaced by OivSetFrontColor(c)
- gl_out[gl_InvocationID].gl_BackColor = c can be replaced by OivSetBackColor(c)
- gl_out[gl_InvocationID].gl_TexCoord[u] = c can be replaced by OivSetTexCoord(u, c)
- gl_out[gl_InvocationID].gl_FogFragCoord = c can be replaced by OivSetFogFragCoord(c)
Fragment Shader
- gl_FragColor = c can be replaced by OivFragmentOutput(c)
- gl_FragData[i] = c can be replaced by OivFragmentOutput(i, c)
Manage transparency
To properly handle transparency, your fragment shader should contains the following function calls:
- You should enclose your code in if ( OivDepthPeel(gl_FragCoord.xyz) ) { } condition
- You should output your color using OivDepthPeelingOutputColor()) method
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 must be manually specified in your geometry shader. Your geometry shader should contain a 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;
PassThrough Helpers
Functions are also available to copy all predefined varyings from one stage to the next:
Vertex Shader
gl_FrontColor = gl_Color;
gl_BackColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_TexCoord[2] = gl_MultiTexCoord2;
gl_TexCoord[3] = gl_MultiTexCoord3;
gl_FogFragCoord = gl_FogCoord;
can be replaced by OivSetupVertex()
Tessellation Evaluation Shader / Geometry Shader
gl_FrontColor = gl_in[i].gl_FrontColor;
gl_BackColor = gl_in[i].gl_BackColor;
gl_FrontSecondaryColor = gl_in[i].gl_FrontSecondaryColor;
gl_BackSecondaryColor = gl_in[i].gl_BackSecondaryColor;
gl_TexCoord = gl_in[i].gl_TexCoord;
gl_FogFragCoord = gl_in[i].gl_FogFragCoord;
can be replaced by OivSetupVertex(i)
Tessellation Control Shader
gl_out[gl_InvocationID].gl_FrontColor = gl_in[i].gl_FrontColor;
gl_out[gl_InvocationID].gl_BackColor = gl_in[i].gl_BackColor;
gl_out[gl_InvocationID].gl_FrontSecondaryColor = gl_in[i].gl_FrontSecondaryColor;
gl_out[gl_InvocationID].gl_BackSecondaryColor = gl_in[i].gl_BackSecondaryColor;
gl_out[gl_InvocationID].gl_TexCoord = gl_in[i].gl_TexCoord;
gl_out[gl_InvocationID].gl_FogFragCoord = gl_in[i].gl_FogFragCoord;
can be replaced by OivSetupVertex(i)