[osg-users] Pragmatic shader - a new #pragma directive proposition
Robert Milharcic
robert.milharcic at ib-caddy.si
Wed Jan 13 23:59:39 PST 2016
Hi all,
With the pragmatic shader one could implement multiple lights and other repetitive constructs like this:
-- start of shader code --
#pragma import_defines ( LIGHTING, LIGHT0, LIGHT1 )
#ifdef LIGHTING
#ifdef LIGHT0
uniform vec4 u_LightColor0;
#endif
#ifdef LIGHT1
uniform vec4 u_LightColor1;
#endif
varying vec4 basecolor;
void light( in vec4 lightColor, inout vec4 color );
#endif
void main(void)
{
basecolor = gl_Color;
#ifdef LIGHTING
#ifdef LIGHT0
light( u_LightColor0, basecolor);
#endif
#ifdef LIGHT1
light( u_LightColor1, basecolor);
#endif
#endif
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
-- end of shader code --
... and to enable both lights:
stateset->setDefine("LIGHTING");
stateset->setDefine("LIGHT0");
stateset->setDefine("LIGHT1");
The problem with this approach is that nobody really knows in advance how many more lights will be needed. Moreover, the shader can get heavily bloated when more and more lights are added. As a solution I would like to propose a new #pragma construct:
#pragma repeat_begin( DEFINE_IDENTIFIER${SubstitutionParameter} )
(shader code block)
#pragma repeat_end()
... and the shader code supporting arbitrary number of lights would then look like this:
-- start of shader code --
#pragma import_defines ( LIGHTING, LIGHT${Member} )
#ifdef LIGHTING
#pragma repeat_begin( LIGHT${Member} )
uniform vec4 u_LightColor${Member};
#pragma repeat_end()
varying vec4 basecolor;
void light( in vec4 lightColor, inout vec4 color );
#endif
void main(void)
{
basecolor = gl_Color;
#ifdef LIGHTING
#pragma repeat_begin( LIGHT${Member} )
light( u_LightColor${Member}, basecolor);
#pragma repeat_end()
#endif
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
-- end of shader code --
... where ${Member} is a substitution parameter and LIGHT is define identifier. Then with:
stateset->setDefine("LIGHTING");
stateset->setDefine("LIGHT${0}");
stateset->setDefine("LIGHT${1}");
stateset->setDefine("LIGHT${5}");
... where ${0}, ${1}, ${5} are substitution values, osg would produce following shader code:
-- start of shader code --
#define LIGHTING
#define LIGHT0
#define LIGHT1
#define LIGHT5
#ifdef LIGHTING
uniform vec4 u_LightColor0;
uniform vec4 u_LightColor1;
uniform vec4 u_LightColor5;
varying vec4 basecolor;
void light( in vec4 lightColor, inout vec4 color );
#endif
void main(void)
{
basecolor = gl_Color;
#ifdef LIGHTING
light( u_LightColor0, basecolor);
light( u_LightColor1, basecolor);
light( u_LightColor5, basecolor);
#endif
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
-- end of shader code --
Before I do any coding I'd like to know if proposed solution would be of any use to the osg community? Or maybe there is a better way? I'm currently solving these kinds of problems with uniform arrays, but unfortunately, the uniform array has its own max number of elements and the management code of such approach tend to be complicated...
Cheers,
Robert Milharcic
More information about the osg-users
mailing list