Implemented ability to switch between different shaders with new MultipassTechnique

This commit is contained in:
Robert Osfield 2013-12-13 12:38:01 +00:00
parent 939aa38a2a
commit 5571c361dc
5 changed files with 318 additions and 91 deletions

View File

@ -1105,8 +1105,6 @@ int main( int argc, char **argv )
cp->addProperty(tfp); cp->addProperty(tfp);
} }
cp->addProperty(isop);
sp->addProperty(cp); sp->addProperty(cp);
} }

View File

@ -53,6 +53,22 @@ class OSGVOLUME_EXPORT MultipassTechnique : public VolumeTechnique
ModelViewMatrixMap _modelViewMatrixMap; ModelViewMatrixMap _modelViewMatrixMap;
osg::ref_ptr<osg::StateSet> _whenMovingStateSet; osg::ref_ptr<osg::StateSet> _whenMovingStateSet;
osg::StateSet* createStateSet(osg::StateSet* statesetPrototype, osg::Program* programPrototype, osg::Shader* shaderToAdd1=0, osg::Shader* shaderToAdd2=0);
enum ShaderMask
{
FRONT_SHADERS = 1,
BACK_SHADERS = 2,
STANDARD_SHADERS = 4,
LIT_SHADERS = 8,
ISO_SHADERS = 16,
MIP_SHADERS = 32,
TF_SHADERS = 64
};
typedef std::map<int, osg::ref_ptr<osg::StateSet> > StateSetMap;
StateSetMap _stateSetMap;
}; };
} }

View File

@ -145,10 +145,21 @@ Program::Program() :
Program::Program(const Program& rhs, const osg::CopyOp& copyop): Program::Program(const Program& rhs, const osg::CopyOp& copyop):
osg::StateAttribute(rhs, copyop) osg::StateAttribute(rhs, copyop)
{ {
if ((copyop.getCopyFlags()&osg::CopyOp::DEEP_COPY_STATEATTRIBUTES)!=0)
{
for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex ) for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex )
{ {
addShader( new osg::Shader( *rhs.getShader( shaderIndex ), copyop ) ); addShader( new osg::Shader( *rhs.getShader( shaderIndex ), copyop ) );
} }
}
else
{
for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex )
{
addShader( const_cast<osg::Shader*>(rhs.getShader( shaderIndex )) );
}
}
const osg::Program::AttribBindingList &abl = rhs.getAttribBindingList(); const osg::Program::AttribBindingList &abl = rhs.getAttribBindingList();
for( osg::Program::AttribBindingList::const_iterator attribute = abl.begin(); attribute != abl.end(); ++attribute ) for( osg::Program::AttribBindingList::const_iterator attribute = abl.begin(); attribute != abl.end(); ++attribute )

View File

