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:
parent
9f8670f50d
commit
751b0498fe
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.*/
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,53 +77,18 @@ 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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user