diff --git a/examples/osgshadercompositor/CreateAdvancedHierachy.cpp b/examples/osgshadercompositor/CreateAdvancedHierachy.cpp index ee847ba34..d67c4f437 100644 --- a/examples/osgshadercompositor/CreateAdvancedHierachy.cpp +++ b/examples/osgshadercompositor/CreateAdvancedHierachy.cpp @@ -1,579 +1,580 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "VirtualProgram.h" - -using osgCandidate::VirtualProgram; - -//////////////////////////////////////////////////////////////////////////////// -// Example shaders assume: -// one texture -// one directional light -// front face lighting -// color material mode not used (its not supported by GLSL anyway) -// diffuse/ambient/emissive/specular factors defined in material structure -// all coords and normal except gl_Position are in view space -//////////////////////////////////////////////////////////////////////////////// - -char MainVertexShaderSource[] = -"vec4 texture( in vec3 position, in vec3 normal ); \n" //1 -"void lighting( in vec3 position, in vec3 normal ); \n" //2 -" \n" //3 -"void main () \n" //4 -"{ \n" //5 -" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" //6 -" vec4 position4 = gl_ModelViewMatrix * gl_Vertex; \n" //7 -" vec3 position = position4.xyz / position4.w; \n" //8 -" vec3 normal = normalize( gl_NormalMatrix * gl_Normal ); \n" //9 -" gl_TexCoord[0] = texture( position, normal ); \n" //10 -" lighting( position, normal ); \n" //11 -"} \n";//12 - -char TexCoordTextureVertexShaderSource[] = -"vec4 texture( in vec3 position, in vec3 normal ) \n" //1 -"{ \n" //2 -" return gl_TextureMatrix[0] * gl_MultiTexCoord0; \n" //3 -"} \n";//4 - -char SphereMapTextureVertexShaderSource[] = -"vec4 texture( in vec3 position, in vec3 normal ) \n" //1 -"{ \n" //2 -" vec3 u = normalize( position ); \n" //3 -" vec3 r = reflect(u, normal); \n" //4 -" float m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z+1.0) * (r.z+1.0)); \n" //5 -" return vec4(r.x / m + 0.5, r.y / m + 0.5, 1.0, 1.0 ); \n" //6 -"} \n";//7 - -char PerVertexDirectionalLightingVertexShaderSource[] = -"void lighting( in vec3 position, in vec3 normal ) \n" //1 -"{ \n" //2 -" float NdotL = dot( normal, normalize(gl_LightSource[0].position.xyz) );\n" //3 -" NdotL = max( 0.0, NdotL ); \n" //4 -" float NdotHV = dot( normal, gl_LightSource[0].halfVector.xyz ); \n" //5 -" NdotHV = max( 0.0, NdotHV ); \n" //6 -" \n" //7 -" gl_FrontColor = gl_FrontLightModelProduct.sceneColor + \n" //8 -" gl_FrontLightProduct[0].ambient + \n" //9 -" gl_FrontLightProduct[0].diffuse * NdotL; \n" //10 -" \n" //11 -" gl_FrontSecondaryColor = vec4(0.0); \n" //12 -" \n" //13 -" if ( NdotL * NdotHV > 0.0 ) \n" //14 -" gl_FrontSecondaryColor = gl_FrontLightProduct[0].specular * \n" //15 -" pow( NdotHV, gl_FrontMaterial.shininess );\n" //16 -" \n" //17 -" gl_BackColor = gl_FrontColor; \n" //18 -" gl_BackSecondaryColor = gl_FrontSecondaryColor; \n" //19 -"} \n";//20 - -char MainFragmentShaderSource[] = -"vec4 texture( void ); \n" //1 -"void lighting( inout vec4 color ); \n" //2 -" \n" //3 -"void main () \n" //4 -"{ \n" //5 -" vec4 color = texture(); \n" //6 -" lighting( color ); \n" //7 -" gl_FragColor = color; \n" //8 -"} \n";//9 - -char TextureFragmentShaderSource[] = -"uniform sampler2D baseTexture; \n" //1 -"vec4 texture( void ) \n" //2 -"{ \n" //3 -" return texture2D( baseTexture, gl_TexCoord[0].xy ); \n" //4 -"} \n";//5 - -char ProceduralBlueTextureFragmentShaderSource[] = -"vec4 texture( void ) \n" //1 -"{ \n" //2 -" return vec4( 0.3, 0.3, 1.0, 1.0 ); \n" //3 -"} \n";//4 - -char PerVertexLightingFragmentShaderSource[] = -"void lighting( inout vec4 color ) \n" //1 -"{ \n" //2 -" color = color * gl_Color + gl_SecondaryColor; \n" //3 -"} \n";//4 - -char PerFragmentLightingVertexShaderSource[] = -"varying vec3 Normal; \n" //1 -"varying vec3 Position; \n" //2 -" \n" //3 -"void lighting( in vec3 position, in vec3 normal ) \n" //4 -"{ \n" //5 -" Normal = normal; \n" //6 -" Position = position; \n" //7 -"} \n";//8 - -char PerFragmentDirectionalLightingFragmentShaderSource[] = -"varying vec3 Normal; \n" //1 -"varying vec3 Position; // not used for directional lighting \n" //2 -" \n" //3 -"void lighting( inout vec4 color ) \n" //4 -"{ \n" //5 -" vec3 n = normalize( Normal ); \n" //5 -" float NdotL = dot( n, normalize(gl_LightSource[0].position.xyz) ); \n" //6 -" NdotL = max( 0.0, NdotL ); \n" //7 -" float NdotHV = dot( n, gl_LightSource[0].halfVector.xyz ); \n" //8 -" NdotHV = max( 0.0, NdotHV ); \n" //9 -" \n" //10 -" color *= gl_FrontLightModelProduct.sceneColor + \n" //11 -" gl_FrontLightProduct[0].ambient + \n" //12 -" gl_FrontLightProduct[0].diffuse * NdotL; \n" //13 -" \n" //14 -" if ( NdotL * NdotHV > 0.0 ) \n" //15 -" color += gl_FrontLightProduct[0].specular * \n" //16 -" pow( NdotHV, gl_FrontMaterial.shininess ); \n" //17 -"} \n";//18 - -//////////////////////////////////////////////////////////////////////////////// -osg::Node * CreateModel( const char * file ) -{ - if ( file ) { - osg::Node * node = NULL; - node = osgDB::readNodeFile( file ); - if( node ) - return node; - } - - // File not found - create textured sphere - osg::Geode * geode = new osg::Geode; - osg::ref_ptr hints = new osg::TessellationHints; - hints->setDetailRatio( 0.3 ); - -#if 1 - osg::ref_ptr shape = new osg::ShapeDrawable - ( new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 4.0 ), hints.get() ); -#else - osg::ref_ptr shape = new osg::ShapeDrawable - ( new osg::Box( osg::Vec3(-1.0f, -1.0f, -1.0f), 2.0, 2.0, 2.0 ) ); -#endif - - shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f)); - - geode->addDrawable( shape.get() ); - - osg::StateSet * stateSet = new osg::StateSet; - - osg::Texture2D * texture = new osg::Texture2D( - osgDB::readImageFile("Images/land_shallow_topo_2048.jpg") - ); - - osg::Material * material = new osg::Material; - - material->setAmbient - ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) ); - - material->setDiffuse - ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) ); - -#if 1 - material->setSpecular - ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.7, 0.3, 0.3, 1.0 ) ); - - material->setShininess( osg::Material::FRONT_AND_BACK, 25 ); - -#endif - - stateSet->setAttributeAndModes( material ); - stateSet->setTextureAttributeAndModes( 0,texture, osg::StateAttribute::ON ); - - geode->setStateSet( stateSet ); - return geode; -} -//////////////////////////////////////////////////////////////////////////////// -// Convenience method to simplify code a little ... -void SetVirtualProgramShader( VirtualProgram * virtualProgram, - std::string shader_semantics, - osg::Shader::Type shader_type, - std::string shader_name, - std::string shader_source ) -{ - osg::Shader * shader = new osg::Shader( shader_type ); - shader->setName( shader_name ); - shader->setShaderSource( shader_source ); - virtualProgram->setShader( shader_semantics, shader ); -} -/////////////////////////////////////////////////////////////////////////////// -void AddLabel( osg::Group * group, const std::string & label, float offset ) -{ - osg::Vec3 center( 0, 0, offset * 0.5 ); - osg::Geode * geode = new osg::Geode; - - // Make sure no program breaks text outputs - geode->getOrCreateStateSet()->setAttribute - ( new osg::Program, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); - - // Turn off stage 1 texture set in parent transform (otherwise it darkens text) - geode->getOrCreateStateSet()->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OFF ); - - group->addChild( geode ); - - osgText::Text* text = new osgText::Text; - geode->addDrawable( text ); - text->setFont("fonts/times.ttf"); - text->setCharacterSize( offset * 0.1 ); - text->setPosition(center); - text->setAlignment( osgText::TextBase::CENTER_CENTER ); - text->setAxisAlignment(osgText::Text::SCREEN); - - osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f); -#if 1 - // reproduce outline bounding box compute problem with backdrop on. - text->setBackdropType(osgText::Text::OUTLINE); - text->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX); -#endif - - text->setText( label ); -} -//////////////////////////////////////////////////////////////////////////////// -osg::Node * CreateAdvancedHierarchy( const char * file = NULL ) -{ - osg::Node * model = CreateModel( file ); - if( !model ) return NULL; - float offset = model->getBound().radius() * 1.3; // diameter - - // Create transforms for translated instances of the model - osg::MatrixTransform * transformCenterMiddle = new osg::MatrixTransform( ); - transformCenterMiddle->setMatrix( osg::Matrix::translate( 0,0, offset * 0.5 ) ); - transformCenterMiddle->addChild( model ); - - osg::MatrixTransform * transformCenterTop = new osg::MatrixTransform( ); - transformCenterMiddle->addChild( transformCenterTop ); - transformCenterTop->setMatrix( osg::Matrix::translate( 0,0,offset ) ); - transformCenterTop->addChild( model ); - - osg::MatrixTransform * transformCenterBottom = new osg::MatrixTransform( ); - transformCenterMiddle->addChild( transformCenterBottom ); - transformCenterBottom->setMatrix( osg::Matrix::translate( 0,0,-offset ) ); - transformCenterBottom->addChild( model ); - - osg::MatrixTransform * transformLeftBottom = new osg::MatrixTransform( ); - transformCenterBottom->addChild( transformLeftBottom ); - transformLeftBottom->setMatrix( osg::Matrix::translate( -offset * 0.8,0, -offset * 0.8 ) ); - transformLeftBottom->addChild( model ); - - osg::MatrixTransform * transformRightBottom = new osg::MatrixTransform( ); - transformCenterBottom->addChild( transformRightBottom ); - transformRightBottom->setMatrix( osg::Matrix::translate( offset * 0.8,0, -offset * 0.8 ) ); - transformRightBottom->addChild( model ); - - // Set default VirtualProgram in root StateSet - // With main vertex and main fragment shaders calling - // lighting and texture functions defined in aditional shaders - // Lighting is done per vertex using simple directional light - // Texture uses stage 0 TexCoords and TexMap - - if( 1 ) - { - // NOTE: - // duplicating the same semantics name in virtual program - // is only possible if its used for shaders of differing types - // here for VERTEX and FRAGMENT - - VirtualProgram * vp = new VirtualProgram( ); - transformCenterMiddle->getOrCreateStateSet()->setAttribute( vp ); - AddLabel( transformCenterMiddle, "Per Vertex Lighting Virtual Program", offset ); - - SetVirtualProgramShader( vp, "main", osg::Shader::VERTEX, - "Vertex Main", MainVertexShaderSource ); - - SetVirtualProgramShader( vp, "main", osg::Shader::FRAGMENT, - "Fragment Main", MainFragmentShaderSource ); - - SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX, - "Vertex Texture Coord 0", TexCoordTextureVertexShaderSource ); - - SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT, - "Fragment Texture", TextureFragmentShaderSource ); - - SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX, - "Vertex Lighting", PerVertexDirectionalLightingVertexShaderSource ); - - SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT, - "Fragment Lighting", PerVertexLightingFragmentShaderSource ); - - transformCenterMiddle->getOrCreateStateSet()-> - addUniform( new osg::Uniform( "baseTexture", 0 ) ); - - } - - // Override default vertex ligting with pixel lighting shaders - // For three bottom models - if( 1 ) - { - AddLabel( transformCenterBottom, "Per Pixel Lighting VP", offset ); - VirtualProgram * vp = new VirtualProgram( ); - transformCenterBottom->getOrCreateStateSet()->setAttribute( vp ); - - SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX, - "Vertex Shader For Per Pixel Lighting", - PerFragmentLightingVertexShaderSource ); - - SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT, - "Fragment Shader For Per Pixel Lighting", - PerFragmentDirectionalLightingFragmentShaderSource ); - } - - // Additionaly set bottom left model texture to procedural blue to - // better observe smooth speculars done through per pixel lighting - if( 1 ) - { - AddLabel( transformLeftBottom, "Blue Tex VP", offset ); - VirtualProgram * vp = new VirtualProgram( ); - transformLeftBottom->getOrCreateStateSet()->setAttribute( vp ); - - SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT, - "Fragment Shader Procedural Blue Tex", - ProceduralBlueTextureFragmentShaderSource ); - } - - // Additionaly change texture mapping to SphereMAp in bottom right model - if( 1 ) - { - AddLabel( transformRightBottom, "EnvMap Sphere VP", offset ); - - osg::StateSet * ss = transformRightBottom->getOrCreateStateSet(); - VirtualProgram * vp = new VirtualProgram( ); - ss->setAttribute( vp ); - SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX, - "Vertex Texture Sphere Map", SphereMapTextureVertexShaderSource ); - - osg::Texture2D * texture = new osg::Texture2D( -// osgDB::readImageFile("Images/reflect.rgb") - osgDB::readImageFile("Images/skymap.jpg") - ); - - // Texture is set on stage 1 to not interfere with label text - // The same could be achieved with texture override - // but such approach also turns off label texture - ss->setTextureAttributeAndModes( 1, texture, osg::StateAttribute::ON ); - ss->addUniform( new osg::Uniform( "baseTexture", 1 ) ); - -#if 0 // Could be useful with Fixed Vertex Pipeline - osg::TexGen * texGen = new osg::TexGen(); - texGen->setMode( osg::TexGen::SPHERE_MAP ); - - // Texture states applied - ss->setTextureAttributeAndModes( 1, texGen, osg::StateAttribute::ON ); -#endif - - } - - - // Top center model usues osg::Program overriding VirtualProgram in model - if( 1 ) - { - AddLabel( transformCenterTop, "Fixed Vertex + Simple Fragment osg::Program", offset ); - osg::Program * program = new osg::Program; - program->setName( "Trivial Fragment + Fixed Vertex Program" ); - - transformCenterTop->getOrCreateStateSet( )->setAttributeAndModes - ( program, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); - - osg::Shader * shader = new osg::Shader( osg::Shader::FRAGMENT ); - shader->setName( "Trivial Fragment Shader" ); - shader->setShaderSource( - "uniform sampler2D baseTexture; \n" - "void main(void) \n" - "{ \n" - " gl_FragColor = gl_Color * texture2D( baseTexture, gl_TexCoord[0] ); \n" - "} \n" - ); - - program->addShader( shader ); - } - - return transformCenterMiddle; -} - -//////////////////////////////////////////////////////////////////////////////// -// Shders not used in the example but left for fun if anyone wants to play -char LightingVertexShaderSource[] = -"// Forward declarations \n" //1 -" \n" //2 -"void SpotLight( in int i, in vec3 eye, in vec3 position, in vec3 normal, \n" //3 -" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //4 -" \n" //5 -"void PointLight( in int i, in vec3 eye, in vec3 position, in vec3 normal, \n" //6 -" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //7 -" \n" //8 -"void DirectionalLight( in int i, in vec3 normal, \n" //9 -" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //10 -" \n" //11 -"const int NumEnabledLights = 1; \n" //12 -" \n" //13 -"void lighting( in vec3 position, in vec3 normal ) \n" //14 -"{ \n" //15 -" vec3 eye = vec3( 0.0, 0.0, 1.0 ); \n" //16 -" //vec3 eye = -normalize(position); \n" //17 -" \n" //18 -" // Clear the light intensity accumulators \n" //19 -" vec4 amb = vec4(0.0); \n" //20 -" vec4 diff = vec4(0.0); \n" //21 -" vec4 spec = vec4(0.0); \n" //22 -" \n" //23 -" // Loop through enabled lights, compute contribution from each \n" //24 -" for (int i = 0; i < NumEnabledLights; i++) \n" //25 -" { \n" //26 -" if (gl_LightSource[i].position.w == 0.0) \n" //27 -" DirectionalLight(i, normal, amb, diff, spec); \n" //28 -" else if (gl_LightSource[i].spotCutoff == 180.0) \n" //29 -" PointLight(i, eye, position, normal, amb, diff, spec); \n" //30 -" else \n" //31 -" SpotLight(i, eye, position, normal, amb, diff, spec); \n" //32 -" } \n" //33 -" \n" //34 -" gl_FrontColor = gl_FrontLightModelProduct.sceneColor + \n" //35 -" amb * gl_FrontMaterial.ambient + \n" //36 -" diff * gl_FrontMaterial.diffuse; \n" //37 -" \n" //38 -" gl_FrontSecondaryColor = vec4(spec*gl_FrontMaterial.specular); \n" //39 -" \n" //40 -" gl_BackColor = gl_FrontColor; \n" //41 -" gl_BackSecondaryColor = gl_FrontSecondaryColor; \n" //42 -"} \n";//43 - -char SpotLightShaderSource[] = -"void SpotLight(in int i, \n" //1 -" in vec3 eye, \n" //2 -" in vec3 position, \n" //3 -" in vec3 normal, \n" //4 -" inout vec4 ambient, \n" //5 -" inout vec4 diffuse, \n" //6 -" inout vec4 specular) \n" //7 -"{ \n" //8 -" float nDotVP; // normal . light direction \n" //9 -" float nDotHV; // normal . light half vector \n" //10 -" float pf; // power factor \n" //11 -" float spotDot; // cosine of angle between spotlight \n" //12 -" float spotAttenuation; // spotlight attenuation factor \n" //13 -" float attenuation; // computed attenuation factor \n" //14 -" float d; // distance from surface to light source \n" //15 -" vec3 VP; // direction from surface to light position \n" //16 -" vec3 halfVector; // direction of maximum highlights \n" //17 -" \n" //18 -" // Compute vector from surface to light position \n" //19 -" VP = vec3(gl_LightSource[i].position) - position; \n" //20 -" \n" //21 -" // Compute distance between surface and light position \n" //22 -" d = length(VP); \n" //23 -" \n" //24 -" // Normalize the vector from surface to light position \n" //25 -" VP = normalize(VP); \n" //26 -" \n" //27 -" // Compute attenuation \n" //28 -" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + \n" //29 -" gl_LightSource[i].linearAttenuation * d + \n" //30 -" gl_LightSource[i].quadraticAttenuation *d*d); \n" //31 -" \n" //32 -" // See if point on surface is inside cone of illumination \n" //33 -" spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection)); \n" //34 -" \n" //35 -" if (spotDot < gl_LightSource[i].spotCosCutoff) \n" //36 -" spotAttenuation = 0.0; // light adds no contribution \n" //37 -" else \n" //38 -" spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent); \n" //39 -" \n" //40 -" // Combine the spotlight and distance attenuation. \n" //41 -" attenuation *= spotAttenuation; \n" //42 -" \n" //43 -" halfVector = normalize(VP + eye); \n" //44 -" \n" //45 -" nDotVP = max(0.0, dot(normal, VP)); \n" //46 -" nDotHV = max(0.0, dot(normal, halfVector)); \n" //47 -" \n" //48 -" if (nDotVP == 0.0) \n" //49 -" pf = 0.0; \n" //50 -" else \n" //51 -" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //52 -" \n" //53 -" ambient += gl_LightSource[i].ambient * attenuation; \n" //54 -" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; \n" //55 -" specular += gl_LightSource[i].specular * pf * attenuation; \n" //56 -"} \n";//57 - -char PointLightShaderSource[] = -"void PointLight(in int i, \n" //1 -" in vec3 eye, \n" //2 -" in vec3 position, \n" //3 -" in vec3 normal, \n" //4 -" inout vec4 ambient, \n" //5 -" inout vec4 diffuse, \n" //6 -" inout vec4 specular) \n" //7 -"{ \n" //8 -" float nDotVP; // normal . light direction \n" //9 -" float nDotHV; // normal . light half vector \n" //10 -" float pf; // power factor \n" //11 -" float attenuation; // computed attenuation factor \n" //12 -" float d; // distance from surface to light source \n" //13 -" vec3 VP; // direction from surface to light position \n" //14 -" vec3 halfVector; // direction of maximum highlights \n" //15 -" \n" //16 -" // Compute vector from surface to light position \n" //17 -" VP = vec3(gl_LightSource[i].position) - position; \n" //18 -" \n" //19 -" // Compute distance between surface and light position \n" //20 -" d = length(VP); \n" //21 -" \n" //22 -" // Normalize the vector from surface to light position \n" //23 -" VP = normalize(VP); \n" //24 -" \n" //25 -" // Compute attenuation \n" //26 -" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + \n" //27 -" gl_LightSource[i].linearAttenuation * d + \n" //28 -" gl_LightSource[i].quadraticAttenuation * d*d); \n" //29 -" \n" //30 -" halfVector = normalize(VP + eye); \n" //31 -" \n" //32 -" nDotVP = max(0.0, dot(normal, VP)); \n" //33 -" nDotHV = max(0.0, dot(normal, halfVector)); \n" //34 -" \n" //35 -" if (nDotVP == 0.0) \n" //36 -" pf = 0.0; \n" //37 -" else \n" //38 -" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //39 -" \n" //40 -" ambient += gl_LightSource[i].ambient * attenuation; \n" //41 -" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; \n" //42 -" specular += gl_LightSource[i].specular * pf * attenuation; \n" //43 -"} \n";//44 - -char DirectionalLightShaderSource[] = -"void DirectionalLight(in int i, \n" //1 -" in vec3 normal, \n" //2 -" inout vec4 ambient, \n" //3 -" inout vec4 diffuse, \n" //4 -" inout vec4 specular) \n" //5 -"{ \n" //6 -" float nDotVP; // normal . light direction \n" //7 -" float nDotHV; // normal . light half vector \n" //8 -" float pf; // power factor \n" //9 -" \n" //10 -" nDotVP = max(0.0, dot(normal, \n" //11 -" normalize(vec3(gl_LightSource[i].position)))); \n" //12 -" nDotHV = max(0.0, dot(normal, \n" //13 -" vec3(gl_LightSource[i].halfVector))); \n" //14 -" \n" //15 -" if (nDotVP == 0.0) \n" //16 -" pf = 0.0; \n" //17 -" else \n" //18 -" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //19 -" \n" //20 -" ambient += gl_LightSource[i].ambient; \n" //21 -" diffuse += gl_LightSource[i].diffuse * nDotVP; \n" //22 -" specular += gl_LightSource[i].specular * pf; \n" //23 -"} \n";//24 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VirtualProgram.h" + +using osgCandidate::VirtualProgram; + +//////////////////////////////////////////////////////////////////////////////// +// Example shaders assume: +// one texture +// one directional light +// front face lighting +// color material mode not used (its not supported by GLSL anyway) +// diffuse/ambient/emissive/specular factors defined in material structure +// all coords and normal except gl_Position are in view space +//////////////////////////////////////////////////////////////////////////////// + +char MainVertexShaderSource[] = +"vec4 texture( in vec3 position, in vec3 normal ); \n" //1 +"void lighting( in vec3 position, in vec3 normal ); \n" //2 +" \n" //3 +"void main () \n" //4 +"{ \n" //5 +" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" //6 +" vec4 position4 = gl_ModelViewMatrix * gl_Vertex; \n" //7 +" vec3 position = position4.xyz / position4.w; \n" //8 +" vec3 normal = normalize( gl_NormalMatrix * gl_Normal ); \n" //9 +" gl_TexCoord[0] = texture( position, normal ); \n" //10 +" lighting( position, normal ); \n" //11 +"} \n";//12 + +char TexCoordTextureVertexShaderSource[] = +"vec4 texture( in vec3 position, in vec3 normal ) \n" //1 +"{ \n" //2 +" return gl_TextureMatrix[0] * gl_MultiTexCoord0; \n" //3 +"} \n";//4 + +char SphereMapTextureVertexShaderSource[] = +"vec4 texture( in vec3 position, in vec3 normal ) \n" //1 +"{ \n" //2 +" vec3 u = normalize( position ); \n" //3 +" vec3 r = reflect(u, normal); \n" //4 +" float m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z+1.0) * (r.z+1.0)); \n" //5 +" return vec4(r.x / m + 0.5, r.y / m + 0.5, 1.0, 1.0 ); \n" //6 +"} \n";//7 + +char PerVertexDirectionalLightingVertexShaderSource[] = +"void lighting( in vec3 position, in vec3 normal ) \n" //1 +"{ \n" //2 +" float NdotL = dot( normal, normalize(gl_LightSource[0].position.xyz) );\n" //3 +" NdotL = max( 0.0, NdotL ); \n" //4 +" float NdotHV = dot( normal, gl_LightSource[0].halfVector.xyz ); \n" //5 +" NdotHV = max( 0.0, NdotHV ); \n" //6 +" \n" //7 +" gl_FrontColor = gl_FrontLightModelProduct.sceneColor + \n" //8 +" gl_FrontLightProduct[0].ambient + \n" //9 +" gl_FrontLightProduct[0].diffuse * NdotL; \n" //10 +" \n" //11 +" gl_FrontSecondaryColor = vec4(0.0); \n" //12 +" \n" //13 +" if ( NdotL * NdotHV > 0.0 ) \n" //14 +" gl_FrontSecondaryColor = gl_FrontLightProduct[0].specular * \n" //15 +" pow( NdotHV, gl_FrontMaterial.shininess );\n" //16 +" \n" //17 +" gl_BackColor = gl_FrontColor; \n" //18 +" gl_BackSecondaryColor = gl_FrontSecondaryColor; \n" //19 +"} \n";//20 + +char MainFragmentShaderSource[] = +"vec4 texture( void ); \n" //1 +"void lighting( inout vec4 color ); \n" //2 +" \n" //3 +"void main () \n" //4 +"{ \n" //5 +" vec4 color = texture(); \n" //6 +" lighting( color ); \n" //7 +" gl_FragColor = color; \n" //8 +"} \n";//9 + +char TextureFragmentShaderSource[] = +"uniform sampler2D baseTexture; \n" //1 +"vec4 texture( void ) \n" //2 +"{ \n" //3 +" return texture2D( baseTexture, gl_TexCoord[0].xy ); \n" //4 +"} \n";//5 + +char ProceduralBlueTextureFragmentShaderSource[] = +"vec4 texture( void ) \n" //1 +"{ \n" //2 +" return vec4( 0.3, 0.3, 1.0, 1.0 ); \n" //3 +"} \n";//4 + +char PerVertexLightingFragmentShaderSource[] = +"void lighting( inout vec4 color ) \n" //1 +"{ \n" //2 +" color = color * gl_Color + gl_SecondaryColor; \n" //3 +"} \n";//4 + +char PerFragmentLightingVertexShaderSource[] = +"varying vec3 Normal; \n" //1 +"varying vec3 Position; \n" //2 +" \n" //3 +"void lighting( in vec3 position, in vec3 normal ) \n" //4 +"{ \n" //5 +" Normal = normal; \n" //6 +" Position = position; \n" //7 +"} \n";//8 + +char PerFragmentDirectionalLightingFragmentShaderSource[] = +"varying vec3 Normal; \n" //1 +"varying vec3 Position; // not used for directional lighting \n" //2 +" \n" //3 +"void lighting( inout vec4 color ) \n" //4 +"{ \n" //5 +" vec3 n = normalize( Normal ); \n" //5 +" float NdotL = dot( n, normalize(gl_LightSource[0].position.xyz) ); \n" //6 +" NdotL = max( 0.0, NdotL ); \n" //7 +" float NdotHV = dot( n, gl_LightSource[0].halfVector.xyz ); \n" //8 +" NdotHV = max( 0.0, NdotHV ); \n" //9 +" \n" //10 +" color *= gl_FrontLightModelProduct.sceneColor + \n" //11 +" gl_FrontLightProduct[0].ambient + \n" //12 +" gl_FrontLightProduct[0].diffuse * NdotL; \n" //13 +" \n" //14 +" if ( NdotL * NdotHV > 0.0 ) \n" //15 +" color += gl_FrontLightProduct[0].specular * \n" //16 +" pow( NdotHV, gl_FrontMaterial.shininess ); \n" //17 +"} \n";//18 + +//////////////////////////////////////////////////////////////////////////////// +osg::Node * CreateModel( const char * file ) +{ + if ( file ) { + osg::Node * node = NULL; + node = osgDB::readNodeFile( file ); + if( node ) + return node; + } + + // File not found - create textured sphere + osg::Geode * geode = new osg::Geode; + osg::ref_ptr hints = new osg::TessellationHints; + hints->setDetailRatio( 0.3 ); + +#if 1 + osg::ref_ptr shape = new osg::ShapeDrawable + ( new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 4.0 ), hints.get() ); +#else + osg::ref_ptr shape = new osg::ShapeDrawable + ( new osg::Box( osg::Vec3(-1.0f, -1.0f, -1.0f), 2.0, 2.0, 2.0 ) ); +#endif + + shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f)); + + geode->addDrawable( shape.get() ); + + osg::StateSet * stateSet = new osg::StateSet; + + osg::Texture2D * texture = new osg::Texture2D( + osgDB::readImageFile("Images/land_shallow_topo_2048.jpg") + ); + + osg::Material * material = new osg::Material; + + material->setAmbient + ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) ); + + material->setDiffuse + ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) ); + +#if 1 + material->setSpecular + ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.7, 0.3, 0.3, 1.0 ) ); + + material->setShininess( osg::Material::FRONT_AND_BACK, 25 ); + +#endif + + stateSet->setAttributeAndModes( material ); + stateSet->setTextureAttributeAndModes( 0,texture, osg::StateAttribute::ON ); + + geode->setStateSet( stateSet ); + return geode; +} +//////////////////////////////////////////////////////////////////////////////// +// Convenience method to simplify code a little ... +void SetVirtualProgramShader( VirtualProgram * virtualProgram, + std::string shader_semantics, + osg::Shader::Type shader_type, + std::string shader_name, + std::string shader_source ) +{ + osg::Shader * shader = new osg::Shader( shader_type ); + shader->setName( shader_name ); + shader->setShaderSource( shader_source ); + virtualProgram->setShader( shader_semantics, shader ); +} +/////////////////////////////////////////////////////////////////////////////// +void AddLabel( osg::Group * group, const std::string & label, float offset ) +{ + osg::Vec3 center( 0, 0, offset * 0.5 ); + osg::Geode * geode = new osg::Geode; + + // Make sure no program breaks text outputs + geode->getOrCreateStateSet()->setAttribute + ( new osg::Program, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); + + // Turn off stage 1 texture set in parent transform (otherwise it darkens text) + geode->getOrCreateStateSet()->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OFF ); + + group->addChild( geode ); + + osgText::Text* text = new osgText::Text; + geode->addDrawable( text ); + text->setFont("fonts/times.ttf"); + text->setCharacterSize( offset * 0.1 ); + text->setPosition(center); + text->setAlignment( osgText::TextBase::CENTER_CENTER ); + text->setAxisAlignment(osgText::Text::SCREEN); + + osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f); +#if 1 + // reproduce outline bounding box compute problem with backdrop on. + text->setBackdropType(osgText::Text::OUTLINE); + text->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX); +#endif + + text->setText( label ); +} +//////////////////////////////////////////////////////////////////////////////// +osg::Node * CreateAdvancedHierarchy( const char * file = NULL ) +{ + osg::Node * model = CreateModel( file ); + if( !model ) return NULL; + float offset = model->getBound().radius() * 1.3; // diameter + + // Create transforms for translated instances of the model + osg::MatrixTransform * transformCenterMiddle = new osg::MatrixTransform( ); + transformCenterMiddle->setMatrix( osg::Matrix::translate( 0,0, offset * 0.5 ) ); + transformCenterMiddle->addChild( model ); + + osg::MatrixTransform * transformCenterTop = new osg::MatrixTransform( ); + transformCenterMiddle->addChild( transformCenterTop ); + transformCenterTop->setMatrix( osg::Matrix::translate( 0,0,offset ) ); + transformCenterTop->addChild( model ); + + osg::MatrixTransform * transformCenterBottom = new osg::MatrixTransform( ); + transformCenterMiddle->addChild( transformCenterBottom ); + transformCenterBottom->setMatrix( osg::Matrix::translate( 0,0,-offset ) ); + transformCenterBottom->addChild( model ); + + osg::MatrixTransform * transformLeftBottom = new osg::MatrixTransform( ); + transformCenterBottom->addChild( transformLeftBottom ); + transformLeftBottom->setMatrix( osg::Matrix::translate( -offset * 0.8,0, -offset * 0.8 ) ); + transformLeftBottom->addChild( model ); + + osg::MatrixTransform * transformRightBottom = new osg::MatrixTransform( ); + transformCenterBottom->addChild( transformRightBottom ); + transformRightBottom->setMatrix( osg::Matrix::translate( offset * 0.8,0, -offset * 0.8 ) ); + transformRightBottom->addChild( model ); + + // Set default VirtualProgram in root StateSet + // With main vertex and main fragment shaders calling + // lighting and texture functions defined in aditional shaders + // Lighting is done per vertex using simple directional light + // Texture uses stage 0 TexCoords and TexMap + + if( 1 ) + { + // NOTE: + // duplicating the same semantics name in virtual program + // is only possible if its used for shaders of differing types + // here for VERTEX and FRAGMENT + + VirtualProgram * vp = new VirtualProgram( ); + transformCenterMiddle->getOrCreateStateSet()->setAttribute( vp ); + AddLabel( transformCenterMiddle, "Per Vertex Lighting Virtual Program", offset ); + + SetVirtualProgramShader( vp, "main", osg::Shader::VERTEX, + "Vertex Main", MainVertexShaderSource ); + + SetVirtualProgramShader( vp, "main", osg::Shader::FRAGMENT, + "Fragment Main", MainFragmentShaderSource ); + + SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX, + "Vertex Texture Coord 0", TexCoordTextureVertexShaderSource ); + + SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT, + "Fragment Texture", TextureFragmentShaderSource ); + + SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX, + "Vertex Lighting", PerVertexDirectionalLightingVertexShaderSource ); + + SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT, + "Fragment Lighting", PerVertexLightingFragmentShaderSource ); + + transformCenterMiddle->getOrCreateStateSet()-> + addUniform( new osg::Uniform( "baseTexture", 0 ) ); + + } + + // Override default vertex ligting with pixel lighting shaders + // For three bottom models + if( 1 ) + { + AddLabel( transformCenterBottom, "Per Pixel Lighting VP", offset ); + VirtualProgram * vp = new VirtualProgram( ); + transformCenterBottom->getOrCreateStateSet()->setAttribute( vp ); + + SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX, + "Vertex Shader For Per Pixel Lighting", + PerFragmentLightingVertexShaderSource ); + + SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT, + "Fragment Shader For Per Pixel Lighting", + PerFragmentDirectionalLightingFragmentShaderSource ); + } + + // Additionaly set bottom left model texture to procedural blue to + // better observe smooth speculars done through per pixel lighting + if( 1 ) + { + AddLabel( transformLeftBottom, "Blue Tex VP", offset ); + VirtualProgram * vp = new VirtualProgram( ); + transformLeftBottom->getOrCreateStateSet()->setAttribute( vp ); + + SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT, + "Fragment Shader Procedural Blue Tex", + ProceduralBlueTextureFragmentShaderSource ); + } + + // Additionaly change texture mapping to SphereMAp in bottom right model + if( 1 ) + { + AddLabel( transformRightBottom, "EnvMap Sphere VP", offset ); + + osg::StateSet * ss = transformRightBottom->getOrCreateStateSet(); + VirtualProgram * vp = new VirtualProgram( ); + ss->setAttribute( vp ); + SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX, + "Vertex Texture Sphere Map", SphereMapTextureVertexShaderSource ); + + osg::Texture2D * texture = new osg::Texture2D( +// osgDB::readImageFile("Images/reflect.rgb") + osgDB::readImageFile("Images/skymap.jpg") + ); + + // Texture is set on stage 1 to not interfere with label text + // The same could be achieved with texture override + // but such approach also turns off label texture + ss->setTextureAttributeAndModes( 1, texture, osg::StateAttribute::ON ); + ss->addUniform( new osg::Uniform( "baseTexture", 1 ) ); + +#if 0 // Could be useful with Fixed Vertex Pipeline + osg::TexGen * texGen = new osg::TexGen(); + texGen->setMode( osg::TexGen::SPHERE_MAP ); + + // Texture states applied + ss->setTextureAttributeAndModes( 1, texGen, osg::StateAttribute::ON ); +#endif + + } + + + // Top center model usues osg::Program overriding VirtualProgram in model + if( 1 ) + { + AddLabel( transformCenterTop, "Fixed Vertex + Simple Fragment osg::Program", offset ); + osg::Program * program = new osg::Program; + program->setName( "Trivial Fragment + Fixed Vertex Program" ); + + transformCenterTop->getOrCreateStateSet( )->setAttributeAndModes + ( program, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); + + osg::Shader * shader = new osg::Shader( osg::Shader::FRAGMENT ); + shader->setName( "Trivial Fragment Shader" ); + shader->setShaderSource( + "uniform sampler2D baseTexture; \n" + "void main(void) \n" + "{ \n" + " gl_FragColor = gl_Color * texture2D( baseTexture,gl_TexCoord[0].xy);\n" + "} \n" + ); + + program->addShader( shader ); + } + + return transformCenterMiddle; +} + +//////////////////////////////////////////////////////////////////////////////// +// Shders not used in the example but left for fun if anyone wants to play +char LightingVertexShaderSource[] = +"// Forward declarations \n" //1 +" \n" //2 +"void SpotLight( in int i, in vec3 eye, in vec3 position, in vec3 normal, \n" //3 +" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //4 +" \n" //5 +"void PointLight( in int i, in vec3 eye, in vec3 position, in vec3 normal, \n" //6 +" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //7 +" \n" //8 +"void DirectionalLight( in int i, in vec3 normal, \n" //9 +" inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //10 +" \n" //11 +"const int NumEnabledLights = 1; \n" //12 +" \n" //13 +"void lighting( in vec3 position, in vec3 normal ) \n" //14 +"{ \n" //15 +" vec3 eye = vec3( 0.0, 0.0, 1.0 ); \n" //16 +" //vec3 eye = -normalize(position); \n" //17 +" \n" //18 +" // Clear the light intensity accumulators \n" //19 +" vec4 amb = vec4(0.0); \n" //20 +" vec4 diff = vec4(0.0); \n" //21 +" vec4 spec = vec4(0.0); \n" //22 +" \n" //23 +" // Loop through enabled lights, compute contribution from each \n" //24 +" for (int i = 0; i < NumEnabledLights; i++) \n" //25 +" { \n" //26 +" if (gl_LightSource[i].position.w == 0.0) \n" //27 +" DirectionalLight(i, normal, amb, diff, spec); \n" //28 +" else if (gl_LightSource[i].spotCutoff == 180.0) \n" //29 +" PointLight(i, eye, position, normal, amb, diff, spec); \n" //30 +" else \n" //31 +" SpotLight(i, eye, position, normal, amb, diff, spec); \n" //32 +" } \n" //33 +" \n" //34 +" gl_FrontColor = gl_FrontLightModelProduct.sceneColor + \n" //35 +" amb * gl_FrontMaterial.ambient + \n" //36 +" diff * gl_FrontMaterial.diffuse; \n" //37 +" \n" //38 +" gl_FrontSecondaryColor = vec4(spec*gl_FrontMaterial.specular); \n" //39 +" \n" //40 +" gl_BackColor = gl_FrontColor; \n" //41 +" gl_BackSecondaryColor = gl_FrontSecondaryColor; \n" //42 +"} \n";//43 + +char SpotLightShaderSource[] = +"void SpotLight(in int i, \n" //1 +" in vec3 eye, \n" //2 +" in vec3 position, \n" //3 +" in vec3 normal, \n" //4 +" inout vec4 ambient, \n" //5 +" inout vec4 diffuse, \n" //6 +" inout vec4 specular) \n" //7 +"{ \n" //8 +" float nDotVP; // normal . light direction \n" //9 +" float nDotHV; // normal . light half vector \n" //10 +" float pf; // power factor \n" //11 +" float spotDot; // cosine of angle between spotlight \n" //12 +" float spotAttenuation; // spotlight attenuation factor \n" //13 +" float attenuation; // computed attenuation factor \n" //14 +" float d; // distance from surface to light source \n" //15 +" vec3 VP; // direction from surface to light position \n" //16 +" vec3 halfVector; // direction of maximum highlights \n" //17 +" \n" //18 +" // Compute vector from surface to light position \n" //19 +" VP = vec3(gl_LightSource[i].position) - position; \n" //20 +" \n" //21 +" // Compute distance between surface and light position \n" //22 +" d = length(VP); \n" //23 +" \n" //24 +" // Normalize the vector from surface to light position \n" //25 +" VP = normalize(VP); \n" //26 +" \n" //27 +" // Compute attenuation \n" //28 +" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + \n" //29 +" gl_LightSource[i].linearAttenuation * d + \n" //30 +" gl_LightSource[i].quadraticAttenuation *d*d); \n" //31 +" \n" //32 +" // See if point on surface is inside cone of illumination \n" //33 +" spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection)); \n" //34 +" \n" //35 +" if (spotDot < gl_LightSource[i].spotCosCutoff) \n" //36 +" spotAttenuation = 0.0; // light adds no contribution \n" //37 +" else \n" //38 +" spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent); \n" //39 +" \n" //40 +" // Combine the spotlight and distance attenuation. \n" //41 +" attenuation *= spotAttenuation; \n" //42 +" \n" //43 +" halfVector = normalize(VP + eye); \n" //44 +" \n" //45 +" nDotVP = max(0.0, dot(normal, VP)); \n" //46 +" nDotHV = max(0.0, dot(normal, halfVector)); \n" //47 +" \n" //48 +" if (nDotVP == 0.0) \n" //49 +" pf = 0.0; \n" //50 +" else \n" //51 +" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //52 +" \n" //53 +" ambient += gl_LightSource[i].ambient * attenuation; \n" //54 +" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; \n" //55 +" specular += gl_LightSource[i].specular * pf * attenuation; \n" //56 +"} \n";//57 + +char PointLightShaderSource[] = +"void PointLight(in int i, \n" //1 +" in vec3 eye, \n" //2 +" in vec3 position, \n" //3 +" in vec3 normal, \n" //4 +" inout vec4 ambient, \n" //5 +" inout vec4 diffuse, \n" //6 +" inout vec4 specular) \n" //7 +"{ \n" //8 +" float nDotVP; // normal . light direction \n" //9 +" float nDotHV; // normal . light half vector \n" //10 +" float pf; // power factor \n" //11 +" float attenuation; // computed attenuation factor \n" //12 +" float d; // distance from surface to light source \n" //13 +" vec3 VP; // direction from surface to light position \n" //14 +" vec3 halfVector; // direction of maximum highlights \n" //15 +" \n" //16 +" // Compute vector from surface to light position \n" //17 +" VP = vec3(gl_LightSource[i].position) - position; \n" //18 +" \n" //19 +" // Compute distance between surface and light position \n" //20 +" d = length(VP); \n" //21 +" \n" //22 +" // Normalize the vector from surface to light position \n" //23 +" VP = normalize(VP); \n" //24 +" \n" //25 +" // Compute attenuation \n" //26 +" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + \n" //27 +" gl_LightSource[i].linearAttenuation * d + \n" //28 +" gl_LightSource[i].quadraticAttenuation * d*d); \n" //29 +" \n" //30 +" halfVector = normalize(VP + eye); \n" //31 +" \n" //32 +" nDotVP = max(0.0, dot(normal, VP)); \n" //33 +" nDotHV = max(0.0, dot(normal, halfVector)); \n" //34 +" \n" //35 +" if (nDotVP == 0.0) \n" //36 +" pf = 0.0; \n" //37 +" else \n" //38 +" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //39 +" \n" //40 +" ambient += gl_LightSource[i].ambient * attenuation; \n" //41 +" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; \n" //42 +" specular += gl_LightSource[i].specular * pf * attenuation; \n" //43 +"} \n";//44 + +char DirectionalLightShaderSource[] = +"void DirectionalLight(in int i, \n" //1 +" in vec3 normal, \n" //2 +" inout vec4 ambient, \n" //3 +" inout vec4 diffuse, \n" //4 +" inout vec4 specular) \n" //5 +"{ \n" //6 +" float nDotVP; // normal . light direction \n" //7 +" float nDotHV; // normal . light half vector \n" //8 +" float pf; // power factor \n" //9 +" \n" //10 +" nDotVP = max(0.0, dot(normal, \n" //11 +" normalize(vec3(gl_LightSource[i].position)))); \n" //12 +" nDotHV = max(0.0, dot(normal, \n" //13 +" vec3(gl_LightSource[i].halfVector))); \n" //14 +" \n" //15 +" if (nDotVP == 0.0) \n" //16 +" pf = 0.0; \n" //17 +" else \n" //18 +" pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" //19 +" \n" //20 +" ambient += gl_LightSource[i].ambient; \n" //21 +" diffuse += gl_LightSource[i].diffuse * nDotVP; \n" //22 +" specular += gl_LightSource[i].specular * pf; \n" //23 +"} \n";//24 +