Added basic code injection fields to osg::Shader,

creation of main shader to ShaderComposer and
collection of ShaderComponent to osg::State.
Also added very basic shader set up in osgshadecomposition example.
This commit is contained in:
Robert Osfield 2010-07-05 16:32:58 +00:00
parent 9f8670f50d
commit 751b0498fe
7 changed files with 194 additions and 56 deletions

View File

@ -29,6 +29,30 @@ osg::Node* createSceneGraph(osg::ArgumentParser& arguments)
osg::ShaderAttribute* sa = new osg::ShaderAttribute; osg::ShaderAttribute* sa = new osg::ShaderAttribute;
stateset->setAttribute(sa); stateset->setAttribute(sa);
{
const char shader_str[] =
"vec4 colour()\n"
"{\n"
" return vec4(1.0,0.5,1.0,1.0);\n"
"}\n";
osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, shader_str);
vertex_shader->addCodeInjection(-1,"varying vec4 c;\n");
vertex_shader->addCodeInjection(-1,"vec4 colour();\n");
vertex_shader->addCodeInjection(0,"gl_Position = ftransform();\n");
vertex_shader->addCodeInjection(0,"c = colour();\n");
sa->addShader(vertex_shader);
}
{
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT);
fragment_shader->addCodeInjection(-1,"varying vec4 c;\n");
fragment_shader->addCodeInjection(0,"gl_FragColor = c;\n");
sa->addShader(fragment_shader);
}
return node; return node;
} }
@ -43,5 +67,17 @@ int main( int argc, char **argv )
viewer.setSceneData(scenegraph.get()); viewer.setSceneData(scenegraph.get());
viewer.realize();
// enable shader composition
osgViewer::Viewer::Windows windows;
viewer.getWindows(windows);
for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
itr != windows.end();
++itr)
{
(*itr)->getState()->setShaderCompositionEnabled(true);
}
return viewer.run(); return viewer.run();
} }

View File

