You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.4 KiB
C
136 lines
4.4 KiB
C
|
1 month ago
|
#pragma once
|
||
|
|
|
||
|
|
// This code was adapted from the osgoit.cpp example.
|
||
|
|
|
||
|
|
#include <osg/Group>
|
||
|
|
#include <osg/Switch>
|
||
|
|
#include <osg/Texture>
|
||
|
|
|
||
|
|
namespace osgtt
|
||
|
|
{
|
||
|
|
|
||
|
|
// A DepthPeeling object is an osg::Group that uses OSG's RTT support to setup
|
||
|
|
// an arbitrary number of passes to use to attempt to render a transparent scene
|
||
|
|
// as accurately as possible. It is not reccomended that you use this object
|
||
|
|
// as a generic group, as the children you add will be deleted every time
|
||
|
|
// dirty() is called.
|
||
|
|
//
|
||
|
|
// This object will create $numPasses RTT cameras and a single "composite"
|
||
|
|
// camera and add them as required to itself. There is currently no support
|
||
|
|
// for stretching an RTT stack internally to fit a viewport that isn't a
|
||
|
|
// 1:1 ratio of texture:view dimensions. This could be achieved by modifying
|
||
|
|
// the CullCallback.
|
||
|
|
//
|
||
|
|
// Note that while we need to create a color buffer for each peel/pass, we can
|
||
|
|
// optimize by only using two depth buffers; modulo-ing (for lack of a better word)
|
||
|
|
// ourselves by using one-or-the-other for each pass.
|
||
|
|
class DepthPeeling: public osg::Switch
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
// Whether the RTT "stack" will use power-of-two textures or texture
|
||
|
|
// rectangles. Your platform will dictate the best choice.
|
||
|
|
enum TextureMode
|
||
|
|
{
|
||
|
|
TEXTURE_STANDARD,
|
||
|
|
TEXTURE_RECTANGLE
|
||
|
|
};
|
||
|
|
|
||
|
|
enum DepthMode
|
||
|
|
{
|
||
|
|
DEPTH_STANDARD,
|
||
|
|
DEPTH_PACKED_STENCIL
|
||
|
|
};
|
||
|
|
|
||
|
|
// This CullCallback is responsible for the projective texturing magic that
|
||
|
|
// is required by the depth peeling technique to function properly.
|
||
|
|
class CullCallback: public osg::NodeCallback
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
CullCallback(
|
||
|
|
unsigned int texUnit,
|
||
|
|
unsigned int texWidth,
|
||
|
|
unsigned int texHeight,
|
||
|
|
unsigned int offsetValue,
|
||
|
|
TextureMode textureMode
|
||
|
|
);
|
||
|
|
|
||
|
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
||
|
|
|
||
|
|
private:
|
||
|
|
unsigned int _texUnit;
|
||
|
|
unsigned int _texWidth;
|
||
|
|
unsigned int _texHeight;
|
||
|
|
unsigned int _offsetValue;
|
||
|
|
TextureMode _textureMode;
|
||
|
|
};
|
||
|
|
|
||
|
|
// You should initialize the DepthPeeling group to the screen's width/height
|
||
|
|
// (if possible) at creation. This isn't mandatory on Windows, but is on Linux.
|
||
|
|
DepthPeeling(unsigned int width = 0, unsigned int height = 0);
|
||
|
|
|
||
|
|
// This method should be called anytime the parent Viewport or window is
|
||
|
|
// resized. It will, if necessary, reallocate the internal texture stack.
|
||
|
|
void resize(int width, int height);
|
||
|
|
|
||
|
|
// This is the "beef" of the DepthPeeling object. It will create the entire
|
||
|
|
// RTT stack and composite viewing camera based on whatever options are currently
|
||
|
|
// set. It should be called any time you change depth peeling settings.
|
||
|
|
//
|
||
|
|
// Conviently, most methods do this for you automatically, so its likely you'll
|
||
|
|
// never have to worry about it.
|
||
|
|
void dirty();
|
||
|
|
|
||
|
|
osg::Node* getScene() {return _scene.get();}
|
||
|
|
|
||
|
|
const osg::Node* getScene() const {return _scene.get();}
|
||
|
|
|
||
|
|
// This is the scene/subgraph which your render-to-texture cameras are pointed at.
|
||
|
|
void setScene(osg::Node* scene) {_scene = scene;}
|
||
|
|
|
||
|
|
// The number of "peels" or layers that are used to chop up your transparent
|
||
|
|
// scene. The composite camera will combine each pass into a composited, blended
|
||
|
|
// final image.
|
||
|
|
void setNumPasses(unsigned int numPasses)
|
||
|
|
{
|
||
|
|
_numPasses = numPasses;
|
||
|
|
// I added
|
||
|
|
dirty();
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned int getNumPasses() const {return _numPasses;}
|
||
|
|
|
||
|
|
// Here you can set the actualy GL_TEXTURE* unit that should be used. This will
|
||
|
|
// almost certainly be ncessary for you to call if your scene is using texturing,
|
||
|
|
// otherwise you'll need to make sure your existing state doesn't use GL_TEXTURE0,
|
||
|
|
// which is the (arguably silly) default.
|
||
|
|
void setTexUnit(unsigned int texUnit) {_texUnit = texUnit;}
|
||
|
|
|
||
|
|
// This is the depth offset used by the CullCallback during the projective
|
||
|
|
// texturing to determine the next "peel" layer. It's generally safe to leave
|
||
|
|
// this alone.
|
||
|
|
void setOffsetValue(unsigned int offsetValue) {_offsetValue = offsetValue;}
|
||
|
|
|
||
|
|
unsigned int getOffsetValue() const {return _offsetValue;}
|
||
|
|
|
||
|
|
unsigned int getTexWidth() const {return _texWidth;}
|
||
|
|
|
||
|
|
unsigned int getTexHeight() const {return _texHeight;}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
TextureMode _textureMode;
|
||
|
|
DepthMode _depthMode;
|
||
|
|
unsigned int _numPasses;
|
||
|
|
unsigned int _texUnit;
|
||
|
|
unsigned int _texWidth;
|
||
|
|
unsigned int _texHeight;
|
||
|
|
unsigned int _offsetValue;
|
||
|
|
|
||
|
|
osg::ref_ptr<osg::Node> _scene;
|
||
|
|
osg::ref_ptr<osg::Camera> _compositeCamera;
|
||
|
|
osg::ref_ptr<osg::Texture> _depthTextures[2];
|
||
|
|
std::vector<osg::ref_ptr<osg::Texture> > _colorTextures;
|
||
|
|
};
|
||
|
|
|
||
|
|
}
|
||
|
|
|