天天看點

osg輪廓特效

// -*-c++-*-

#ifndef OSGFX_OUTLINE_

#define OSGFX_OUTLINE_

#include <osgFX/Export>

#include <osgFX/Effect>

namespace osgFX

{

    class Outline : public Effect

    {

    public:

        /// Constructor.

        Outline();

        Outline(const Outline& copy,

                const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY)

            : Effect(copy, op) {

            _width = copy._width;

            _color = copy._color;

        }

        // Effect class info

        META_Effect(osgFX, Outline, "Outline",

                    "Stencil buffer based object outlining.",

                    "Ulrich Hertlein <[email protected]>");

        /// Set outline width.

        void setWidth(float w) {

            _width = w;

        }

        /// Get outline width.

        float getWidth() const {

            return _width;

        }

        /// Set outline color.

        void setColor(const osg::Vec4& col) {

            _color = col;

        }

        /// Get outline color.

        const osg::Vec4& getColor() const {

            return _color;

        }

    protected:

        /// Destructor.

        virtual ~Outline() {

        }

        /// Define available techniques.

        bool define_techniques();

    private:

        /// Outline width.

        float _width;

        /// Outline color.

        osg::Vec4 _color;

    };

};

#endif

// -*-c++-*-

#include <osgFX/Outline>

#include <osgFX/Registry>

#include <osg/Group>

#include <osg/Stencil>

#include <osg/CullFace>

#include <osg/PolygonMode>

#include <osg/LineWidth>

#include <osg/Material>

#include <osg/NodeCallback>

#include <osgUtil/CullVisitor>

#include <iostream>

const unsigned int Override_On = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;

const unsigned int Override_Off = osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE;

namespace osgFX

{

    /// Register prototype.

    Registry::Proxy proxy(new Outline);

    class OutlineTechnique : public Technique

    {

    public:

        /// Constructor.

        OutlineTechnique(const Outline& outline) : Technique() {

            _outline = &outline;

        }

        /// Validate.

        bool validate(osg::State&) const {

            return true;

        }

    protected:

        /// Define render passes.

        void define_passes() {

            {

                osg::StateSet* state = new osg::StateSet;

                // stencil op

                osg::Stencil* stencil  = new osg::Stencil;

                stencil->setFunction(osg::Stencil::ALWAYS, 1, ~0);

                stencil->setOperation(osg::Stencil::KEEP,

                                      osg::Stencil::KEEP,

                                      osg::Stencil::REPLACE);

                state->setAttributeAndModes(stencil, Override_On);

                addPass(state);

            }

            {

                osg::StateSet* state = new osg::StateSet;

                // stencil op

                osg::Stencil* stencil  = new osg::Stencil;

                stencil->setFunction(osg::Stencil::NOTEQUAL, 1, ~0);

                stencil->setOperation(osg::Stencil::KEEP,

                                      osg::Stencil::KEEP,

                                      osg::Stencil::REPLACE);

                state->setAttributeAndModes(stencil, Override_On);

                // cull front-facing polys

                osg::CullFace* cf = new osg::CullFace;

                cf->setMode(osg::CullFace::FRONT);

                state->setAttributeAndModes(cf, Override_On);

                // poly mode for back-facing polys

                osg::PolygonMode* pm = new osg::PolygonMode;

                pm->setMode(osg::PolygonMode::BACK, osg::PolygonMode::LINE);

                state->setAttributeAndModes(pm, Override_On);

                // outline width

                osg::LineWidth* lw = new osg::LineWidth;

                lw->setWidth(_outline->getWidth());

                state->setAttributeAndModes(lw, Override_On);

                // outline color/material

                const osg::Material::Face face = osg::Material::FRONT_AND_BACK;

                osg::Material* mtl = new osg::Material;

                mtl->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);

                mtl->setAmbient(face, _outline->getColor());

                mtl->setDiffuse(face, _outline->getColor());

                mtl->setEmission(face, _outline->getColor());

                state->setAttributeAndModes(mtl, Override_On);

                // disable modes

                state->setMode(GL_BLEND, Override_Off);

                state->setMode(GL_DEPTH_TEST, Override_Off);

                state->setTextureMode(0, GL_TEXTURE_1D, Override_Off);

                state->setTextureMode(0, GL_TEXTURE_2D, Override_Off);

                state->setTextureMode(0, GL_TEXTURE_3D, Override_Off);

                addPass(state);

            }

        }

    private:

        /// Outline effect.

        osg::ref_ptr<const Outline> _outline;

    };

    class EnableStencilCallback : public osg::NodeCallback

    {

    public:

        EnableStencilCallback() {}

        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {

            osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);

            if (cv) {

                // enable stencil clear on render stage

                osgUtil::RenderStage* render = cv->getRenderStage();

                unsigned int mask = render->getClearMask();

                if ((mask & GL_STENCIL_BUFFER_BIT) == 0) {

                    render->setClearMask(mask | GL_STENCIL_BUFFER_BIT);

                    render->setClearStencil(0);

                    //std::cerr << "osgFX::Outline activated stencil/n";

                }

            }

            traverse(node, nv);

        }

    private:

    };

    /// Constructor.

    Outline::Outline() : Effect()

    {

        _width = 3.0f;

        _color.set(1.0f,1.0f,1.0f,1.0f);

        addCullCallback(new EnableStencilCallback);

    }

    /// Define available techniques.

    bool Outline::define_techniques()

    {

        addTechnique(new OutlineTechnique(*this));

        return true;

    }

};

繼續閱讀