@ -48,6 +48,17 @@ MultipassTechnique::~MultipassTechnique()
{ {
} }
osg::StateSet* MultipassTechnique::createStateSet(osg::StateSet* statesetPrototype, osg::Program* programPrototype, osg::Shader* shaderToAdd1, osg::Shader* shaderToAdd2)
{
osg::ref_ptr<osg::StateSet> stateset = osg::clone(statesetPrototype, osg::CopyOp::SHALLOW_COPY);
osg::ref_ptr<osg::Program> program = osg::clone(programPrototype, osg::CopyOp::SHALLOW_COPY);
stateset->setAttribute(program.get());
if (shaderToAdd1) program->addShader(shaderToAdd1);
if (shaderToAdd2) program->addShader(shaderToAdd2);
return stateset.release();
}
void MultipassTechnique::init() void MultipassTechnique::init()
{ {
OSG_INFO<<"MultipassTechnique::init()"<<std::endl; OSG_INFO<<"MultipassTechnique::init()"<<std::endl;
@ -72,7 +83,7 @@ void MultipassTechnique::init()
OSG_NOTICE<<"MultipassTechnique::init() Need to set up"<<std::endl; OSG_NOTICE<<"MultipassTechnique::init() Need to set up"<<std::endl;
CollectPropertiesVisitor cpv; CollectPropertiesVisitor cpv(false);
if (_volumeTile->getLayer()->getProperty()) if (_volumeTile->getLayer()->getProperty())
{ {
_volumeTile->getLayer()->getProperty()->accept(cpv); _volumeTile->getLayer()->getProperty()->accept(cpv);
@ -142,6 +153,7 @@ void MultipassTechnique::init()
} }
_transform = new osg::MatrixTransform; _transform = new osg::MatrixTransform;
_transform->addChild(geode.get());
// handle locators // handle locators
Locator* masterLocator = _volumeTile->getLocator(); Locator* masterLocator = _volumeTile->getLocator();
@ -215,7 +227,6 @@ void MultipassTechnique::init()
tf = dynamic_cast<osg::TransferFunction1D*>(cpv._tfProperty->getTransferFunction()); tf = dynamic_cast<osg::TransferFunction1D*>(cpv._tfProperty->getTransferFunction());
} }
#if 1
osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen; osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
texgen->setMode(osg::TexGen::OBJECT_LINEAR); texgen->setMode(osg::TexGen::OBJECT_LINEAR);
texgen->setPlanesFromMatrix( geometryMatrix * osg::Matrix::inverse(imageMatrix)); texgen->setPlanesFromMatrix( geometryMatrix * osg::Matrix::inverse(imageMatrix));
@ -231,7 +242,6 @@ void MultipassTechnique::init()
} }
stateset->setTextureAttributeAndModes(texgenTextureUnit, texgen.get(), osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(texgenTextureUnit, texgen.get(), osg::StateAttribute::ON);
#endif
} }
@ -317,6 +327,11 @@ void MultipassTechnique::init()
} }
// creates CullFace attributes to apply to front/back StateSet configurations.
osg::ref_ptr<osg::CullFace> front_CullFace = new osg::CullFace(osg::CullFace::BACK);
osg::ref_ptr<osg::CullFace> back_CullFace = new osg::CullFace(osg::CullFace::FRONT);
osg::ref_ptr<osg::Shader> computeRayColorShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_compute_ray_color.frag"); osg::ref_ptr<osg::Shader> computeRayColorShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_compute_ray_color.frag");
#if 0 #if 0
@ -327,95 +342,222 @@ void MultipassTechnique::init()
} }
#endif #endif
// set up the renderin of the front faces osg::ref_ptr<osg::Shader> main_vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass.vert");
{
osg::ref_ptr<osg::Group> front_face_group = new osg::Group;
front_face_group->addChild(geode.get());
_transform->addChild(front_face_group.get());
osg::ref_ptr<osg::StateSet> front_face_stateset = front_face_group->getOrCreateStateSet();
front_face_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON);
osg::ref_ptr<osg::Program> program = new osg::Program;
front_face_stateset->setAttribute(program);
// get vertex shaders from source
osg::ref_ptr<osg::Shader> vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass_front.vert");
if (vertexShader.valid())
{
program->addShader(vertexShader.get());
}
#if 0 #if 0
else if (!main_vertexShader)
{ {
#include "Shaders/volume_color_depth_vert.cpp" #include "Shaders/volume_multipass_vert.cpp"
program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert)); main_vertexShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_vert));
}
#endif
// get fragment shaders from source
osg::ref_ptr<osg::Shader> fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_front.frag");
if (fragmentShader.valid())
{
program->addShader(fragmentShader.get());
}
#if 0
else
{
#include "Shaders/volume_color_depth_frag.cpp"
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag));
} }
#endif #endif
if (computeRayColorShader.valid()) osg::ref_ptr<osg::Shader> front_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_front.frag");
{
program->addShader(computeRayColorShader.get());
}
}
// set up the rendering of the back faces
{
osg::ref_ptr<osg::Group> back_face_group = new osg::Group;
back_face_group->addChild(geode.get());
_transform->addChild(back_face_group.get());
osg::ref_ptr<osg::StateSet> back_face_stateset = back_face_group->getOrCreateStateSet();
back_face_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON);
osg::ref_ptr<osg::Program> program = new osg::Program;
back_face_stateset->setAttribute(program);
// get vertex shaders from source
osg::ref_ptr<osg::Shader> vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass_back.vert");
if (vertexShader.valid())
{
program->addShader(vertexShader.get());
}
#if 0 #if 0
else if (!front_main_fragmentShader)
{ {
#include "Shaders/volume_color_depth_vert.cpp" #include "Shaders/volume_multipass_front_frag.cpp"
program->addShader(new osg::Shader(osg::Shader::VERTEX, volume_color_depth_vert)); front_main_fragmentShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_front_frag));
} }
#endif #endif
// get fragment shaders from source
osg::ref_ptr<osg::Shader> fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back.frag");
if (fragmentShader.valid()) osg::ref_ptr<osg::Shader> back_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_back.frag");
{
program->addShader(fragmentShader.get());
}
#if 0 #if 0
else if (!back_main_fragmentShader)
{ {
#include "Shaders/volume_color_depth_frag.cpp" #include "Shaders/volume_multipass_back_frag.cpp"
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, volume_color_depth_frag)); back_main_fragmentShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_back_frag));
} }
#endif #endif
if (computeRayColorShader.valid())
// clear any previous settings
_stateSetMap.clear();
osg::ref_ptr<osg::StateSet> front_stateset_prototype = new osg::StateSet;
osg::ref_ptr<osg::Program> front_program_prototype = new osg::Program;
{ {
program->addShader(computeRayColorShader.get()); front_stateset_prototype->setAttributeAndModes(front_CullFace.get(), osg::StateAttribute::ON);
front_program_prototype->addShader(main_vertexShader.get());
front_program_prototype->addShader(front_main_fragmentShader.get());
front_program_prototype->addShader(computeRayColorShader.get());
} }
osg::ref_ptr<osg::StateSet> back_stateset_prototype = new osg::StateSet;
osg::ref_ptr<osg::Program> back_program_prototype = new osg::Program;
{
back_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON);
back_program_prototype->addShader(main_vertexShader.get());
back_program_prototype->addShader(back_main_fragmentShader.get());
back_program_prototype->addShader(computeRayColorShader.get());
}
// STANDARD_SHADERS
{
// STANDARD_SHADERS without TransferFunction
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_standard.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_standard_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_frag);
}
#endif
// front
_stateSetMap[STANDARD_SHADERS|FRONT_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[STANDARD_SHADERS|BACK_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
// STANDARD_SHADERS with TransferFunction
if (tf)
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_standard_tf.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_standard_tf_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_tf_frag);
}
#endif
// front
_stateSetMap[STANDARD_SHADERS|FRONT_SHADERS|TF_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[STANDARD_SHADERS|BACK_SHADERS|TF_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
}
// ISO_SHADERS
if (cpv._isoProperty.valid())
{
// ISO_SHADERS without TransferFunction
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_iso.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_iso_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_iso_frag);
}
#endif
// front
_stateSetMap[ISO_SHADERS|FRONT_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[ISO_SHADERS|BACK_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
// ISO_SHADERS with TransferFunction
if (tf)
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_iso_tf.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_standard_iso_tf_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_iso_tf_frag);
}
#endif
// front
_stateSetMap[ISO_SHADERS|FRONT_SHADERS|TF_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[ISO_SHADERS|BACK_SHADERS|TF_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
}
// MIP_SHADERS
if (cpv._mipProperty.valid())
{
// MIP_SHADERS without TransferFunction
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_mip.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_mip_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_mip_frag);
}
#endif
// front
_stateSetMap[MIP_SHADERS|FRONT_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[MIP_SHADERS|BACK_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
// MIP_SHADERS with TransferFunction
if (tf)
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_mip_tf.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_standard_mip_tf_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_mip_tf_frag);
}
#endif
// front
_stateSetMap[MIP_SHADERS|FRONT_SHADERS|TF_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[MIP_SHADERS|BACK_SHADERS|TF_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
}
// LIT_SHADERS
if (cpv._lightingProperty.valid())
{
// LIT_SHADERS without TransferFunction
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_lit.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_lit_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_lit_frag);
}
#endif
// front
_stateSetMap[LIT_SHADERS|FRONT_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[LIT_SHADERS|BACK_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
// MIP_SHADERS with TransferFunction
if (tf)
{
osg::ref_ptr<osg::Shader> accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_lit_tf.frag");
#if 0
if (!accumulateSamplesShader)
{
#include "Shaders/volume_accumulateSamples_standard_lit_tf_frag.cpp";
accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_lit_tf_frag);
}
#endif
// front
_stateSetMap[LIT_SHADERS|FRONT_SHADERS|TF_SHADERS] = createStateSet(front_stateset_prototype.get(), front_program_prototype.get(), accumulateSamplesShader.get());
// back
_stateSetMap[LIT_SHADERS|BACK_SHADERS|TF_SHADERS] = createStateSet(back_stateset_prototype.get(), back_program_prototype.get(), accumulateSamplesShader.get());
}
} }
@ -441,17 +583,73 @@ void MultipassTechnique::cull(osgUtil::CullVisitor* cv)
if (postTraversal) if (postTraversal)
{ {
if (_whenMovingStateSet.valid() && isMoving(cv))
int shaderMask = 0;
if (_volumeTile->getLayer()->getProperty())
{ {
OSG_NOTICE<<"Using MovingStateSet"<<std::endl; CollectPropertiesVisitor cpv;
cv->pushStateSet(_whenMovingStateSet.get()); _volumeTile->getLayer()->getProperty()->accept(cpv);
_transform->accept(*cv);
cv->popStateSet(); if (cpv._tfProperty.valid())
{
shaderMask |= TF_SHADERS;
}
if (cpv._isoProperty.valid())
{
shaderMask |= ISO_SHADERS;
}
else if (cpv._mipProperty.valid())
{
shaderMask |= MIP_SHADERS;
}
else if (cpv._lightingProperty.valid())
{
shaderMask |= LIT_SHADERS;
} }
else else
{ {
OSG_NOTICE<<"NOT using MovingStateSet"<<std::endl; shaderMask |= STANDARD_SHADERS;
}
}
int shaderMaskFront = shaderMask | FRONT_SHADERS;
int shaderMaskBack = shaderMask | BACK_SHADERS;
OSG_NOTICE<<"shaderMaskFront "<<shaderMaskFront<<std::endl;
OSG_NOTICE<<"shaderMaskBack "<<shaderMaskBack<<std::endl;
osg::ref_ptr<osg::StateSet> front_stateset = _stateSetMap[shaderMaskFront];
osg::ref_ptr<osg::StateSet> back_stateset = _stateSetMap[shaderMaskBack];
osg::ref_ptr<osg::StateSet> moving_stateset = (_whenMovingStateSet.valid() && isMoving(cv)) ? _whenMovingStateSet : 0;
if (moving_stateset.valid())
{
// OSG_NOTICE<<"Using MovingStateSet"<<std::endl;
cv->pushStateSet(moving_stateset.get());
}
if (front_stateset.valid())
{
OSG_NOTICE<<"Have front stateset"<<std::endl;
cv->pushStateSet(front_stateset.get());
_transform->accept(*cv); _transform->accept(*cv);
cv->popStateSet();
}
if (back_stateset.valid())
{
OSG_NOTICE<<"Have back stateset"<<std::endl;
cv->pushStateSet(back_stateset.get());
_transform->accept(*cv);
cv->popStateSet();
}
if (moving_stateset.valid())
{
// OSG_NOTICE<<"Using MovingStateSet"<<std::endl;
cv->popStateSet();
} }
} }
else else

