/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace osgVolume { osg::Image* createDownsampledImage(osg::Image* sourceImage) { osg::ref_ptr targetImage = new osg::Image; int s_base = sourceImage->s()/2; int s_odd = (sourceImage->s()%2); int s = s_base + s_odd; int t_base = sourceImage->t()/2; int t_odd = (sourceImage->t()%2); int t = t_base + t_odd; int r_base = sourceImage->r()/2; int r_odd = (sourceImage->r()%2); int r = r_base + r_odd; OSG_NOTICE<<"createDownsampledImage("<s()<<", "<t()<<", "<r()<<")"<asCullVisitor(); cv->pushProjectionMatrix(_tileData->projectionMatrix.get()); // OSG_NOTICE<<"Traversing tile subgraph for pre-render "<<_mt->getVolumeTile()->getNumChildren()<getVolumeTile()->osg::Group::traverse(*cv); cv->popProjectionMatrix(); } protected: virtual ~RTTCameraCullCallback() {} osg::observer_ptr _tileData; osg::observer_ptr _mt; }; MultipassTechnique::MultipassTileData::MultipassTileData(osgUtil::CullVisitor* cv, MultipassTechnique* mpt): TileData(), multipassTechnique(mpt) { currentRenderingMode = mpt->computeRenderingMode(); int width = 512; int height = 512; osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); if (viewport) { width = static_cast(viewport->width()); height = static_cast(viewport->height()); } stateset = new osg::StateSet; eyeToTileUniform = new osg::Uniform("eyeToTile",osg::Matrixf()); stateset->addUniform(eyeToTileUniform.get()); tileToImageUniform = new osg::Uniform("tileToImage",osg::Matrixf()); stateset->addUniform(tileToImageUniform.get()); switch(currentRenderingMode) { case(MultipassTechnique::CUBE): { // no need to set up RTT Cameras; OSG_NOTICE<<"Setting up MultipassTileData for CUBE rendering"<setName("frontFaceRttCamera"); frontFaceRttCamera->setCullCallback(new RTTCameraCullCallback(this, mpt)); frontFaceRttCamera->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); stateset->setTextureAttribute(2, frontFaceDepthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); break; } case(MultipassTechnique::CUBE_AND_HULL): { OSG_NOTICE<<"Setting up MultipassTileData for CUBE_AND_HULL rendering"<setName("frontFaceRttCamera"); frontFaceRttCamera->setCullCallback(new RTTCameraCullCallback(this, mpt)); frontFaceRttCamera->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); setUp(backFaceRttCamera, backFaceDepthTexture, width, height); backFaceRttCamera->setName("backFaceRttCamera"); backFaceRttCamera->setCullCallback(new RTTCameraCullCallback(this, mpt)); backFaceRttCamera->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); stateset->setTextureAttribute(2, frontFaceDepthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); stateset->setTextureAttribute(3, backFaceDepthTexture.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); break; } } } void MultipassTechnique::MultipassTileData::setUp(osg::ref_ptr& camera, osg::ref_ptr& depthTexture, int width, int height) { depthTexture = new osg::Texture2D; depthTexture->setTextureSize(width, height); depthTexture->setInternalFormat(GL_DEPTH_COMPONENT); depthTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); depthTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); depthTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); depthTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); depthTexture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); camera = new osg::Camera; camera->attach(osg::Camera::DEPTH_BUFFER, depthTexture.get()); camera->setViewport(0, 0, width, height); // clear the depth and colour bufferson each clear. camera->setClearMask(GL_DEPTH_BUFFER_BIT); // set the camera to render before the main camera. camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->setReferenceFrame(osg::Transform::RELATIVE_RF); camera->setProjectionMatrix(osg::Matrixd::identity()); camera->setViewMatrix(osg::Matrixd::identity()); } void MultipassTechnique::MultipassTileData::update(osgUtil::CullVisitor* cv) { if (currentRenderingMode != multipassTechnique->computeRenderingMode()) { OSG_NOTICE<<"Warning: need to re-structure MP setup."<getNodePath(); projectionMatrix = cv->getProjectionMatrix(); modelviewMatrix = cv->getModelViewMatrix(); int width = 512; int height = 512; osg::Viewport* viewport = cv->getCurrentRenderStage()->getViewport(); if (viewport) { width = static_cast(viewport->width()); height = static_cast(viewport->height()); } if (frontFaceDepthTexture.valid()) { if (frontFaceDepthTexture->getTextureWidth()!=width || frontFaceDepthTexture->getTextureHeight()!=height) { OSG_NOTICE<<"Need to change texture size to "<setTextureSize(width, height); frontFaceRttCamera->setViewport(0, 0, width, height); if (frontFaceRttCamera->getRenderingCache()) { frontFaceRttCamera->getRenderingCache()->releaseGLObjects(0); } } } if (backFaceDepthTexture.valid()) { if (backFaceDepthTexture->getTextureWidth()!=width || backFaceDepthTexture->getTextureHeight()!=height) { OSG_NOTICE<<"Need to change texture size to "<setTextureSize(width, height); backFaceRttCamera->setViewport(0, 0, width, height); if (backFaceRttCamera->getRenderingCache()) { backFaceRttCamera->getRenderingCache()->releaseGLObjects(0); } } } } ///////////////////////////////////////////////////////////////////////////////////////// // // MultipassTechnique // MultipassTechnique::MultipassTechnique() { } MultipassTechnique::MultipassTechnique(const MultipassTechnique& fft,const osg::CopyOp& copyop): VolumeTechnique(fft,copyop) { } MultipassTechnique::~MultipassTechnique() { } osg::StateSet* MultipassTechnique::createStateSet(osg::StateSet* statesetPrototype, osg::Program* programPrototype, osg::Shader* shaderToAdd1, osg::Shader* shaderToAdd2) { osg::ref_ptr stateset = osg::clone(statesetPrototype, osg::CopyOp::SHALLOW_COPY); osg::ref_ptr 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(); } MultipassTechnique::RenderingMode MultipassTechnique::computeRenderingMode() { bool hasHull = (_volumeTile->getNumChildren()>0); if (!hasHull) { return CUBE; } CollectPropertiesVisitor cpv(false); if (_volumeTile->getLayer()->getProperty()) { _volumeTile->getLayer()->getProperty()->accept(cpv); } double etfValue = cpv._exteriorTransparencyFactorProperty.valid() ? cpv._exteriorTransparencyFactorProperty->getValue() : 0.0; if (etfValue<=0.0) { return HULL; } else if (etfValue<1.0) { return CUBE_AND_HULL; } else { return CUBE; } } void MultipassTechnique::init() { OSG_INFO<<"MultipassTechnique::init()"<getLayer()==0) { OSG_NOTICE<<"MultipassTechnique::init(), error no layer assigend to volume tile."<getLayer()->getImage()==0) { OSG_NOTICE<<"MultipassTechnique::init(), error no image assigned to layer."<getLayer()->getProperty()) { _volumeTile->getLayer()->getProperty()->accept(cpv); } osg::ref_ptr geode = new osg::Geode; { osg::Geometry* geom = new osg::Geometry; osg::Vec3Array* coords = new osg::Vec3Array(8); (*coords)[0] = osg::Vec3d(0.0,0.0,0.0); (*coords)[1] = osg::Vec3d(1.0,0.0,0.0); (*coords)[2] = osg::Vec3d(1.0,1.0,0.0); (*coords)[3] = osg::Vec3d(0.0,1.0,0.0); (*coords)[4] = osg::Vec3d(0.0,0.0,1.0); (*coords)[5] = osg::Vec3d(1.0,0.0,1.0); (*coords)[6] = osg::Vec3d(1.0,1.0,1.0); (*coords)[7] = osg::Vec3d(0.0,1.0,1.0); geom->setVertexArray(coords); osg::Vec4Array* colours = new osg::Vec4Array(1); (*colours)[0].set(1.0f,1.0f,1.0,1.0f); geom->setColorArray(colours, osg::Array::BIND_OVERALL); osg::DrawElementsUShort* drawElements = new osg::DrawElementsUShort(GL_QUADS); // bottom drawElements->push_back(3); drawElements->push_back(2); drawElements->push_back(1); drawElements->push_back(0); // bottom drawElements->push_back(7);//7623 drawElements->push_back(6); drawElements->push_back(2); drawElements->push_back(3); // left drawElements->push_back(4);//4730 drawElements->push_back(7); drawElements->push_back(3); drawElements->push_back(0); // right drawElements->push_back(1);//1265 drawElements->push_back(2); drawElements->push_back(6); drawElements->push_back(5); // front drawElements->push_back(5);//5401 drawElements->push_back(4); drawElements->push_back(0); drawElements->push_back(1); // top drawElements->push_back(4);//4567 drawElements->push_back(5); drawElements->push_back(6); drawElements->push_back(7); geom->addPrimitiveSet(drawElements); geode->addDrawable(geom); } _transform = new osg::MatrixTransform; _transform->addChild(geode.get()); // handle locators Locator* masterLocator = _volumeTile->getLocator(); Locator* layerLocator = _volumeTile->getLayer()->getLocator(); osg::TransferFunction1D* tf = 0; if (!masterLocator && layerLocator) masterLocator = layerLocator; if (!layerLocator && masterLocator) layerLocator = masterLocator; osg::Matrix geometryMatrix; if (masterLocator) { geometryMatrix = masterLocator->getTransform(); _transform->setMatrix(geometryMatrix); masterLocator->applyAppropriateFrontFace(_transform->getOrCreateStateSet()); masterLocator->addCallback(new TransformLocatorCallback(_transform.get())); } osg::Matrix imageMatrix; if (layerLocator) { imageMatrix = layerLocator->getTransform(); } OSG_NOTICE<<"MultipassTechnique::init() : geometryMatrix = "<addUniform(new osg::Uniform("depthTexture",1)); stateset->setMode(GL_ALPHA_TEST,osg::StateAttribute::ON); //stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF); float alphaFuncValue = 0.1; if (cpv._isoProperty.valid()) { alphaFuncValue = cpv._isoProperty->getValue(); } if (cpv._sampleRatioProperty.valid()) stateset->addUniform(cpv._sampleRatioProperty->getUniform()); else stateset->addUniform(new osg::Uniform("SampleRatioValue",1.0f)); if (cpv._transparencyProperty.valid()) stateset->addUniform(cpv._transparencyProperty->getUniform()); else stateset->addUniform(new osg::Uniform("TransparencyValue",1.0f)); if (cpv._exteriorTransparencyFactorProperty.valid()) stateset->addUniform(cpv._exteriorTransparencyFactorProperty->getUniform()); else stateset->addUniform(new osg::Uniform("ExteriorTransparencyFactorValue",0.0f)); if (cpv._afProperty.valid()) stateset->addUniform(cpv._afProperty->getUniform()); else stateset->addUniform(new osg::Uniform("AlphaFuncValue",alphaFuncValue)); if (cpv._isoProperty.valid()) stateset->addUniform(cpv._isoProperty->getUniform()); else stateset->addUniform(new osg::Uniform("IsoSurfaceValue",alphaFuncValue)); if (cpv._tfProperty.valid()) { tf = dynamic_cast(cpv._tfProperty->getTransferFunction()); } } // set up 3D texture osg::ref_ptr image_3d = _volumeTile->getLayer()->getImage(); // create a downsampled image to use when rendering at a lower quality. // osg::ref_ptr downsampled_image_3d = createDownsampledImage(image_3d.get()); //image_3d = createDownsampledImage(downsampled_image_3d.get()); // image_3d = downsampled_image_3d; osg::ref_ptr texture3D = new osg::Texture3D; { osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT; #define VOLUME_TYPE 2 #if VOLUME_TYPE==1 osg::Texture::FilterMode minFilter = osg::Texture::LINEAR_MIPMAP_LINEAR; osg::Texture::FilterMode magFilter = osg::Texture::LINEAR; #elif VOLUME_TYPE==2 osg::Texture::FilterMode minFilter = osg::Texture::LINEAR; osg::Texture::FilterMode magFilter = osg::Texture::LINEAR; #else osg::Texture::FilterMode minFilter = osg::Texture::NEAREST; osg::Texture::FilterMode magFilter = osg::Texture::NEAREST; #endif // set up the 3d texture itself, // note, well set the filtering up so that mip mapping is disabled, // gluBuild3DMipsmaps doesn't do a very good job of handled the // imbalanced dimensions of the 256x256x4 texture. texture3D->setResizeNonPowerOfTwoHint(false); texture3D->setFilter(osg::Texture3D::MIN_FILTER,minFilter); texture3D->setFilter(osg::Texture3D::MAG_FILTER, magFilter); texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::CLAMP_TO_BORDER); texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::CLAMP_TO_BORDER); texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::CLAMP_TO_BORDER); //texture3D->setMaxAnisotropy(16.0f); texture3D->setBorderColor(osg::Vec4(0.0,0.0,0.0,0.0)); if (image_3d->getPixelFormat()==GL_ALPHA || image_3d->getPixelFormat()==GL_LUMINANCE) { texture3D->setInternalFormatMode(osg::Texture3D::USE_USER_DEFINED_FORMAT); texture3D->setInternalFormat(GL_INTENSITY); } else { texture3D->setInternalFormatMode(internalFormatMode); } texture3D->setImage(image_3d.get()); stateset->setTextureAttributeAndModes(volumeTextureUnit, texture3D.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); osg::ref_ptr baseTextureSampler = new osg::Uniform("volumeTexture", int(volumeTextureUnit)); stateset->addUniform(baseTextureSampler.get()); osg::ref_ptr volumeCellSize = new osg::Uniform("volumeCellSize", osg::Vec3(1.0f/static_cast(image_3d->s()),1.0f/static_cast(image_3d->t()),1.0f/static_cast(image_3d->r()))); stateset->addUniform(volumeCellSize.get()); OSG_NOTICE<<"Texture Dimensions "<s()<<", "<t()<<", "<r()<(_volumeTile->getLayer()); if (imageLayer) { tfOffset = (imageLayer->getTexelOffset()[3] - tf->getMinimum()) / (tf->getMaximum() - tf->getMinimum()); tfScale = imageLayer->getTexelScale()[3] / (tf->getMaximum() - tf->getMinimum()); } else { tfOffset = -tf->getMinimum() / (tf->getMaximum()-tf->getMinimum()); tfScale = 1.0f / (tf->getMaximum()-tf->getMinimum()); } osg::ref_ptr tf_texture = new osg::Texture1D; tf_texture->setImage(tf->getImage()); tf_texture->setResizeNonPowerOfTwoHint(false); tf_texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); tf_texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); tf_texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_EDGE); stateset->setTextureAttributeAndModes(transferFunctionTextureUnit, tf_texture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->addUniform(new osg::Uniform("tfTexture",int(transferFunctionTextureUnit))); stateset->addUniform(new osg::Uniform("tfOffset",tfOffset)); stateset->addUniform(new osg::Uniform("tfScale",tfScale)); } // creates CullFace attributes to apply to front/back StateSet configurations. osg::ref_ptr front_CullFace = new osg::CullFace(osg::CullFace::BACK); osg::ref_ptr back_CullFace = new osg::CullFace(osg::CullFace::FRONT); osg::ref_ptr main_vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, "shaders/volume_multipass.vert"); if (!main_vertexShader) { #include "Shaders/volume_multipass_vert.cpp" main_vertexShader = new osg::Shader(osg::Shader::VERTEX, volume_multipass_vert); } osg::ref_ptr computeRayColorShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_compute_ray_color.frag"); if (!computeRayColorShader) { #include "Shaders/volume_compute_ray_color_frag.cpp" computeRayColorShader = new osg::Shader(osg::Shader::FRAGMENT, volume_compute_ray_color_frag); } // clear any previous settings _stateSetMap.clear(); // set up the program template for rendering just the cube osg::ref_ptr cube_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_cube.frag");; if (!cube_main_fragmentShader) { #include "Shaders/volume_multipass_cube_frag.cpp" cube_main_fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, volume_multipass_cube_frag); } osg::ref_ptr cube_stateset_prototype = new osg::StateSet; osg::ref_ptr cube_program_prototype = new osg::Program; { cube_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); cube_program_prototype->addShader(main_vertexShader.get()); cube_program_prototype->addShader(cube_main_fragmentShader.get()); cube_program_prototype->addShader(computeRayColorShader.get()); } // set up the program template for rendering just the hull osg::ref_ptr hull_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_hull.frag");; if (!hull_main_fragmentShader) { #include "Shaders/volume_multipass_hull_frag.cpp" hull_main_fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, volume_multipass_hull_frag); } osg::ref_ptr hull_stateset_prototype = new osg::StateSet; osg::ref_ptr hull_program_prototype = new osg::Program; { hull_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); hull_stateset_prototype->addUniform(new osg::Uniform("frontFaceDepthTexture",2)); hull_program_prototype->addShader(main_vertexShader.get()); hull_program_prototype->addShader(hull_main_fragmentShader.get()); hull_program_prototype->addShader(computeRayColorShader.get()); } // set up the program template for rendering just the cube osg::ref_ptr cube_and_hull_main_fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_multipass_cube_and_hull.frag");; if (!cube_and_hull_main_fragmentShader) { #include "Shaders/volume_multipass_cube_and_hull_frag.cpp" cube_and_hull_main_fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, volume_multipass_cube_and_hull_frag); } osg::ref_ptr cube_and_hull_stateset_prototype = new osg::StateSet; osg::ref_ptr cube_and_hull_program_prototype = new osg::Program; { cube_and_hull_stateset_prototype->setAttributeAndModes(back_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); cube_and_hull_stateset_prototype->addUniform(new osg::Uniform("frontFaceDepthTexture",2)); cube_and_hull_stateset_prototype->addUniform(new osg::Uniform("backFaceDepthTexture",3)); cube_and_hull_program_prototype->addShader(main_vertexShader.get()); cube_and_hull_program_prototype->addShader(cube_and_hull_main_fragmentShader.get()); cube_and_hull_program_prototype->addShader(computeRayColorShader.get()); } // set up the rendering of the front face { _frontFaceStateSet = new osg::StateSet; // cull only the bac faces so we write only the front _frontFaceStateSet->setAttributeAndModes(front_CullFace.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); // set up the front falce osg::ref_ptr program = new osg::Program; program->addShader(main_vertexShader.get()); _frontFaceStateSet->setAttribute(program.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } // STANDARD_SHADERS { // STANDARD_SHADERS without TransferFunction { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_standard.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_standard_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_frag); } _stateSetMap[STANDARD_SHADERS|CUBE_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[STANDARD_SHADERS|HULL_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[STANDARD_SHADERS|CUBE_AND_HULL_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } // STANDARD_SHADERS with TransferFunction if (tf) { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_standard_tf.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_standard_tf_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_standard_tf_frag); } _stateSetMap[STANDARD_SHADERS|CUBE_SHADERS|TF_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[STANDARD_SHADERS|HULL_SHADERS|TF_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[STANDARD_SHADERS|CUBE_AND_HULL_SHADERS|TF_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } } // ISO_SHADERS if (cpv._isoProperty.valid()) { // ISO_SHADERS without TransferFunction { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_iso.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_iso_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_iso_frag); } _stateSetMap[ISO_SHADERS|CUBE_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[ISO_SHADERS|HULL_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[ISO_SHADERS|CUBE_AND_HULL_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } // ISO_SHADERS with TransferFunction if (tf) { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_iso_tf.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_iso_tf_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_iso_tf_frag); } _stateSetMap[ISO_SHADERS|CUBE_SHADERS|TF_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[ISO_SHADERS|HULL_SHADERS|TF_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[ISO_SHADERS|CUBE_AND_HULL_SHADERS|TF_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } } // MIP_SHADERS if (cpv._mipProperty.valid()) { // MIP_SHADERS without TransferFunction { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_mip.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_mip_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_mip_frag); } _stateSetMap[MIP_SHADERS|CUBE_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[MIP_SHADERS|HULL_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[MIP_SHADERS|CUBE_AND_HULL_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } // MIP_SHADERS with TransferFunction if (tf) { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_mip_tf.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_mip_tf_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_mip_tf_frag); } _stateSetMap[MIP_SHADERS|CUBE_SHADERS|TF_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[MIP_SHADERS|HULL_SHADERS|TF_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[MIP_SHADERS|CUBE_AND_HULL_SHADERS|TF_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } } // LIT_SHADERS if (cpv._lightingProperty.valid()) { // LIT_SHADERS without TransferFunction { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_lit.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_lit_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_lit_frag); } _stateSetMap[LIT_SHADERS|CUBE_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[LIT_SHADERS|HULL_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[LIT_SHADERS|CUBE_AND_HULL_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } // MIP_SHADERS with TransferFunction if (tf) { osg::ref_ptr accumulateSamplesShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, "shaders/volume_accumulateSamples_lit_tf.frag"); if (!accumulateSamplesShader) { #include "Shaders/volume_accumulateSamples_lit_tf_frag.cpp" accumulateSamplesShader = new osg::Shader(osg::Shader::FRAGMENT, volume_accumulateSamples_lit_tf_frag); } _stateSetMap[LIT_SHADERS|CUBE_SHADERS|TF_SHADERS] = createStateSet(cube_stateset_prototype.get(), cube_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[LIT_SHADERS|HULL_SHADERS|TF_SHADERS] = createStateSet(hull_stateset_prototype.get(), hull_program_prototype.get(), accumulateSamplesShader.get()); _stateSetMap[LIT_SHADERS|CUBE_AND_HULL_SHADERS|TF_SHADERS] = createStateSet(cube_and_hull_stateset_prototype.get(), cube_and_hull_program_prototype.get(), accumulateSamplesShader.get()); } } if (cpv._sampleRatioWhenMovingProperty.valid()) { _whenMovingStateSet = new osg::StateSet; _whenMovingStateSet->addUniform(cpv._sampleRatioWhenMovingProperty->getUniform(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); } } void MultipassTechnique::update(osgUtil::UpdateVisitor* uv) { // OSG_NOTICE<<"MultipassTechnique:update(osgUtil::UpdateVisitor* uv):"<getNumChildren()>0) { getVolumeTile()->osg::Group::traverse(*uv); } else { _transform->accept(*uv); } } void MultipassTechnique::backfaceSubgraphCullTraversal(osgUtil::CullVisitor* cv) { if (!cv) return; cv->pushStateSet(_frontFaceStateSet.get()); if (getVolumeTile()->getNumChildren()>0) { getVolumeTile()->osg::Group::traverse(*cv); } else { _transform->accept(*cv); } cv->popStateSet(); } class ShadingModelVisitor : public osgVolume::PropertyVisitor { public: ShadingModelVisitor(): PropertyVisitor(true), _shadingModel(VolumeSettings::Standard), _usesTransferFunction(false) {} virtual void apply(IsoSurfaceProperty& /*iso*/) { _shadingModel = VolumeSettings::Isosurface; } virtual void apply(MaximumIntensityProjectionProperty& /*mip*/) { _shadingModel = VolumeSettings::MaximumIntensityProjection; } virtual void apply(LightingProperty& /*lp*/) { _shadingModel = VolumeSettings::Light; } virtual void apply(TransferFunctionProperty& /*tf*/) { _usesTransferFunction = true; } virtual void apply(VolumeSettings& vs) { _shadingModel = vs.getShadingModel(); } VolumeSettings::ShadingModel _shadingModel; bool _usesTransferFunction; }; void MultipassTechnique::cull(osgUtil::CullVisitor* cv) { std::string traversalPass; bool rttTraversal = cv->getUserValue("VolumeSceneTraversal", traversalPass) && traversalPass=="RenderToTexture"; // OSG_NOTICE<<"MultipassTechnique::cull() traversalPass="<getNodePath(); for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); (itr != nodePath.rend()) && (vs == 0); ++itr) { vs = dynamic_cast(*itr); } RenderingMode renderingMode = computeRenderingMode(); if (rttTraversal) { if (vs) { MultipassTileData* tileData = dynamic_cast(vs->tileVisited(cv, getVolumeTile())); if (tileData) { switch(renderingMode) { case(CUBE): { // no work required to pre-render break; } case(HULL): { if (tileData->frontFaceRttCamera.valid()) tileData->frontFaceRttCamera->accept(*cv); break; } case(CUBE_AND_HULL): { // OSG_NOTICE<<"Doing pre-rendering"<frontFaceRttCamera.valid()) { // OSG_NOTICE<<" frontFaceRttCamera"<frontFaceRttCamera->accept(*cv); } if (tileData->backFaceRttCamera.valid()) { // OSG_NOTICE<<" backFaceRttCamera"<backFaceRttCamera->accept(*cv); } } } } osg::BoundingBox bb; if (_transform.valid()) bb.expandBy(_transform->getBound()); if (getVolumeTile()->getNumChildren()>0) bb.expandBy(getVolumeTile()->getBound()); cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb); } } else { int shaderMask = 0; if (_volumeTile->getLayer()->getProperty()) { ShadingModelVisitor smv; _volumeTile->getLayer()->getProperty()->accept(smv); if (smv._usesTransferFunction) { shaderMask |= TF_SHADERS; } switch(smv._shadingModel) { case(VolumeSettings::Isosurface): shaderMask |= ISO_SHADERS; break; case(VolumeSettings::MaximumIntensityProjection): shaderMask |= MIP_SHADERS; break; case(VolumeSettings::Light): shaderMask |= LIT_SHADERS; break; default: shaderMask |= STANDARD_SHADERS; break; } } switch(renderingMode) { case(CUBE): shaderMask |= CUBE_SHADERS; break; case(HULL): shaderMask |= HULL_SHADERS; break; case(CUBE_AND_HULL): shaderMask |= CUBE_AND_HULL_SHADERS; break; } if (vs) { MultipassTileData* tileData = dynamic_cast(vs->getTileData(cv, getVolumeTile())); if (tileData) { Locator* tileLocator = _volumeTile->getLocator(); osg::Matrixd tileToEye = tileLocator->getTransform() * (*(cv->getModelViewMatrix())); osg::Matrixd eyeToTile; eyeToTile.invert(tileToEye); tileData->eyeToTileUniform->set(osg::Matrixf(eyeToTile)); Locator* layerLocator = _volumeTile->getLayer()->getLocator(); if (tileLocator==layerLocator) { tileData->tileToImageUniform->set(osg::Matrixf::identity()); } else { osg::Matrixd tileToImage(tileLocator->getTransform() * osg::Matrixd::inverse(layerLocator->getTransform())); tileData->tileToImageUniform->set(osg::Matrixf(tileToImage)); } // OSG_NOTICE<<"Updating texgen"< moving_stateset = (_whenMovingStateSet.valid() && isMoving(cv)) ? _whenMovingStateSet : 0; if (moving_stateset.valid()) { // OSG_NOTICE<<"Using MovingStateSet"<pushStateSet(moving_stateset.get()); } osg::ref_ptr program_stateset = _stateSetMap[shaderMask]; if (program_stateset.valid()) { // OSG_NOTICE<<"Have program_stateset OK."<pushStateSet(program_stateset.get()); cv->pushStateSet(_volumeRenderStateSet.get()); switch(renderingMode) { case(CUBE): // OSG_NOTICE<<"Travering Transform for CUBE rendering"<accept(*cv); break; case(HULL): // OSG_NOTICE<<"Travering children for HULL rendering"<osg::Group::traverse(*cv); break; case(CUBE_AND_HULL): // OSG_NOTICE<<"Travering Transform for CUBE_AND_HULL rendering"<accept(*cv); //getVolumeTile()->osg::Group::traverse(*cv); break; } cv->popStateSet(); cv->popStateSet(); } else { OSG_NOTICE<<"Warning: No program available for required shader mask "<popStateSet(); } } } void MultipassTechnique::cleanSceneGraph() { OSG_NOTICE<<"MultipassTechnique::cleanSceneGraph()"<getDirty()) _volumeTile->init(); osgUtil::UpdateVisitor* uv = nv.asUpdateVisitor(); if (uv) { update(uv); return; } } else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) { osgUtil::CullVisitor* cv = nv.asCullVisitor(); if (cv) { cull(cv); return; } } if (_volumeTile->getDirty()) { OSG_INFO<<"******* Doing init ***********"<init(); } } } // end of osgVolume namespace