From Christian Buchner, "Here is a strongly overhauled version of the original osgoit ("order independent transparency") by Mathias Fröhlich. I called this version myosgoit. It looks very nice, just build and run it!
This version adds: - an encapsulation of the entire Depth Peeling procedure into a class (not currently a scene graph node) for easier integration in other projects. - compositing with opaque (solid) geometry is possible and the opaque model is only rendered once. This needs to performs some depth buffer blitting between FBOs. - mix and match with GLSL shaders in the transparent objects is possible, as demonstrated with a 3D heat map intersecting an opaque truck model. Some Drawbacks: - the display framebuffer does not receive any depth information from the compositing camera. This could be fixed by compositing with a GLSL shader and writing to FragDepth." From Robert Osfield, ported the code to work under Linux and without the automatic ref_ptr to C* conversion.
This commit is contained in:
parent
00acf55571
commit
ceb97fe230
@ -1,2 +1,8 @@
|
||||
SET(TARGET_SRC osgoit.cpp)
|
||||
SET(TARGET_SRC
|
||||
osgoit.cpp
|
||||
DepthPeeling.h
|
||||
DepthPeeling.cpp
|
||||
HeatMap.h
|
||||
HeatMap.cpp)
|
||||
|
||||
SETUP_EXAMPLE(osgoit)
|
||||
|
574
examples/osgoit/DepthPeeling.cpp
Normal file
574
examples/osgoit/DepthPeeling.cpp
Normal file
@ -0,0 +1,574 @@
|
||||
|
||||
#include "DepthPeeling.h"
|
||||
|
||||
#include <osg/Array>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Depth>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TextureRectangle>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/TexGenNode>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
#include <osg/Math>
|
||||
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
const char *DepthPeeling::PeelingShader =
|
||||
{
|
||||
"#version 120\n"
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRectShadow depthtex;\n"
|
||||
#else
|
||||
"uniform sampler2DShadow depthtex;\n"
|
||||
#endif
|
||||
"uniform bool depthtest;\n" // depth test enable flag
|
||||
"uniform float invWidth;\n" // 1.0/width (shadow texture size)
|
||||
"uniform float invHeight;\n" // 1.0/height (shadow texture size)
|
||||
"uniform float offsetX;\n" // viewport lower left corner (int)
|
||||
"uniform float offsetY;\n" // viewport lower left corner (int)
|
||||
"\n"
|
||||
"bool depthpeeling()\n"
|
||||
"{\n"
|
||||
" if( depthtest ) {\n"
|
||||
" vec3 r0 = vec3((gl_FragCoord.x-offsetX)*invWidth,\n"
|
||||
" (gl_FragCoord.y-offsetY)*invHeight,\n"
|
||||
" gl_FragCoord.z);\n"
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
" return shadow2DRect(depthtex, r0).r < 0.5;\n"
|
||||
#else
|
||||
" return shadow2D(depthtex, r0).r < 0.5;\n"
|
||||
#endif
|
||||
" }\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
class PreDrawFBOCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
PreDrawFBOCallback( osg::FrameBufferObject* fbo, osg::FrameBufferObject* source_fbo, unsigned int width, unsigned int height, osg::Texture *dt, osg::Texture *ct ) :
|
||||
_fbo(fbo), _source_fbo(source_fbo), _depthTexture(dt), _colorTexture(ct), _width(width), _height(height) {}
|
||||
|
||||
virtual void operator () (osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
// switching only the frame buffer attachments is actually faster than switching the framebuffer
|
||||
#ifdef USE_PACKED_DEPTH_STENCIL
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_fbo->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment((osg::TextureRectangle*)(_depthTexture.get())));
|
||||
#else
|
||||
_fbo->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment((osg::Texture2D*)(_depthTexture.get())));
|
||||
#endif
|
||||
#else
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_fbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment((osg::TextureRectangle*)(_depthTexture.get())));
|
||||
#else
|
||||
_fbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment((osg::Texture2D*)(_depthTexture.get())));
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_fbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment((osg::TextureRectangle*)(_colorTexture.get())));
|
||||
#else
|
||||
_fbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment((osg::Texture2D*)(_colorTexture.get())));
|
||||
#endif
|
||||
|
||||
// check if we need to do some depth buffer copying from a source FBO into the current FBO
|
||||
if (_source_fbo.get() != NULL)
|
||||
{
|
||||
osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(renderInfo.getContextID(),true);
|
||||
bool fbo_supported = fbo_ext && fbo_ext->isSupported();
|
||||
if (fbo_supported && fbo_ext->glBlitFramebuffer)
|
||||
{
|
||||
// blit the depth buffer from the solid geometry fbo into the current transparency fbo
|
||||
(_fbo.get())->apply(*renderInfo.getState(), osg::FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
(_source_fbo.get())->apply(*renderInfo.getState(), osg::FrameBufferObject::READ_FRAMEBUFFER);
|
||||
|
||||
// glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); // only needed to blit the color buffer
|
||||
// glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); // only needed to blit the color buffer
|
||||
fbo_ext->glBlitFramebuffer(
|
||||
0, 0, static_cast<GLint>(_width), static_cast<GLint>(_height),
|
||||
0, 0, static_cast<GLint>(_width), static_cast<GLint>(_height),
|
||||
#ifdef USE_PACKED_DEPTH_STENCIL
|
||||
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
#else
|
||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
#endif
|
||||
(_fbo.get())->apply(*renderInfo.getState(), osg::FrameBufferObject::READ_FRAMEBUFFER);
|
||||
(_fbo.get())->apply(*renderInfo.getState(), osg::FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
}
|
||||
}
|
||||
// switch to this fbo, if it isn't already bound
|
||||
(_fbo.get())->apply( *renderInfo.getState() );
|
||||
}
|
||||
protected:
|
||||
osg::ref_ptr<osg::FrameBufferObject> _fbo;
|
||||
osg::ref_ptr<osg::FrameBufferObject> _source_fbo;
|
||||
osg::ref_ptr<osg::Texture> _depthTexture;
|
||||
osg::ref_ptr<osg::Texture> _colorTexture;
|
||||
unsigned int _width;
|
||||
unsigned int _height;
|
||||
};
|
||||
|
||||
|
||||
class PostDrawFBOCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
PostDrawFBOCallback(bool restore) : _restore(restore) {}
|
||||
|
||||
virtual void operator () (osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
// only unbind the fbo if this is the last transparency pass
|
||||
if (_restore)
|
||||
osg::FBOExtensions::instance( renderInfo.getState()->getContextID(), false )->glBindFramebuffer( GL_FRAMEBUFFER_EXT, 0 );
|
||||
}
|
||||
protected:
|
||||
bool _restore;
|
||||
};
|
||||
|
||||
|
||||
DepthPeeling::CullCallback::CullCallback(unsigned int texUnit, unsigned int texWidth, unsigned int texHeight, unsigned int offsetValue) :
|
||||
_texUnit(texUnit),
|
||||
_texWidth(texWidth),
|
||||
_texHeight(texHeight),
|
||||
_offsetValue(offsetValue)
|
||||
{
|
||||
}
|
||||
|
||||
void DepthPeeling::CullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
|
||||
osgUtil::RenderStage* renderStage = cullVisitor->getCurrentRenderStage();
|
||||
const osg::Viewport* viewport = renderStage->getViewport();
|
||||
|
||||
osg::Matrixd m(*cullVisitor->getProjectionMatrix());
|
||||
m.postMultTranslate(osg::Vec3d(1, 1, 1));
|
||||
m.postMultScale(osg::Vec3d(0.5, 0.5, 0.5));
|
||||
|
||||
// scale the texture coordinates to the viewport
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
m.postMultScale(osg::Vec3d(viewport->width(), viewport->height(), 1));
|
||||
#else
|
||||
#ifndef USE_NON_POWER_OF_TWO_TEXTURE
|
||||
m.postMultScale(osg::Vec3d(viewport->width()/double(_texWidth), viewport->height()/double(_texHeight), 1));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (_texUnit != 0 && _offsetValue)
|
||||
{
|
||||
// Kind of polygon offset: note this way, we can also offset lines and points.
|
||||
// Whereas with the polygon offset we could only handle surface primitives.
|
||||
m.postMultTranslate(osg::Vec3d(0, 0, -ldexp(double(_offsetValue), -24)));
|
||||
}
|
||||
|
||||
osg::TexMat* texMat = new osg::TexMat(m);
|
||||
osg::StateSet* stateSet = new osg::StateSet;
|
||||
stateSet->setTextureAttribute(_texUnit, texMat);
|
||||
|
||||
if (_texUnit != 0)
|
||||
{
|
||||
//
|
||||
// GLSL pipeline support
|
||||
//
|
||||
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
// osg::Uniform::SAMPLER_2D_RECT_SHADOW not yet available in OSG 3.0.1
|
||||
// osg::Uniform* depthUniform = new osg::Uniform(osg::Uniform::SAMPLER_2D_RECT_SHADOW, "depthtex");
|
||||
// depthUniform->set((int)_texUnit);
|
||||
osg::Uniform* depthUniform = new osg::Uniform("depthtex", (int)_texUnit);
|
||||
osg::Uniform *invWidthUniform = new osg::Uniform("invWidth", (float)1.0f);
|
||||
osg::Uniform *invHeightUniform = new osg::Uniform("invHeight", (float)1.0f);
|
||||
#else
|
||||
osg::Uniform* depthUniform = new osg::Uniform(osg::Uniform::SAMPLER_2D_SHADOW, "depthtex");
|
||||
depthUniform->set((int)_texUnit);
|
||||
osg::Uniform *invWidthUniform = new osg::Uniform("invWidth", (float)1.0f / _texWidth);
|
||||
osg::Uniform *invHeightUniform = new osg::Uniform("invHeight", (float)1.0f / _texHeight);
|
||||
#endif
|
||||
osg::Uniform *offsetXUniform = new osg::Uniform("offsetX", (float)viewport->x());
|
||||
osg::Uniform *offsetYUniform = new osg::Uniform("offsetY", (float)viewport->y());
|
||||
|
||||
// uniforms required for any any GLSL implementation in the rendered geometry
|
||||
stateSet->addUniform(depthUniform);
|
||||
stateSet->addUniform(invWidthUniform);
|
||||
stateSet->addUniform(invHeightUniform);
|
||||
stateSet->addUniform(offsetXUniform);
|
||||
stateSet->addUniform(offsetYUniform);
|
||||
}
|
||||
|
||||
cullVisitor->pushStateSet(stateSet);
|
||||
traverse(node, nv);
|
||||
cullVisitor->popStateSet();
|
||||
}
|
||||
|
||||
|
||||
osg::Node* DepthPeeling::createQuad(unsigned int layerNumber, unsigned int numTiles)
|
||||
{
|
||||
float tileSpan = 1;
|
||||
float tileOffsetX = 0;
|
||||
float tileOffsetY = 0;
|
||||
if (_showAllLayers) {
|
||||
tileSpan /= numTiles;
|
||||
tileOffsetX = tileSpan * (layerNumber%numTiles);
|
||||
tileOffsetY = 1 - tileSpan * (1 + layerNumber/numTiles);
|
||||
}
|
||||
|
||||
osg::Vec3Array* vertices = new osg::Vec3Array;
|
||||
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX , tileOffsetY , 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX , tileOffsetY + tileSpan, 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY + tileSpan, 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY , 0));
|
||||
|
||||
osg::Vec3Array* colors = new osg::Vec3Array;
|
||||
colors->push_back(osg::Vec3(1, 1, 1));
|
||||
|
||||
osg::Vec2Array* texcoords = new osg::Vec2Array;
|
||||
texcoords->push_back(osg::Vec2f(0, 0));
|
||||
texcoords->push_back(osg::Vec2f(0, 1));
|
||||
texcoords->push_back(osg::Vec2f(1, 1));
|
||||
texcoords->push_back(osg::Vec2f(1, 0));
|
||||
|
||||
osg::Geometry* geometry = new osg::Geometry;
|
||||
geometry->setVertexArray(vertices);
|
||||
geometry->setTexCoordArray(0, texcoords);
|
||||
|
||||
geometry->setColorArray(colors);
|
||||
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
|
||||
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
#include <osg/State>
|
||||
|
||||
void DepthPeeling::createPeeling()
|
||||
{
|
||||
int numTiles = ceil(sqrt(double(_numPasses)));
|
||||
|
||||
// cleanup any previous scene data
|
||||
_root->removeChildren(0, _root->getNumChildren());
|
||||
|
||||
// create depth textures
|
||||
_depthTextures.clear();
|
||||
_depthTextures.resize(3);
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_depthTextures[i] = new osg::TextureRectangle;
|
||||
#else
|
||||
_depthTextures[i] = new osg::Texture2D;
|
||||
#endif
|
||||
_depthTextures[i]->setTextureSize(_texWidth, _texHeight);
|
||||
|
||||
_depthTextures[i]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
_depthTextures[i]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
_depthTextures[i]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
|
||||
_depthTextures[i]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
|
||||
|
||||
#ifdef USE_PACKED_DEPTH_STENCIL
|
||||
_depthTextures[i]->setInternalFormat(GL_DEPTH24_STENCIL8_EXT);
|
||||
_depthTextures[i]->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||
_depthTextures[i]->setSourceType(GL_UNSIGNED_INT_24_8_EXT);
|
||||
#else
|
||||
_depthTextures[i]->setInternalFormat(GL_DEPTH_COMPONENT);
|
||||
#endif
|
||||
|
||||
_depthTextures[i]->setShadowComparison(true);
|
||||
_depthTextures[i]->setShadowAmbient(0.0); // The r value if the test fails
|
||||
_depthTextures[i]->setShadowCompareFunc(osg::Texture::GREATER);
|
||||
_depthTextures[i]->setShadowTextureMode(osg::Texture::INTENSITY);
|
||||
}
|
||||
|
||||
// create the cameras for the individual depth peel layers
|
||||
_colorTextures.clear();
|
||||
_colorTextures.resize(_numPasses);
|
||||
for (unsigned int i = 0; i < _numPasses; ++i) {
|
||||
|
||||
// create textures for the color buffers
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
osg::ref_ptr<osg::TextureRectangle> colorTexture = new osg::TextureRectangle;
|
||||
#else
|
||||
osg::ref_ptr<osg::Texture2D> colorTexture = new osg::Texture2D;
|
||||
#endif
|
||||
colorTexture->setTextureSize(_texWidth, _texHeight);
|
||||
colorTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
colorTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
colorTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
|
||||
colorTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
|
||||
colorTexture->setInternalFormat(GL_RGBA);
|
||||
|
||||
_colorTextures[i] = colorTexture;
|
||||
}
|
||||
|
||||
// create some uniform and cull callback objects
|
||||
osg::Uniform *depthOff = new osg::Uniform("depthtest", (bool)false);
|
||||
osg::Uniform *depthOn = new osg::Uniform("depthtest", (bool)true);
|
||||
CullCallback *ccb = new CullCallback(_texUnit, _texWidth, _texHeight, _offsetValue);
|
||||
|
||||
// create a node for solid model rendering
|
||||
osg::Group *pre_solidNode = new osg::Group;
|
||||
pre_solidNode->addChild(_solidscene.get());
|
||||
|
||||
// create a node for non depth peeled transparent rendering (topmost layer)
|
||||
osg::Group *transparentNodeNoPeel = new osg::Group;
|
||||
transparentNodeNoPeel->addChild(_transparentscene.get());
|
||||
transparentNodeNoPeel->getOrCreateStateSet()->addUniform(depthOff);
|
||||
transparentNodeNoPeel->getOrCreateStateSet()->setRenderBinDetails(99, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||
|
||||
// create a node for depth peeled transparent rendering (any layers below).
|
||||
osg::TexGenNode* transparentNodePeel = new osg::TexGenNode;
|
||||
transparentNodePeel->setReferenceFrame(osg::TexGenNode::ABSOLUTE_RF);
|
||||
transparentNodePeel->setTextureUnit(_texUnit);
|
||||
transparentNodePeel->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
|
||||
transparentNodePeel->addChild(_transparentscene.get());
|
||||
transparentNodePeel->getOrCreateStateSet()->addUniform(depthOn);
|
||||
transparentNodePeel->getOrCreateStateSet()->setRenderBinDetails(99, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||
|
||||
// only render fragments that are not completely transparent
|
||||
transparentNodePeel->getOrCreateStateSet()->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01),
|
||||
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
// generate texcoords for the depth texture, supporting the fixed function pipeline
|
||||
transparentNodePeel->getOrCreateStateSet()->setTextureMode(_texUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
|
||||
transparentNodePeel->getOrCreateStateSet()->setTextureMode(_texUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
|
||||
transparentNodePeel->getOrCreateStateSet()->setTextureMode(_texUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
|
||||
transparentNodePeel->getOrCreateStateSet()->setTextureMode(_texUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);
|
||||
|
||||
// use two FBOs, one for solid geometry - the other one for the transparency passes
|
||||
// depth and color attachments will be switched as needed.
|
||||
osg::ref_ptr<osg::FrameBufferObject> fbos[2] = {new osg::FrameBufferObject(), new osg::FrameBufferObject()};
|
||||
|
||||
// create the cameras for the individual depth peel layers
|
||||
for (unsigned int i = 0; i < _numPasses; ++i) {
|
||||
|
||||
// get the pointers to the required fbo, color and depth textures for each camera instance
|
||||
// we perform ping ponging between two depth textures
|
||||
osg::FrameBufferObject *fbo0 = (i >= 1) ? fbos[0].get() : NULL;
|
||||
osg::FrameBufferObject *fbo = (i >= 1) ? fbos[1].get() : fbos[0].get();
|
||||
osg::Texture *colorTexture = _colorTextures[i].get();
|
||||
osg::Texture *depthTexture = (i >= 1) ? _depthTextures[1+(i-1)%2].get() : _depthTextures[i].get();
|
||||
osg::Texture *prevDepthTexture = (i >= 2) ? _depthTextures[1+(i-2)%2].get() : NULL;
|
||||
|
||||
// all our peeling layer cameras are post render
|
||||
osg::Camera* camera = new osg::Camera;
|
||||
camera->setDataVariance(osg::Object::DYNAMIC);
|
||||
camera->setInheritanceMask(osg::Camera::ALL_VARIABLES);
|
||||
camera->setRenderOrder(osg::Camera::POST_RENDER, i);
|
||||
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
camera->setClearColor(osg::Vec4f(0, 0, 0, 0));
|
||||
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
camera->setPreDrawCallback(new PreDrawFBOCallback(fbo, fbo0, _texWidth, _texHeight, depthTexture, colorTexture));
|
||||
camera->setPostDrawCallback(new PostDrawFBOCallback(i == _numPasses - 1));
|
||||
camera->setDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
camera->setReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
camera->setAllowEventFocus(false);
|
||||
|
||||
// the peeled layers are rendered with blending forced off
|
||||
// and the depth buffer is directly taken from camera 0 via framebuffer blit
|
||||
if (i > 0) {
|
||||
camera->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
|
||||
camera->setClearMask(GL_COLOR_BUFFER_BIT);
|
||||
} else {
|
||||
// camera 0 has to clear both the depth and color buffers
|
||||
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// add the correct geometry for each pass.
|
||||
// the peeling passes also need read access to prevDepthTexture and a cull callback
|
||||
if (0 == i) { // solid geometry
|
||||
camera->addChild(pre_solidNode);
|
||||
} else if (1 == i) { // topmost layer peeling pass
|
||||
camera->addChild(transparentNodeNoPeel);
|
||||
} else { // behind layers peeling passes
|
||||
camera->addChild(transparentNodePeel);
|
||||
// set depth (shadow) texture for depth peeling and add a cull callback
|
||||
camera->getOrCreateStateSet()->setTextureAttributeAndModes(_texUnit, prevDepthTexture);
|
||||
camera->addCullCallback(ccb);
|
||||
}
|
||||
_root->addChild(camera);
|
||||
}
|
||||
|
||||
// create the composite camera that blends the peeled layers into the final scene
|
||||
_compositeCamera = new osg::Camera;
|
||||
_compositeCamera->setDataVariance(osg::Object::DYNAMIC);
|
||||
_compositeCamera->setInheritanceMask(osg::Camera::READ_BUFFER | osg::Camera::DRAW_BUFFER);
|
||||
_compositeCamera->setRenderOrder(osg::Camera::POST_RENDER, _numPasses);
|
||||
_compositeCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
|
||||
_compositeCamera->setClearMask(0);
|
||||
_compositeCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
_compositeCamera->setViewMatrix(osg::Matrix());
|
||||
_compositeCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||
_compositeCamera->setCullCallback(new CullCallback(0, _texWidth, _texHeight, 0));
|
||||
osg::StateSet* stateSet = _compositeCamera->getOrCreateStateSet();
|
||||
stateSet->setRenderBinDetails(100, "TraversalOrderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||
_root->addChild(_compositeCamera.get());
|
||||
|
||||
// solid geometry is blended first, transparency layers are blended in back to front order.
|
||||
// this order is achieved by rendering using a TraversalOrderBin (see camera stateset).
|
||||
for (unsigned int i = _numPasses; i > 0; --i) {
|
||||
osg::Node* geode = createQuad(i%_numPasses, numTiles);
|
||||
osg::StateSet *stateSet = geode->getOrCreateStateSet();
|
||||
stateSet->setTextureAttributeAndModes(0, _colorTextures[i%_numPasses].get(), osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
osg::Depth* depth = new osg::Depth;
|
||||
depth->setWriteMask( false );
|
||||
stateSet->setAttributeAndModes( depth, osg::StateAttribute::ON );
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
_compositeCamera->addChild(geode);
|
||||
}
|
||||
}
|
||||
|
||||
DepthPeeling::DepthPeeling(unsigned int width, unsigned int height) :
|
||||
_numPasses(9),
|
||||
_texUnit(2),
|
||||
_texWidth(width),
|
||||
_texHeight(height),
|
||||
_showAllLayers(false),
|
||||
_offsetValue(8),
|
||||
_root(new osg::Group),
|
||||
_solidscene(new osg::Group),
|
||||
_transparentscene(new osg::Group)
|
||||
{
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void DepthPeeling::setSolidScene(osg::Node* scene)
|
||||
{
|
||||
_solidscene->removeChildren(0, _solidscene->getNumChildren());
|
||||
_solidscene->addChild(scene);
|
||||
}
|
||||
|
||||
void DepthPeeling::setTransparentScene(osg::Node* scene)
|
||||
{
|
||||
_transparentscene->removeChildren(0, _transparentscene->getNumChildren());
|
||||
_transparentscene->addChild(scene);
|
||||
}
|
||||
|
||||
osg::Node* DepthPeeling::getRoot()
|
||||
{
|
||||
return _root.get();
|
||||
}
|
||||
|
||||
void DepthPeeling::resize(int width, int height)
|
||||
{
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
_depthTextures[i]->setTextureSize(width, height);
|
||||
for (unsigned int i = 0; i < _colorTextures.size(); ++i)
|
||||
_colorTextures[i]->setTextureSize(width, height);
|
||||
_texWidth = width;
|
||||
_texHeight = height;
|
||||
#else
|
||||
#ifndef USE_NON_POWER_OF_TWO_TEXTURE
|
||||
width = nextPowerOfTwo(width);
|
||||
height = nextPowerOfTwo(height);
|
||||
#endif
|
||||
_depthTextures[0]->setTextureSize(width, height);
|
||||
_depthTextures[1]->setTextureSize(width, height);
|
||||
for (unsigned int i = 0; i < _colorTextures.size(); ++i)
|
||||
_colorTextures[i]->setTextureSize(width, height);
|
||||
_texWidth = width;
|
||||
_texHeight = height;
|
||||
#endif
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void DepthPeeling::setNumPasses(unsigned int numPasses)
|
||||
{
|
||||
if (numPasses == _numPasses)
|
||||
return;
|
||||
if (numPasses == unsigned(-1))
|
||||
return;
|
||||
_numPasses = numPasses;
|
||||
createPeeling();
|
||||
}
|
||||
unsigned int DepthPeeling::getNumPasses() const
|
||||
{
|
||||
return _numPasses;
|
||||
}
|
||||
|
||||
void DepthPeeling::setTexUnit(unsigned int texUnit)
|
||||
{
|
||||
if (texUnit == _texUnit)
|
||||
return;
|
||||
_texUnit = texUnit;
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void DepthPeeling::setShowAllLayers(bool showAllLayers)
|
||||
{
|
||||
if (showAllLayers == _showAllLayers)
|
||||
return;
|
||||
_showAllLayers = showAllLayers;
|
||||
createPeeling();
|
||||
}
|
||||
bool DepthPeeling::getShowAllLayers() const
|
||||
{
|
||||
return _showAllLayers;
|
||||
}
|
||||
|
||||
void DepthPeeling::setOffsetValue(unsigned int offsetValue)
|
||||
{
|
||||
if (offsetValue == _offsetValue)
|
||||
return;
|
||||
_offsetValue = offsetValue;
|
||||
createPeeling();
|
||||
}
|
||||
unsigned int DepthPeeling::getOffsetValue() const
|
||||
{
|
||||
return _offsetValue;
|
||||
}
|
||||
|
||||
|
||||
DepthPeeling::EventHandler::EventHandler(DepthPeeling* depthPeeling) :
|
||||
_depthPeeling(depthPeeling)
|
||||
{ }
|
||||
|
||||
|
||||
/** Handle events, return true if handled, false otherwise. */
|
||||
bool DepthPeeling::EventHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
|
||||
{
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) {
|
||||
_depthPeeling->resize(ea.getWindowWidth(), ea.getWindowHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
|
||||
switch (ea.getKey()) {
|
||||
case 'm':
|
||||
_depthPeeling->setNumPasses(_depthPeeling->getNumPasses() + 1);
|
||||
return true;
|
||||
case 'n':
|
||||
_depthPeeling->setNumPasses(_depthPeeling->getNumPasses() - 1);
|
||||
return true;
|
||||
case 'p':
|
||||
_depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() + 1);
|
||||
return true;
|
||||
case 'o':
|
||||
_depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() - 1);
|
||||
return true;
|
||||
case 'l':
|
||||
_depthPeeling->setShowAllLayers(!_depthPeeling->getShowAllLayers());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
102
examples/osgoit/DepthPeeling.h
Normal file
102
examples/osgoit/DepthPeeling.h
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Node>
|
||||
#include <osg/Camera>
|
||||
#include <osg/TextureRectangle>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgGA/GUIEventHandler>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#ifndef DEPTHPEELING_H
|
||||
#define DEPTHPEELING_H
|
||||
|
||||
// Some choices for the kind of textures we can use ...
|
||||
#define USE_TEXTURE_RECTANGLE
|
||||
//#define USE_NON_POWER_OF_TWO_TEXTURE
|
||||
#define USE_PACKED_DEPTH_STENCIL
|
||||
|
||||
template<typename T>
|
||||
inline T
|
||||
nextPowerOfTwo(T k)
|
||||
{
|
||||
if (k == T(0))
|
||||
return 1;
|
||||
k--;
|
||||
for (int i = 1; i < std::numeric_limits<T>::digits; i <<= 1)
|
||||
k = k | k >> i;
|
||||
return k + 1;
|
||||
}
|
||||
|
||||
class DepthPeeling : public osg::Referenced {
|
||||
public:
|
||||
|
||||
DepthPeeling(unsigned int width, unsigned int height);
|
||||
void setSolidScene(osg::Node* scene);
|
||||
void setTransparentScene(osg::Node* scene);
|
||||
osg::Node* getRoot();
|
||||
void resize(int width, int height);
|
||||
void setNumPasses(unsigned int numPasses);
|
||||
unsigned int getNumPasses() const;
|
||||
void setTexUnit(unsigned int texUnit);
|
||||
void setShowAllLayers(bool showAllLayers);
|
||||
bool getShowAllLayers() const;
|
||||
void setOffsetValue(unsigned int offsetValue);
|
||||
unsigned int getOffsetValue() const;
|
||||
|
||||
static const char *PeelingShader; /* use this to support depth peeling in GLSL shaders in transparent objects */
|
||||
|
||||
class EventHandler : public osgGA::GUIEventHandler {
|
||||
public:
|
||||
EventHandler(DepthPeeling* depthPeeling);
|
||||
|
||||
/** Handle events, return true if handled, false otherwise. */
|
||||
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*);
|
||||
|
||||
protected:
|
||||
osg::ref_ptr<DepthPeeling> _depthPeeling;
|
||||
};
|
||||
|
||||
protected:
|
||||
osg::Node *createQuad(unsigned int layerNumber, unsigned int numTiles);
|
||||
void createPeeling();
|
||||
|
||||
class CullCallback : public osg::NodeCallback {
|
||||
public:
|
||||
CullCallback(unsigned int texUnit, unsigned int texWidth, unsigned int texHeight, unsigned int offsetValue);
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
||||
|
||||
private:
|
||||
unsigned int _texUnit;
|
||||
unsigned int _texWidth;
|
||||
unsigned int _texHeight;
|
||||
unsigned int _offsetValue;
|
||||
};
|
||||
|
||||
unsigned int _numPasses;
|
||||
unsigned int _texUnit;
|
||||
unsigned int _texWidth;
|
||||
unsigned int _texHeight;
|
||||
bool _showAllLayers;
|
||||
unsigned int _offsetValue;
|
||||
|
||||
// The root node that is handed over to the viewer
|
||||
osg::ref_ptr<osg::Group> _root;
|
||||
|
||||
// The scene that is displayed
|
||||
osg::ref_ptr<osg::Group> _solidscene;
|
||||
osg::ref_ptr<osg::Group> _transparentscene;
|
||||
|
||||
// The final camera that composites the pre rendered textures to the final picture
|
||||
osg::ref_ptr<osg::Camera> _compositeCamera;
|
||||
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
std::vector<osg::ref_ptr<osg::TextureRectangle> > _depthTextures;
|
||||
std::vector<osg::ref_ptr<osg::TextureRectangle> > _colorTextures;
|
||||
#else
|
||||
std::vector<osg::ref_ptr<osg::Texture2D> > _depthTextures;
|
||||
std::vector<osg::ref_ptr<osg::Texture2D> > _colorTextures;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // #ifndef DEPTHPEELING_H
|
232
examples/osgoit/HeatMap.cpp
Normal file
232
examples/osgoit/HeatMap.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 3D Heat map using vertex displacement mapping
|
||||
* Rendered using depth peeling in fragment shader.
|
||||
*/
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/LightModel>
|
||||
#include <osg/io_utils>
|
||||
#include <osg/Material>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/WriteFile>
|
||||
#include <osgGA/TrackballManipulator>
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osg/Math>
|
||||
#include <iostream>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/Depth>
|
||||
#include <osg/ShapeDrawable>
|
||||
#include <osg/Texture1D>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/PolygonOffset>
|
||||
|
||||
#include "HeatMap.h"
|
||||
#include "DepthPeeling.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// in-line GLSL source code
|
||||
|
||||
static const char *VertexShader = {
|
||||
"#version 120\n"
|
||||
"uniform float maximum;\n"
|
||||
"uniform float maxheight;\n"
|
||||
"uniform float transparency;\n"
|
||||
"uniform sampler1D colortex;\n"
|
||||
"uniform sampler2D datatex;\n"
|
||||
"in vec2 xypos;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" float foo;\n"
|
||||
" float tmp = min(texture2D(datatex, xypos).x / maximum, 1.0);\n"
|
||||
" gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, 0.0, maxheight * tmp, 0.0));\n"
|
||||
" vec4 color = texture1D(colortex, tmp);\n"
|
||||
" color.w = color.w * transparency;\n"
|
||||
" gl_FrontColor = color;\n"
|
||||
" gl_BackColor = color;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
static const char *FragmentShader =
|
||||
{
|
||||
"#version 120\n"
|
||||
"bool depthpeeling();\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" if( depthpeeling() ) discard;\n"
|
||||
" gl_FragColor = gl_Color;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
/**
|
||||
* Overloaded Geometry class to return predefined bounds
|
||||
*/
|
||||
class MyGeometry : public osg::Geometry
|
||||
{
|
||||
public:
|
||||
MyGeometry(osg::BoundingBox bounds)
|
||||
{
|
||||
m_bounds = bounds;
|
||||
m_bsphere = osg::BoundingSphere(bounds);
|
||||
}
|
||||
|
||||
// an attempt to return a reasonable bounding box. Still does not prevent clipping of the heat map.
|
||||
virtual const osg::BoundingBox& getBoundingBox() const {return m_bounds;}
|
||||
virtual osg::BoundingBox computeBound() const {return m_bounds;}
|
||||
virtual const osg::BoundingSphere& getBound() const {return m_bsphere;}
|
||||
|
||||
protected:
|
||||
osg::BoundingBox m_bounds;
|
||||
osg::BoundingSphere m_bsphere;
|
||||
};
|
||||
|
||||
Heatmap::Heatmap(float width, float depth, float maxheight, unsigned int K, unsigned int N, float maximum, float transparency)
|
||||
{
|
||||
m_K = K;
|
||||
m_N = N;
|
||||
const int O = 4;
|
||||
|
||||
// create Geometry object to store all the vertices primitives.
|
||||
osg::Geometry *meshGeom = new MyGeometry(osg::BoundingBox(osg::Vec3(-width/2, -depth/2, 0), osg::Vec3(width/2, depth/2, maxheight)));
|
||||
|
||||
// we use a float attribute array storing texcoords
|
||||
osg::Vec2Array* xypositions = new osg::Vec2Array();
|
||||
xypositions->setName("xypos");
|
||||
|
||||
// create vertex coordinates
|
||||
osg::Vec3Array* vertices = new osg::Vec3Array();
|
||||
osg::Vec3 off(-width/2, -depth/2, 0);
|
||||
for (unsigned int y=0; y < O*N; y++) {
|
||||
if (y % 2 == 0)
|
||||
{
|
||||
for (unsigned int x=0; x < O*K; x++) {
|
||||
vertices->push_back(osg::Vec3(width*x/(O*K-1), depth*y/(O*N-1), 0.0)+off);
|
||||
xypositions->push_back(osg::Vec2(((float)x+0.5f)/(O*K),((float)y+0.5f)/(O*N)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices->push_back(osg::Vec3(0, depth*y/(O*N-1), 0.0)+off);
|
||||
xypositions->push_back(osg::Vec2(0.5f/(O*K),((float)y+0.5f)/(O*N)));
|
||||
for (unsigned int x=0; x < O*K-1; x++) {
|
||||
vertices->push_back(osg::Vec3(width*(0.5+x)/(O*K-1), depth*y/(O*N-1), 0.0)+off);
|
||||
xypositions->push_back(osg::Vec2(((float)(x+0.5f)+0.5f)/(O*K),((float)y+0.5f)/(O*N)));
|
||||
}
|
||||
vertices->push_back(osg::Vec3(width, depth*y/(O*N-1), 0.0)+off);
|
||||
xypositions->push_back(osg::Vec2(1.0f-0.5f/(O*K),((float)y+0.5f)/(O*N)));
|
||||
}
|
||||
}
|
||||
|
||||
meshGeom->setVertexAttribArray(6, xypositions);
|
||||
meshGeom->setVertexAttribNormalize(6, false);
|
||||
meshGeom->setVertexAttribBinding(6, osg::Geometry::BIND_PER_VERTEX);
|
||||
meshGeom->setVertexArray(vertices);
|
||||
|
||||
// generate several tri strips to form a mesh
|
||||
GLuint *indices = new GLuint[4*O*K];
|
||||
for (unsigned int y=0; y < O*N-1; y++) {
|
||||
if (y % 2 == 0)
|
||||
{
|
||||
int base = (y/2) * (O*K+O*K+1);
|
||||
int base2 = (y/2) * (O*K+O*K+1) + O*K;
|
||||
int i=0; for (unsigned int x=0; x < O*K; x++) { indices[i++] = base2+x; indices[i++] = base+x;}
|
||||
indices[i++] = base2+O*K;
|
||||
meshGeom->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, i, indices));
|
||||
}
|
||||
else
|
||||
{
|
||||
int base = (y/2) * (O*K+O*K+1) + O*K;
|
||||
int base2 = (y/2) * (O*K+O*K+1) + O*K + O*K+1;
|
||||
int i=0; for (unsigned int x=0; x < O*K; x++) { indices[i++] = base+x; indices[i++] = base2+x;}
|
||||
indices[i++] = base+O*K;
|
||||
meshGeom->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, i, indices));
|
||||
}
|
||||
}
|
||||
delete[] indices;
|
||||
|
||||
// create vertex and fragment shader
|
||||
osg::Program* program = new osg::Program;
|
||||
program->setName( "mesh" );
|
||||
program->addBindAttribLocation("xypos", 6);
|
||||
program->addShader( new osg::Shader( osg::Shader::VERTEX, VertexShader ) );
|
||||
program->addShader( new osg::Shader( osg::Shader::FRAGMENT, DepthPeeling::PeelingShader ) );
|
||||
program->addShader( new osg::Shader( osg::Shader::FRAGMENT, FragmentShader ) );
|
||||
|
||||
// create a 1D texture for color lookups
|
||||
colorimg = new osg::Image();
|
||||
colorimg->allocateImage(5, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
unsigned char *data = colorimg->data();
|
||||
*data++ = 0; *data++ = 0; *data++ = 255; *data++ = 0; // fully transparent blue
|
||||
*data++ = 0; *data++ = 255; *data++ = 255; *data++ = 255; // turquoise
|
||||
*data++ = 0; *data++ = 255; *data++ = 0; *data++ = 255; // green
|
||||
*data++ = 255; *data++ = 255; *data++ = 0; *data++ = 255; // yellow
|
||||
*data++ = 255; *data++ = 0; *data++ = 0; *data++ = 255; // red
|
||||
colortex = new osg::Texture1D(colorimg.get());
|
||||
colortex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
colortex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
colortex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
colortex->setResizeNonPowerOfTwoHint(false);
|
||||
|
||||
// create a 2D texture for data lookups
|
||||
m_img2 = new osg::Image();
|
||||
m_img2->allocateImage(K, N, 1, GL_LUMINANCE, GL_FLOAT);
|
||||
m_img2->setInternalTextureFormat(GL_RGB32F_ARB);
|
||||
m_data = (float*)m_img2.get()->data();
|
||||
m_tex2 = new osg::Texture2D(m_img2.get());
|
||||
m_tex2.get()->setResizeNonPowerOfTwoHint(false);
|
||||
m_tex2.get()->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
m_tex2.get()->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
m_tex2.get()->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
m_tex2.get()->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
|
||||
// set render states
|
||||
osg::StateSet *meshstate = meshGeom->getOrCreateStateSet();
|
||||
meshstate->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
meshstate->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
meshstate->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||
meshstate->setTextureAttributeAndModes(0,colortex.get(),osg::StateAttribute::ON);
|
||||
meshstate->setTextureAttributeAndModes(1,m_tex2.get(),osg::StateAttribute::ON);
|
||||
|
||||
// uniforms for height and color scaling
|
||||
maximumUniform = new osg::Uniform( "maximum", (float)maximum );
|
||||
maxheightUniform = new osg::Uniform( "maxheight", (float)maxheight );
|
||||
transparencyUniform = new osg::Uniform( "transparency", (float)transparency);
|
||||
|
||||
osg::Uniform* texUniform = new osg::Uniform(osg::Uniform::SAMPLER_1D, "colortex");
|
||||
texUniform->set(0);
|
||||
osg::Uniform* texUniform2 = new osg::Uniform(osg::Uniform::SAMPLER_2D, "datatex");
|
||||
texUniform2->set(1);
|
||||
meshstate->addUniform(texUniform);
|
||||
meshstate->addUniform(texUniform2);
|
||||
meshstate->addUniform(maximumUniform);
|
||||
meshstate->addUniform(maxheightUniform);
|
||||
meshstate->addUniform(transparencyUniform);
|
||||
|
||||
// add the geometries to the geode.
|
||||
meshGeom->setUseDisplayList(false);
|
||||
addDrawable(meshGeom);
|
||||
}
|
||||
|
||||
void Heatmap::setData(float *buffer, float maxheight, float maximum, float transparency)
|
||||
{
|
||||
memcpy(m_data, buffer, m_N*m_K*sizeof(float));
|
||||
|
||||
maximumUniform->set( maximum );
|
||||
maxheightUniform->set( maxheight );
|
||||
transparencyUniform->set ( transparency );
|
||||
|
||||
m_img2.get()->dirty();
|
||||
}
|
||||
|
||||
Heatmap::~Heatmap()
|
||||
{
|
||||
}
|
33
examples/osgoit/HeatMap.h
Normal file
33
examples/osgoit/HeatMap.h
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef HEATMAP_H
|
||||
#define HEATMAP_H
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Uniform>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Texture1D>
|
||||
|
||||
class Heatmap : public osg::Geode
|
||||
{
|
||||
public:
|
||||
Heatmap(float width, float depth, float maxheight, unsigned int K, unsigned int N, float maximum, float transparency);
|
||||
~Heatmap();
|
||||
|
||||
void setData(float *buffer, float maxheight, float maximum, float transparency);
|
||||
|
||||
protected:
|
||||
unsigned int m_K;
|
||||
unsigned int m_N;
|
||||
float *m_data;
|
||||
osg::ref_ptr<osg::Image> m_img2;
|
||||
osg::ref_ptr<osg::Texture2D> m_tex2;
|
||||
|
||||
osg::ref_ptr<osg::Image> colorimg;
|
||||
osg::ref_ptr<osg::Texture1D> colortex;
|
||||
|
||||
osg::Uniform *maximumUniform;
|
||||
osg::Uniform *maxheightUniform;
|
||||
osg::Uniform *transparencyUniform;
|
||||
};
|
||||
|
||||
#endif // #ifndef HEATMAP_H
|
@ -1,460 +1,49 @@
|
||||
#include <osg/Array>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Depth>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TextureRectangle>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/TexGenNode>
|
||||
/* OpenSceneGraph example, myosgoit.
|
||||
*
|
||||
* Author: Christian Buchner, based on original osgoit by Mathias Frhlich
|
||||
*
|
||||
* This demo provides a DepthPeeling object that can correctly compose
|
||||
* solid and transparent geometry within the same scene. The transparent
|
||||
* geometry can also use GLSL shaders, as demonstrated in the 3D HeatMap.
|
||||
* The solid geometry is only rendered once, and its depth buffer blitted
|
||||
* into the cameras rendering the transparency layers.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include "DepthPeeling.h"
|
||||
#include "HeatMap.h"
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
#include <osg/Math>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Material>
|
||||
#include <osg/LightModel>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
// Some choices for the kind of textures we can use ...
|
||||
#define USE_TEXTURE_RECTANGLE
|
||||
// #define USE_NON_POWER_OF_TWO_TEXTURE
|
||||
#define USE_PACKED_DEPTH_STENCIL
|
||||
|
||||
template<typename T>
|
||||
inline T
|
||||
nextPowerOfTwo(T k)
|
||||
{
|
||||
if (k == T(0))
|
||||
return 1;
|
||||
k--;
|
||||
for (int i = 1; i < std::numeric_limits<T>::digits; i <<= 1)
|
||||
k = k | k >> i;
|
||||
return k + 1;
|
||||
}
|
||||
|
||||
class DepthPeeling : public osg::Referenced {
|
||||
public:
|
||||
osg::Node*
|
||||
createQuad(unsigned layerNumber, unsigned numTiles)
|
||||
{
|
||||
float tileSpan = 1;
|
||||
float tileOffsetX = 0;
|
||||
float tileOffsetY = 0;
|
||||
if (_showAllLayers) {
|
||||
tileSpan /= numTiles;
|
||||
tileOffsetX = tileSpan * (layerNumber%numTiles);
|
||||
tileOffsetY = 1 - tileSpan * (1 + layerNumber/numTiles);
|
||||
}
|
||||
|
||||
osg::Vec3Array* vertices = new osg::Vec3Array;
|
||||
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX , tileOffsetY , 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX , tileOffsetY + tileSpan, 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY + tileSpan, 0));
|
||||
vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY , 0));
|
||||
|
||||
osg::Vec3Array* colors = new osg::Vec3Array;
|
||||
colors->push_back(osg::Vec3(1, 1, 1));
|
||||
|
||||
osg::Vec2Array* texcoords = new osg::Vec2Array;
|
||||
texcoords->push_back(osg::Vec2f(0, 0));
|
||||
texcoords->push_back(osg::Vec2f(0, 1));
|
||||
texcoords->push_back(osg::Vec2f(1, 1));
|
||||
texcoords->push_back(osg::Vec2f(1, 0));
|
||||
|
||||
osg::Geometry* geometry = new osg::Geometry;
|
||||
geometry->setVertexArray(vertices);
|
||||
geometry->setTexCoordArray(0, texcoords);
|
||||
|
||||
geometry->setColorArray(colors);
|
||||
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
|
||||
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
class CullCallback : public osg::NodeCallback {
|
||||
public:
|
||||
CullCallback(unsigned texUnit, unsigned texWidth, unsigned texHeight, unsigned offsetValue) :
|
||||
_texUnit(texUnit),
|
||||
_texWidth(texWidth),
|
||||
_texHeight(texHeight),
|
||||
_offsetValue(offsetValue)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
|
||||
osgUtil::RenderStage* renderStage = cullVisitor->getCurrentRenderStage();
|
||||
const osg::Viewport* viewport = renderStage->getViewport();
|
||||
|
||||
osg::Matrixd m(*cullVisitor->getProjectionMatrix());
|
||||
m.postMultTranslate(osg::Vec3d(1, 1, 1));
|
||||
m.postMultScale(osg::Vec3d(0.5, 0.5, 0.5));
|
||||
|
||||
// scale the texture coordinates to the viewport
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
m.postMultScale(osg::Vec3d(viewport->width(), viewport->height(), 1));
|
||||
#else
|
||||
#ifndef USE_NON_POWER_OF_TWO_TEXTURE
|
||||
m.postMultScale(osg::Vec3d(viewport->width()/double(_texWidth), viewport->height()/double(_texHeight), 1));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Kind of polygon offset: note this way, we can also offset lines and points.
|
||||
// Whereas with the polygon offset we could only handle surface primitives.
|
||||
m.postMultTranslate(osg::Vec3d(0, 0, -ldexp(double(_offsetValue), -24)));
|
||||
|
||||
osg::TexMat* texMat = new osg::TexMat(m);
|
||||
osg::StateSet* stateSet = new osg::StateSet;
|
||||
stateSet->setTextureAttribute(_texUnit, texMat);
|
||||
cullVisitor->pushStateSet(stateSet);
|
||||
traverse(node, nv);
|
||||
cullVisitor->popStateSet();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned _texUnit;
|
||||
unsigned _texWidth;
|
||||
unsigned _texHeight;
|
||||
unsigned _offsetValue;
|
||||
};
|
||||
|
||||
void
|
||||
createPeeling()
|
||||
{
|
||||
int numTiles = ceil(sqrt(double(_numPasses)));
|
||||
|
||||
_root->removeChildren(0, _root->getNumChildren());
|
||||
_colorTextures.clear();
|
||||
|
||||
// If not enabled, just use the top level camera
|
||||
if (!_depthPeelingEnabled) {
|
||||
_root->addChild(_scene.get());
|
||||
return;
|
||||
}
|
||||
|
||||
_compositeCamera = new osg::Camera;
|
||||
_compositeCamera->setDataVariance(osg::Object::DYNAMIC);
|
||||
_compositeCamera->setInheritanceMask(osg::Camera::READ_BUFFER | osg::Camera::DRAW_BUFFER);
|
||||
_compositeCamera->setRenderOrder(osg::Camera::POST_RENDER);
|
||||
_compositeCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
|
||||
_compositeCamera->setClearMask(0);
|
||||
|
||||
_compositeCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
_compositeCamera->setViewMatrix(osg::Matrix());
|
||||
_compositeCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||
|
||||
_compositeCamera->setCullCallback(new CullCallback(0, _texWidth, _texHeight, 0));
|
||||
|
||||
osg::StateSet* stateSet = _compositeCamera->getOrCreateStateSet();
|
||||
stateSet->setBinName("TraversalOrderBin");
|
||||
stateSet->setRenderBinMode(osg::StateSet::USE_RENDERBIN_DETAILS);
|
||||
|
||||
_root->addChild(_compositeCamera.get());
|
||||
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_depthTextures[i] = new osg::TextureRectangle;
|
||||
#else
|
||||
_depthTextures[i] = new osg::Texture2D;
|
||||
#endif
|
||||
_depthTextures[i]->setTextureSize(_texWidth, _texHeight);
|
||||
|
||||
_depthTextures[i]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
_depthTextures[i]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
_depthTextures[i]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
|
||||
_depthTextures[i]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
|
||||
|
||||
#ifdef USE_PACKED_DEPTH_STENCIL
|
||||
_depthTextures[i]->setInternalFormat(GL_DEPTH24_STENCIL8_EXT);
|
||||
_depthTextures[i]->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||
_depthTextures[i]->setSourceType(GL_UNSIGNED_INT_24_8_EXT);
|
||||
#else
|
||||
_depthTextures[i]->setInternalFormat(GL_DEPTH_COMPONENT);
|
||||
_depthTextures[i]->setInternalFormat(GL_DEPTH_COMPONENT24);
|
||||
#endif
|
||||
|
||||
_depthTextures[i]->setShadowComparison(true);
|
||||
_depthTextures[i]->setShadowAmbient(0); // The r value if the test fails
|
||||
_depthTextures[i]->setShadowCompareFunc(osg::Texture::GREATER);
|
||||
_depthTextures[i]->setShadowTextureMode(osg::Texture::INTENSITY);
|
||||
}
|
||||
|
||||
// Then, the other ones
|
||||
for (unsigned i = 0; i < _numPasses; ++i) {
|
||||
osg::Camera* camera = new osg::Camera;
|
||||
camera->setDataVariance(osg::Object::DYNAMIC);
|
||||
|
||||
camera->setInheritanceMask(osg::Camera::ALL_VARIABLES);
|
||||
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER, i);
|
||||
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
camera->setClearColor(osg::Vec4f(0, 0, 0, 0));
|
||||
|
||||
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
|
||||
osg::ref_ptr<osg::Texture> depthTexture = _depthTextures[i%2];
|
||||
osg::ref_ptr<osg::Texture> prevDepthTexture = _depthTextures[(i+1)%2];
|
||||
|
||||
#ifdef USE_PACKED_DEPTH_STENCIL
|
||||
camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, depthTexture.get());
|
||||
#else
|
||||
camera->attach(osg::Camera::DEPTH_BUFFER, depthTexture.get());
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
osg::ref_ptr<osg::TextureRectangle> colorTexture = new osg::TextureRectangle;
|
||||
#else
|
||||
osg::ref_ptr<osg::Texture2D> colorTexture = new osg::Texture2D;
|
||||
#endif
|
||||
_colorTextures.push_back(colorTexture);
|
||||
|
||||
colorTexture->setTextureSize(_texWidth, _texHeight);
|
||||
colorTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
colorTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
colorTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
|
||||
colorTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
|
||||
colorTexture->setInternalFormat(GL_RGBA);
|
||||
camera->attach(osg::Camera::COLOR_BUFFER, colorTexture.get());
|
||||
|
||||
camera->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
|
||||
if (0 == i) {
|
||||
camera->addChild(_scene.get());
|
||||
} else {
|
||||
osg::StateSet* stateSet = camera->getOrCreateStateSet();
|
||||
|
||||
stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01),
|
||||
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
stateSet->setTextureAttributeAndModes(_texUnit, prevDepthTexture.get());
|
||||
|
||||
// Is the default ...
|
||||
// stateSet->setTextureAttributeAndModes(_texUnit, new osg::TexEnv(osg::TexEnv::MODULATE));
|
||||
stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
|
||||
stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
|
||||
stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
|
||||
stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);
|
||||
|
||||
osg::TexGenNode* texGenNode = new osg::TexGenNode;
|
||||
texGenNode->setReferenceFrame(osg::TexGenNode::ABSOLUTE_RF);
|
||||
texGenNode->setTextureUnit(_texUnit);
|
||||
texGenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
|
||||
camera->addChild(texGenNode);
|
||||
camera->addCullCallback(new CullCallback(_texUnit, _texWidth, _texHeight, _offsetValue));
|
||||
|
||||
texGenNode->addChild(_scene.get());
|
||||
}
|
||||
|
||||
_root->addChild(camera);
|
||||
|
||||
osg::Node* geode = createQuad(i, numTiles);
|
||||
osg::StateSet* stateSet = geode->getOrCreateStateSet();
|
||||
stateSet->setTextureAttributeAndModes(0, colorTexture.get(), osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
_compositeCamera->insertChild(0, geode);
|
||||
}
|
||||
}
|
||||
|
||||
DepthPeeling(unsigned width, unsigned height) :
|
||||
_numPasses(8),
|
||||
_texUnit(1),
|
||||
_texWidth(width),
|
||||
_texHeight(height),
|
||||
_showAllLayers(false),
|
||||
_depthPeelingEnabled(true),
|
||||
_offsetValue(8),
|
||||
_root(new osg::Group),
|
||||
_scene(new osg::Group)
|
||||
{
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void setScene(osg::Node* scene)
|
||||
{
|
||||
_scene->removeChildren(0, _scene->getNumChildren());
|
||||
_scene->addChild(scene);
|
||||
}
|
||||
|
||||
osg::Node* getRoot()
|
||||
{
|
||||
return _root.get();
|
||||
}
|
||||
|
||||
void resize(int width, int height)
|
||||
{
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
_depthTextures[0]->setTextureSize(width, height);
|
||||
_depthTextures[1]->setTextureSize(width, height);
|
||||
for (unsigned i = 0; i < _colorTextures.size(); ++i)
|
||||
_colorTextures[i]->setTextureSize(width, height);
|
||||
_texWidth = width;
|
||||
_texHeight = height;
|
||||
#else
|
||||
#ifndef USE_NON_POWER_OF_TWO_TEXTURE
|
||||
width = nextPowerOfTwo(width);
|
||||
height = nextPowerOfTwo(height);
|
||||
#endif
|
||||
_depthTextures[0]->setTextureSize(width, height);
|
||||
_depthTextures[1]->setTextureSize(width, height);
|
||||
for (unsigned i = 0; i < _colorTextures.size(); ++i)
|
||||
_colorTextures[i]->setTextureSize(width, height);
|
||||
_texWidth = width;
|
||||
_texHeight = height;
|
||||
#endif
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void setNumPasses(unsigned numPasses)
|
||||
{
|
||||
if (numPasses == _numPasses)
|
||||
return;
|
||||
if (numPasses == unsigned(-1))
|
||||
return;
|
||||
_numPasses = numPasses;
|
||||
createPeeling();
|
||||
}
|
||||
unsigned getNumPasses() const
|
||||
{
|
||||
return _numPasses;
|
||||
}
|
||||
|
||||
void setTexUnit(unsigned texUnit)
|
||||
{
|
||||
if (texUnit == _texUnit)
|
||||
return;
|
||||
_texUnit = texUnit;
|
||||
createPeeling();
|
||||
}
|
||||
|
||||
void setShowAllLayers(bool showAllLayers)
|
||||
{
|
||||
if (showAllLayers == _showAllLayers)
|
||||
return;
|
||||
_showAllLayers = showAllLayers;
|
||||
createPeeling();
|
||||
}
|
||||
bool getShowAllLayers() const
|
||||
{
|
||||
return _showAllLayers;
|
||||
}
|
||||
|
||||
void setDepthPeelingEnabled(bool depthPeelingEnabled)
|
||||
{
|
||||
if (depthPeelingEnabled == _depthPeelingEnabled)
|
||||
return;
|
||||
_depthPeelingEnabled = depthPeelingEnabled;
|
||||
createPeeling();
|
||||
}
|
||||
bool getDepthPeelingEnabled() const
|
||||
{
|
||||
return _depthPeelingEnabled;
|
||||
}
|
||||
|
||||
void setOffsetValue(unsigned offsetValue)
|
||||
{
|
||||
if (offsetValue == _offsetValue)
|
||||
return;
|
||||
_offsetValue = offsetValue;
|
||||
createPeeling();
|
||||
}
|
||||
unsigned getOffsetValue() const
|
||||
{
|
||||
return _offsetValue;
|
||||
}
|
||||
|
||||
unsigned _numPasses;
|
||||
unsigned _texUnit;
|
||||
unsigned _texWidth;
|
||||
unsigned _texHeight;
|
||||
bool _showAllLayers;
|
||||
bool _depthPeelingEnabled;
|
||||
unsigned _offsetValue;
|
||||
|
||||
// The root node that is handed over to the viewer
|
||||
osg::ref_ptr<osg::Group> _root;
|
||||
|
||||
// The scene that is displayed
|
||||
osg::ref_ptr<osg::Group> _scene;
|
||||
|
||||
// The final camera that composites the pre rendered textures to the final picture
|
||||
osg::ref_ptr<osg::Camera> _compositeCamera;
|
||||
|
||||
#ifdef USE_TEXTURE_RECTANGLE
|
||||
osg::ref_ptr<osg::TextureRectangle> _depthTextures[2];
|
||||
std::vector<osg::ref_ptr<osg::TextureRectangle> > _colorTextures;
|
||||
#else
|
||||
osg::ref_ptr<osg::Texture2D> _depthTextures[2];
|
||||
std::vector<osg::ref_ptr<osg::Texture2D> > _colorTextures;
|
||||
#endif
|
||||
};
|
||||
|
||||
class EventHandler : public osgGA::GUIEventHandler {
|
||||
public:
|
||||
EventHandler(DepthPeeling* depthPeeling) :
|
||||
_depthPeeling(depthPeeling)
|
||||
{ }
|
||||
|
||||
/** Handle events, return true if handled, false otherwise. */
|
||||
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
|
||||
{
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) {
|
||||
_depthPeeling->resize(ea.getWindowWidth(), ea.getWindowHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
|
||||
switch (ea.getKey()) {
|
||||
case 'd':
|
||||
_depthPeeling->setDepthPeelingEnabled(!_depthPeeling->getDepthPeelingEnabled());
|
||||
return true;
|
||||
case 'm':
|
||||
_depthPeeling->setNumPasses(_depthPeeling->getNumPasses() + 1);
|
||||
return true;
|
||||
case 'n':
|
||||
_depthPeeling->setNumPasses(_depthPeeling->getNumPasses() - 1);
|
||||
return true;
|
||||
case 'p':
|
||||
_depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() + 1);
|
||||
return true;
|
||||
case 'o':
|
||||
_depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() - 1);
|
||||
return true;
|
||||
case 'l':
|
||||
_depthPeeling->setShowAllLayers(!_depthPeeling->getShowAllLayers());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
osg::ref_ptr<DepthPeeling> _depthPeeling;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// use an ArgumentParser object to manage the program arguments.
|
||||
osg::ArgumentParser arguments(&argc, argv);
|
||||
arguments.getApplicationUsage()->addKeyboardMouseBinding("d", "Toggle depth peeling enabled");
|
||||
arguments.getApplicationUsage()->addKeyboardMouseBinding("m", "Increase the number of depth peeling layers");
|
||||
arguments.getApplicationUsage()->addKeyboardMouseBinding("n", "Decrease the number of depth peeling layers");
|
||||
arguments.getApplicationUsage()->addKeyboardMouseBinding("l", "Toggle display of the individual or composed layer textures");
|
||||
@ -473,31 +62,65 @@ int main(int argc, char** argv)
|
||||
// add the help handler
|
||||
viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
|
||||
|
||||
// load the data
|
||||
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
|
||||
if (!loadedModel)
|
||||
{
|
||||
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// any option left unread are converted into errors to write out later.
|
||||
arguments.reportRemainingOptionsAsUnrecognized();
|
||||
|
||||
// report any errors if they have occurred when parsing the program arguments.
|
||||
if (arguments.errors())
|
||||
{
|
||||
arguments.writeErrorMessages(std::cout);
|
||||
return 1;
|
||||
}
|
||||
// read the dump truck, we will need it twice
|
||||
osg::ref_ptr<osg::Node> dt = osgDB::readNodeFile("dumptruck.osg");
|
||||
|
||||
// The initial size sez to 0, 0. We get a resize event for the right size ...
|
||||
// display a solid version of the dump truck
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> solidModel = new osg::PositionAttitudeTransform;
|
||||
solidModel->setPosition(osg::Vec3f(7.0f, -2.0f, 7.0f));
|
||||
solidModel->addChild(dt.get());
|
||||
|
||||
// generate the 3D heatmap surface to display
|
||||
osg::ref_ptr<Heatmap> hm = new Heatmap(30, 30, 10, 30, 30, 1.0, 0.25);
|
||||
float data[30][30];
|
||||
for (int x=0; x < 30; ++x)
|
||||
for (int y=0; y < 30; ++y)
|
||||
data[y][x] = (double)rand() / RAND_MAX;
|
||||
hm->setData((float*)data, 10.0, 1.0, 0.25);
|
||||
|
||||
// add a transparent version of the truck to the scene also
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> transparentTruck = new osg::PositionAttitudeTransform;
|
||||
transparentTruck->setPosition(osg::Vec3f(7.0f, -25.0f, 7.0f));
|
||||
|
||||
// set the states of the truck so that it actually appears transparently and nicely lit.
|
||||
osg::StateSet *state = transparentTruck->getOrCreateStateSet();
|
||||
state->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
osg::Material* material = new osg::Material;
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.2f,0.2f,0.2f,0.3f));
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(0.8f,0.8f,0.8f,0.3f));
|
||||
state->setAttribute(material,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
osg::LightModel *lm = new osg::LightModel();
|
||||
lm->setTwoSided(true);
|
||||
state->setAttribute(lm, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
(transparentTruck.get())->addChild(dt.get());
|
||||
|
||||
// place the heatmap and a transparent dump truck in the transparent geometry group
|
||||
osg::ref_ptr<osg::Group> transparentModel = new osg::Group;
|
||||
(transparentModel.get())->addChild(hm.get());
|
||||
(transparentModel.get())->addChild(transparentTruck.get());
|
||||
|
||||
// The initial size set to 0, 0. We get a resize event for the right size...
|
||||
DepthPeeling* depthPeeling = new DepthPeeling(0, 0);
|
||||
depthPeeling->setScene(loadedModel.get());
|
||||
// the heat map already uses two textures bound to unit 0 and 1, so we can use TexUnit 2 for the peeling
|
||||
depthPeeling->setTexUnit(2);
|
||||
depthPeeling->setSolidScene(solidModel.get());
|
||||
depthPeeling->setTransparentScene(transparentModel.get());
|
||||
viewer.setSceneData(depthPeeling->getRoot());
|
||||
|
||||
// Add the event handler for the depth peeling stuff
|
||||
viewer.addEventHandler(new EventHandler(depthPeeling));
|
||||
viewer.addEventHandler(new DepthPeeling::EventHandler(depthPeeling));
|
||||
|
||||
// force a resize event, so the DepthPeeling object updates _texWidth and _texHeight
|
||||
viewer.realize();
|
||||
int x, y, width, height;
|
||||
osgViewer::ViewerBase::Windows windows;
|
||||
viewer.getWindows(windows);
|
||||
windows.front()->getWindowRectangle(x,y,width,height);
|
||||
viewer.getEventQueue()->windowResize(x,y,width,height);
|
||||
|
||||
return viewer.run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user