= Using OpenGL Shading Language Vertex and Fragment Shaders (Introduction) = [[TracNav(TracNav/SupportTOC)]] '''(Wiki editing note: Code needs conversion to osgViewer)'''[[BR]] '''(Wiki editing note: Add link to complete source code at bottom)''' == Goal == Replace the fixed-function pipeling lighting and texture calculations with an OpenGL Shading Language vertex and fragment program for selected nodes in the scene graph. (The procedural brick shader from 3Dlabs.) == Overview == OpenGL Shading Language allows programers to write custom pixel and vertex shaders. For more information on shading languages - including minimum hardware and software requirements - visit here. The osg::Program and osg::Shader module allow osg users to apply these shaders as part of a !StateSet to selected subtrees within a scene graph. Using a custom vertex or fragment shader in !OpenSceneGraph involves the following basic classes: 1. osg::Program - application level abstraction of the OpenGL Shading Language glProgramObject. The !ProgramObject class is derived from the osg::!StateAttribute class. This means that instance of the osg::Program class can be associated with !StateSets and enabled using the !StateSet class' setAttributeAndModes() method. Enabling a program object for a stateset results in drawables within that stateset being rendered using the Program's shaders. 2. osg::Shader - application level abstraction of the OpenGL Shading Language glShaderObject. This class manages loading and compiling shader source code. Instances of the osg::Shader class can be assigned to one or more osg::Program instances. There are two types of shader objects: osg::Shader::FRAGMENT and osg::Shader::VERTEX. == The code == The steps to create an application that uses an OpenGL pixel and fragment shader are as follows: * Create an osg::Program instance * Create VERTEX and FRAGMENT instances of the osg::Shader class * Load and compile the shader source * Add the shaders to the osg::Program instance * Associate and enable the osg::Program instance as part of a !StateSet. The code to load and apply a basic vertex and fragment shader is as follows: {{{ osg::StateSet* brickState = tankNode->getOrCreateStateSet(); osg::Program* brickProgramObject = new osg::Program; osg::Shader* brickVertexObject = new osg::Shader( osg::Shader::VERTEX ); osg::Shader* brickFragmentObject = new osg::Shader( osg::Shader::FRAGMENT ); brickProgramObject->addShader( brickFragmentObject ); brickProgramObject->addShader( brickVertexObject ); loadShaderSource( brickVertexObject, "shaders/brick.vert" ); loadShaderSource( brickFragmentObject, "shaders/brick.frag" ); brickState->setAttributeAndModes(brickProgramObject, osg::StateAttribute::ON); }}} The convenience function to load the source code for a shader and associate the compiled code with a shader object instance is as follows: {{{ bool loadShaderSource(osg::Shader* obj, const std::string& fileName ) { std::string fqFileName = osgDB::findDataFile(fileName); if( fqFileName.length() == 0 ) { std::cout << "File \"" << fileName << "\" not found." << std::endl; return false; } bool success = obj->loadShaderSourceFromFile( fqFileName.c_str()); if ( !success ) { std::cout << "Couldn't load file: " << fileName << std::endl; return false; } else { return true; } } }}}