View File

@ -13,6 +13,7 @@
#include <osgVolume/Property> #include <osgVolume/Property>
#include <osgVolume/VolumeTile> #include <osgVolume/VolumeTile>
#include <osgVolume/RayTracedTechnique>
using namespace osgVolume; using namespace osgVolume;
@ -400,11 +401,14 @@ bool PropertyAdjustmentCallback::handle(const osgGA::GUIEventAdapter& ea,osgGA::
CycleSwitchVisitor csv( (ea.getKey()==_cyleForwardKey) ? 1 : -1); CycleSwitchVisitor csv( (ea.getKey()==_cyleForwardKey) ? 1 : -1);
property->accept(csv); property->accept(csv);
if (csv._switchModified) if (csv._switchModified)
{
if (dynamic_cast<osgVolume::RayTracedTechnique*>(tile->getVolumeTechnique()))
{ {
tile->setDirty(true); tile->setDirty(true);
tile->init(); tile->init();
} }
} }
}
else if (ea.getKey()==_transparencyKey) _updateTransparency = passOnUpdates = true; else if (ea.getKey()==_transparencyKey) _updateTransparency = passOnUpdates = true;
else if (ea.getKey()==_alphaFuncKey) _updateAlphaCutOff = passOnUpdates = true; else if (ea.getKey()==_alphaFuncKey) _updateAlphaCutOff = passOnUpdates = true;
else if (ea.getKey()==_sampleDensityKey) _updateSampleDensity = passOnUpdates = true; else if (ea.getKey()==_sampleDensityKey) _updateSampleDensity = passOnUpdates = true;