@ -25,6 +25,7 @@
#include <osg/buffered_value> #include <osg/buffered_value>
#include <set> #include <set>
#include <map>
namespace osg { namespace osg {
@ -143,6 +144,24 @@ class OSG_EXPORT Shader : public osg::Object
bool loadShaderSourceFromFile( const std::string& fileName ); bool loadShaderSourceFromFile( const std::string& fileName );
/** The code injection map used when generating the main shader during main shader composition.*/
typedef std::multimap<float, std::string> CodeInjectionMap;
/** Add code injection that will be placed in the main shader to enable support for this shader.
* The position is set up so that code to be inserted before the main() will have a negative value,
* a position between 0 and 1.0 will be inserted in main() and a position greater than 1.0 will
* be placed after the main().
* During shader composition all the code injections are sorted in ascending order and then
* placed in the appropriate section of the main shader. */
void addCodeInjection(float position, const std::string& code) { _codeInjectionMap.insert(CodeInjectionMap::value_type(position, code)); }
/** Get the code injection map.*/
CodeInjectionMap& getCodeInjectionMap() { return _codeInjectionMap; }
/** Get the const code injection map.*/
const CodeInjectionMap& getCodeInjectionMap() const { return _codeInjectionMap; }
/** Resize any per context GLObject buffers to specified size. */ /** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize); virtual void resizeGLObjectBuffers(unsigned int maxSize);
@ -243,6 +262,8 @@ class OSG_EXPORT Shader : public osg::Object
std::string _shaderSource; std::string _shaderSource;
osg::ref_ptr<ShaderBinary> _shaderBinary; osg::ref_ptr<ShaderBinary> _shaderBinary;
CodeInjectionMap _codeInjectionMap;
/** osg::Programs that this osg::Shader is attached to */ /** osg::Programs that this osg::Shader is attached to */
typedef std::set< osg::Program* > ProgramSet; typedef std::set< osg::Program* > ProgramSet;
ProgramSet _programSet; ProgramSet _programSet;

View File

@ -38,11 +38,13 @@ class OSG_EXPORT ShaderComposer : public osg::Object
typedef std::vector< const osg::Shader* > Shaders; typedef std::vector< const osg::Shader* > Shaders;
virtual osg::Shader* composeMain(const Shaders& shaders); virtual osg::Shader* composeMain(const Shaders& shaders);
virtual void addShaderToProgram(Program* program, const Shaders& shaders);
protected: protected:
virtual ~ShaderComposer(); virtual ~ShaderComposer();
typedef std::map< ShaderComponents, ref_ptr<Program> > ProgramMap; typedef std::map< ShaderComponents, ref_ptr<Program> > ProgramMap;
ProgramMap _programMap; ProgramMap _programMap;

View File

@ -142,6 +142,12 @@ class OSG_EXPORT State : public Referenced, public Observer
inline unsigned int getContextID() const { return _contextID; } inline unsigned int getContextID() const { return _contextID; }
/* Set whether shader composition is enabled.*/
void setShaderCompositionEnabled(bool flag) { _shaderCompositionEnabled = flag; }
/* Get whether shader composition is enabled.*/
bool getShaderCompositionEnabled() const { return _shaderCompositionEnabled; }
/** Set the ShaderComposor object that implements shader composition.*/ /** Set the ShaderComposor object that implements shader composition.*/
void setShaderComposer(ShaderComposer* sc) { _shaderComposer = sc; } void setShaderComposer(ShaderComposer* sc) { _shaderComposer = sc; }
@ -250,6 +256,8 @@ class OSG_EXPORT State : public Referenced, public Observer
*/ */
void apply(); void apply();
/** Apply any shader composed state.*/
void applyShaderComposition();
/** Set whether a particular OpenGL mode is valid in the current graphics context. /** Set whether a particular OpenGL mode is valid in the current graphics context.
* Use to disable OpenGL modes that are not supported by current graphics drivers/context.*/ * Use to disable OpenGL modes that are not supported by current graphics drivers/context.*/

View File

@ -201,7 +201,8 @@ Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
_type(rhs._type), _type(rhs._type),
_shaderFileName(rhs._shaderFileName), _shaderFileName(rhs._shaderFileName),
_shaderSource(rhs._shaderSource), _shaderSource(rhs._shaderSource),
_shaderBinary(rhs._shaderBinary) _shaderBinary(rhs._shaderBinary),
_codeInjectionMap(rhs._codeInjectionMap)
{ {
} }

View File

@ -77,54 +77,19 @@ osg::Program* ShaderComposer::getOrCreateProgram(const ShaderComponents& shaderC
if (!vertexShaders.empty()) if (!vertexShaders.empty())
{ {
ShaderMainMap::iterator itr = _shaderMainMap.find(vertexShaders); addShaderToProgram(program.get(), vertexShaders);
if (itr == _shaderMainMap.end())
{
// no vertex shader in map yet, need to compose a new main shader
osg::Shader* mainShader = composeMain(vertexShaders);
_shaderMainMap[vertexShaders] = mainShader;
program->addShader(mainShader);
}
else
{
program->addShader(itr->second.get());
}
} }
if (!geometryShaders.empty()) if (!geometryShaders.empty())
{ {
ShaderMainMap::iterator itr = _shaderMainMap.find(geometryShaders); addShaderToProgram(program.get(), geometryShaders);
if (itr == _shaderMainMap.end())
{
// no vertex shader in map yet, need to compose a new main shader
osg::Shader* mainShader = composeMain(geometryShaders);
_shaderMainMap[geometryShaders] = mainShader;
program->addShader(mainShader);
}
else
{
program->addShader(itr->second.get());
}
} }
if (!fragmentShaders.empty()) if (!fragmentShaders.empty())
{ {
ShaderMainMap::iterator itr = _shaderMainMap.find(fragmentShaders); addShaderToProgram(program.get(), fragmentShaders);
if (itr == _shaderMainMap.end())
{
// no vertex shader in map yet, need to compose a new main shader
osg::Shader* mainShader = composeMain(fragmentShaders);
_shaderMainMap[fragmentShaders] = mainShader;
program->addShader(mainShader);
}
else
{
program->addShader(itr->second.get());
}
} }
// assign newly created program to map. // assign newly created program to map.
_programMap[shaderComponents] = program; _programMap[shaderComponents] = program;
@ -133,8 +98,93 @@ osg::Program* ShaderComposer::getOrCreateProgram(const ShaderComponents& shaderC
return program.get(); return program.get();
} }
void ShaderComposer::addShaderToProgram(Program* program, const Shaders& shaders)
{
ShaderMainMap::iterator itr = _shaderMainMap.find(shaders);
if (itr == _shaderMainMap.end())
{
// no vertex shader in map yet, need to compose a new main shader
osg::Shader* mainShader = composeMain(shaders);
_shaderMainMap[shaders] = mainShader;
program->addShader(mainShader);
}
else
{
program->addShader(itr->second.get());
}
for(Shaders::const_iterator itr = shaders.begin();
itr != shaders.end();
++itr)
{
Shader* shader = const_cast<Shader*>(*itr);
if (!(shader->getShaderSource().empty()) || shader->getShaderBinary())
{
program->addShader(shader);
}
}
}
osg::Shader* ShaderComposer::composeMain(const Shaders& shaders) osg::Shader* ShaderComposer::composeMain(const Shaders& shaders)
{ {
OSG_NOTICE<<"ShaderComposer::composeMain(Shaders) shaders.size()=="<<shaders.size()<<std::endl; OSG_NOTICE<<"ShaderComposer::composeMain(Shaders) shaders.size()=="<<shaders.size()<<std::endl;
return 0;
// collect the shader type and the code injection from each of the contributing shaders
Shader::Type type = Shader::UNDEFINED;
Shader::CodeInjectionMap codeInjectionMap;
for(Shaders::const_iterator itr = shaders.begin();
itr != shaders.end();
++itr)
{
const Shader* shader = *itr;
if (type == Shader::UNDEFINED)
{
type = shader->getType();
}
else if (type != shader->getType())
{
OSG_NOTICE<<"Warning:ShaderComposer::composeMain() mixing different types of Shaders prohibited."<<std::endl;
continue;
}
const Shader::CodeInjectionMap& cim = shader->getCodeInjectionMap();
for(Shader::CodeInjectionMap::const_iterator citr = cim.begin();
citr != cim.end();
++citr)
{
codeInjectionMap.insert(*citr);
}
}
// collect together the different parts of the main shader
std::string before_main;
std::string in_main;
std::string after_main;
for(Shader::CodeInjectionMap::iterator citr = codeInjectionMap.begin();
citr != codeInjectionMap.end();
++citr)
{
float position = citr->first;
if (position<0.0) before_main += citr->second;
else if (position<=1.0) in_main += citr->second;
else after_main += citr->second;
}
// assembly the final main shader source
std::string full_source;
full_source += before_main;
full_source += std::string("void main(void)\n");
full_source += std::string("{\n");
full_source += in_main;
full_source += std::string("}\n");
full_source += after_main;
ref_ptr<Shader> mainShader = new Shader(type, full_source);
_shaderMainMap[shaders] = mainShader;
return mainShader.get();
} }

View File

@ -42,7 +42,7 @@ State::State():
_graphicsContext = 0; _graphicsContext = 0;
_contextID = 0; _contextID = 0;
_shaderCompositionEnabled = false; // true; _shaderCompositionEnabled = false;
_shaderCompositionDirty = true; _shaderCompositionDirty = true;
_shaderComposer = new ShaderComposer; _shaderComposer = new ShaderComposer;
_currentShaderCompositionProgram = 0L; _currentShaderCompositionProgram = 0L;
@ -515,21 +515,7 @@ void State::apply(const StateSet* dstate)
else if (unit<_textureAttributeMapList.size()) applyAttributeMapOnTexUnit(unit,_textureAttributeMapList[unit]); else if (unit<_textureAttributeMapList.size()) applyAttributeMapOnTexUnit(unit,_textureAttributeMapList[unit]);
} }
if (_shaderCompositionEnabled) applyShaderComposition();
{
if (_shaderCompositionDirty)
{
// build lits of current ShaderComponents
ShaderComponents shaderComponents;
_currentShaderCompositionProgram = _shaderComposer->getOrCreateProgram(shaderComponents);
}
if (_currentShaderCompositionProgram)
{
Program::PerContextProgram* pcp = _currentShaderCompositionProgram->getPCP(_contextID);
if (_lastAppliedProgramObject != pcp) applyAttribute(_currentShaderCompositionProgram);
}
}
applyUniformList(_uniformMap,dstate->getUniformList()); applyUniformList(_uniformMap,dstate->getUniformList());
} }
@ -562,11 +548,45 @@ void State::apply()
if (unit<_textureAttributeMapList.size()) applyAttributeMapOnTexUnit(unit,_textureAttributeMapList[unit]); if (unit<_textureAttributeMapList.size()) applyAttributeMapOnTexUnit(unit,_textureAttributeMapList[unit]);
} }
applyShaderComposition();
applyUniformMap(_uniformMap); applyUniformMap(_uniformMap);
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors("end of State::apply()"); if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors("end of State::apply()");
} }
void State::applyShaderComposition()
{
if (_shaderCompositionEnabled)
{
if (_shaderCompositionDirty)
{
// build lits of current ShaderComponents
ShaderComponents shaderComponents;
for(AttributeMap::iterator itr = _attributeMap.begin();
itr != _attributeMap.end();
++itr)
{
AttributeStack& as = itr->second;
if (as.last_applied_shadercomponent)
{
shaderComponents.push_back(const_cast<ShaderComponent*>(as.last_applied_shadercomponent));
}
}
_currentShaderCompositionProgram = _shaderComposer->getOrCreateProgram(shaderComponents);
}
if (_currentShaderCompositionProgram)
{
Program::PerContextProgram* pcp = _currentShaderCompositionProgram->getPCP(_contextID);
if (_lastAppliedProgramObject != pcp) applyAttribute(_currentShaderCompositionProgram);
}
}
}
void State::haveAppliedMode(StateAttribute::GLMode mode,StateAttribute::GLModeValue value) void State::haveAppliedMode(StateAttribute::GLMode mode,StateAttribute::GLModeValue value)
{ {
haveAppliedMode(_modeMap,mode,value); haveAppliedMode(_modeMap,mode,value);