Added osg::StencilTwoSided state attribute to wrap up the stencil_two_sided extension.
Added path in osgShadow work for using StencilTwoSided to accelerate shadow volume rendering.
This commit is contained in:
@@ -95,6 +95,7 @@ CXXFILES =\
|
||||
StateAttribute.cpp\
|
||||
StateSet.cpp\
|
||||
Stencil.cpp\
|
||||
StencilTwoSided.cpp\
|
||||
Switch.cpp\
|
||||
TexEnvCombine.cpp\
|
||||
TexEnv.cpp\
|
||||
|
||||
160
src/osg/StencilTwoSided.cpp
Normal file
160
src/osg/StencilTwoSided.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 <osg/StencilTwoSided>
|
||||
#include <osg/State>
|
||||
#include <osg/GLExtensions>
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osg;
|
||||
|
||||
StencilTwoSided::StencilTwoSided()
|
||||
{
|
||||
// set up same defaults as glStencilFunc.
|
||||
_func[FRONT] = _func[BACK] = ALWAYS;
|
||||
_funcRef[FRONT] = _funcRef[BACK] = 0;
|
||||
_funcMask[FRONT] = _funcMask[BACK] = ~0u;
|
||||
|
||||
// set up same defaults as glStencilOp.
|
||||
_sfail[FRONT] = _sfail[BACK] = KEEP;
|
||||
_zfail[FRONT] = _zfail[BACK] = KEEP;
|
||||
_zpass[FRONT] = _zpass[BACK] = KEEP;
|
||||
|
||||
_writeMask[FRONT] = _writeMask[BACK] = ~0u;
|
||||
}
|
||||
|
||||
StencilTwoSided::StencilTwoSided(const StencilTwoSided& stencil,const CopyOp& copyop):
|
||||
StateAttribute(stencil,copyop)
|
||||
{
|
||||
_func[FRONT] = stencil._func[FRONT];
|
||||
_funcRef[FRONT] = stencil._funcRef[FRONT];
|
||||
_funcMask[FRONT] = stencil._funcMask[FRONT];
|
||||
_sfail[FRONT] = stencil._sfail[FRONT];
|
||||
_zfail[FRONT] = stencil._zfail[FRONT];
|
||||
_zpass[FRONT] = stencil._zpass[FRONT];
|
||||
_writeMask[FRONT] = stencil._writeMask[FRONT];
|
||||
|
||||
_func[BACK] = stencil._func[BACK];
|
||||
_funcRef[BACK] = stencil._funcRef[BACK];
|
||||
_funcMask[BACK] = stencil._funcMask[BACK];
|
||||
_sfail[BACK] = stencil._sfail[BACK];
|
||||
_zfail[BACK] = stencil._zfail[BACK];
|
||||
_zpass[BACK] = stencil._zpass[BACK];
|
||||
_writeMask[BACK] = stencil._writeMask[BACK];
|
||||
}
|
||||
|
||||
StencilTwoSided::~StencilTwoSided()
|
||||
{
|
||||
}
|
||||
|
||||
int StencilTwoSided::compare(const StateAttribute& sa) const
|
||||
{
|
||||
// check the types are equal and then create the rhs variable
|
||||
// used by the COMPARE_StateAttribute_Parameter macro's below.
|
||||
COMPARE_StateAttribute_Types(StencilTwoSided,sa)
|
||||
|
||||
// compare each parameter in turn against the rhs.
|
||||
COMPARE_StateAttribute_Parameter(_func[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_funcRef[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_funcMask[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_sfail[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_zfail[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_zpass[FRONT])
|
||||
COMPARE_StateAttribute_Parameter(_writeMask[FRONT])
|
||||
|
||||
COMPARE_StateAttribute_Parameter(_func[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_funcRef[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_funcMask[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_sfail[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_zfail[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_zpass[BACK])
|
||||
COMPARE_StateAttribute_Parameter(_writeMask[BACK])
|
||||
|
||||
return 0; // passed all the above comparison macro's, must be equal.
|
||||
}
|
||||
|
||||
void StencilTwoSided::apply(State& state) const
|
||||
{
|
||||
const unsigned int contextID = state.getContextID();
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
|
||||
if (!extensions->isStencilTwoSidedSupported())
|
||||
return;
|
||||
|
||||
extensions->glActiveStencilFace(GL_BACK);
|
||||
glStencilOp((GLenum)_sfail[BACK],(GLenum)_zfail[BACK],(GLenum)_zpass[BACK]);
|
||||
glStencilMask(_writeMask[BACK]);
|
||||
glStencilFunc((GLenum)_func[BACK],_funcRef[BACK],_funcMask[BACK]);
|
||||
|
||||
extensions->glActiveStencilFace(GL_FRONT);
|
||||
glStencilOp((GLenum)_sfail[FRONT],(GLenum)_zfail[FRONT],(GLenum)_zpass[FRONT]);
|
||||
glStencilMask(_writeMask[FRONT]);
|
||||
glStencilFunc((GLenum)_func[FRONT],_funcRef[FRONT],_funcMask[FRONT]);
|
||||
}
|
||||
|
||||
|
||||
typedef buffered_value< ref_ptr<StencilTwoSided::Extensions> > BufferedExtensions;
|
||||
static BufferedExtensions s_extensions;
|
||||
|
||||
StencilTwoSided::Extensions* StencilTwoSided::getExtensions(unsigned int contextID,bool createIfNotInitalized)
|
||||
{
|
||||
if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
|
||||
return s_extensions[contextID].get();
|
||||
}
|
||||
|
||||
void StencilTwoSided::setExtensions(unsigned int contextID,Extensions* extensions)
|
||||
{
|
||||
s_extensions[contextID] = extensions;
|
||||
}
|
||||
|
||||
StencilTwoSided::Extensions::Extensions(unsigned int contextID)
|
||||
{
|
||||
setupGLExtenions(contextID);
|
||||
}
|
||||
|
||||
StencilTwoSided::Extensions::Extensions(const Extensions& rhs):
|
||||
Referenced()
|
||||
{
|
||||
_isStencilTwoSidedSupported = rhs._isStencilTwoSidedSupported;
|
||||
_glActiveStencilFace = rhs._glActiveStencilFace;
|
||||
}
|
||||
|
||||
|
||||
void StencilTwoSided::Extensions::lowestCommonDenominator(const Extensions& rhs)
|
||||
{
|
||||
if (!rhs._isStencilTwoSidedSupported) _isStencilTwoSidedSupported = false;
|
||||
|
||||
if (!rhs._glActiveStencilFace) _glActiveStencilFace = 0;
|
||||
|
||||
}
|
||||
|
||||
void StencilTwoSided::Extensions::setupGLExtenions(unsigned int contextID)
|
||||
{
|
||||
_isStencilTwoSidedSupported = isGLExtensionSupported(contextID,"GL_EXT_stencil_two_side");
|
||||
|
||||
_glActiveStencilFace = osg::getGLExtensionFuncPtr("glActiveStencilFace","glActiveStencilFaceEXT");
|
||||
}
|
||||
|
||||
void StencilTwoSided::Extensions::glActiveStencilFace(GLenum face) const
|
||||
{
|
||||
if (_glActiveStencilFace)
|
||||
{
|
||||
typedef void (APIENTRY * ActiveStencilFaceProc) (GLenum);
|
||||
((ActiveStencilFaceProc)_glActiveStencilFace)(face);
|
||||
}
|
||||
else
|
||||
{
|
||||
notify(WARN)<<"Error: glActiveStencilFace not supported by OpenGL driver"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include <osgShadow/OccluderGeometry>
|
||||
|
||||
#include <osg/Notify>
|
||||
@@ -23,6 +27,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
using namespace osgShadow;
|
||||
|
||||
OccluderGeometry::OccluderGeometry()
|
||||
@@ -762,7 +767,7 @@ void OccluderGeometry::computeShadowVolumeGeometry(const osg::Vec4& lightpos, Sh
|
||||
// directional light.
|
||||
osg::Vec3 lightdirection( -lightpos.x(), -lightpos.y(), -lightpos.z());
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Directional light"<<std::endl;
|
||||
// osg::notify(osg::NOTICE)<<"Directional light"<<std::endl;
|
||||
|
||||
// choose the base plane
|
||||
const osg::Polytope::PlaneList& planes = _boundingPolytope.getPlaneList();
|
||||
@@ -822,12 +827,12 @@ void OccluderGeometry::computeShadowVolumeGeometry(const osg::Vec4& lightpos, Sh
|
||||
|
||||
osg::Plane basePlane(0.0, 0.0, 1.0, 0.0);
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Positional light"<<std::endl;
|
||||
// osg::notify(osg::NOTICE)<<"Positional light"<<std::endl;
|
||||
UIntList silhouetteIndices;
|
||||
computeLightPositionSlihouetteEdges(lightposition, silhouetteIndices);
|
||||
|
||||
osg::notify(osg::NOTICE)<<"basePlane "<<basePlane[0]<<" "<<basePlane[1]<<" "<<basePlane[2]<<" "<<basePlane[3]<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<"lightpos = "<<std::endl;
|
||||
// osg::notify(osg::NOTICE)<<"basePlane "<<basePlane[0]<<" "<<basePlane[1]<<" "<<basePlane[2]<<" "<<basePlane[3]<<std::endl;
|
||||
// osg::notify(osg::NOTICE)<<"lightpos = "<<std::endl;
|
||||
const osg::Polytope::PlaneList& planes = _boundingPolytope.getPlaneList();
|
||||
|
||||
for(UIntList::iterator itr = silhouetteIndices.begin();
|
||||
@@ -881,7 +886,7 @@ void OccluderGeometry::computeShadowVolumeGeometry(const osg::Vec4& lightpos, Sh
|
||||
svg.dirtyBound();
|
||||
|
||||
osg::Timer_t t1 = osg::Timer::instance()->tick();
|
||||
osg::notify(osg::NOTICE)<<"computeShadowVolumeGeometry "<<osg::Timer::instance()->delta_m(t0,t1)<<" ms"<<std::endl;
|
||||
// osg::notify(osg::NOTICE)<<"computeShadowVolumeGeometry "<<osg::Timer::instance()->delta_m(t0,t1)<<" ms"<<std::endl;
|
||||
}
|
||||
|
||||
void OccluderGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
@@ -918,7 +923,8 @@ osg::BoundingBox OccluderGeometry::computeBound() const
|
||||
//
|
||||
// ShadowVolumeGeometry
|
||||
//
|
||||
ShadowVolumeGeometry::ShadowVolumeGeometry()
|
||||
ShadowVolumeGeometry::ShadowVolumeGeometry():
|
||||
_drawMode(GEOMETRY)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -929,23 +935,60 @@ ShadowVolumeGeometry::ShadowVolumeGeometry(const ShadowVolumeGeometry& oc, const
|
||||
|
||||
void ShadowVolumeGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
renderInfo.getState()->disableAllVertexArrays();
|
||||
|
||||
renderInfo.getState()->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
|
||||
|
||||
if (!_normals.empty())
|
||||
if (_drawMode==GEOMETRY)
|
||||
{
|
||||
renderInfo.getState()->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) );
|
||||
osg::State* state = renderInfo.getState();
|
||||
|
||||
state->disableAllVertexArrays();
|
||||
|
||||
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
|
||||
|
||||
if (!_normals.empty())
|
||||
{
|
||||
state->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
glNormal3f(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
glColor4f(0.5f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
glDrawArrays( GL_QUADS, 0, _vertices.size() );
|
||||
}
|
||||
else
|
||||
else if (_drawMode==STENCIL_TWO_PASS)
|
||||
{
|
||||
glNormal3f(0.0f, 0.0f, 0.0f);
|
||||
osg::State* state = renderInfo.getState();
|
||||
|
||||
state->disableAllVertexArrays();
|
||||
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
|
||||
|
||||
// draw front faces of shadow volume
|
||||
glCullFace(GL_BACK);
|
||||
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR);
|
||||
|
||||
glDrawArrays( GL_QUADS, 0, _vertices.size() );
|
||||
|
||||
// draw back faces of shadow volume
|
||||
glCullFace(GL_FRONT);
|
||||
glStencilOp( GL_KEEP, GL_KEEP, GL_DECR);
|
||||
|
||||
glDrawArrays( GL_QUADS, 0, _vertices.size() );
|
||||
|
||||
state->haveAppliedAttribute(osg::StateAttribute::CULLFACE);
|
||||
state->haveAppliedAttribute(osg::StateAttribute::STENCIL);
|
||||
|
||||
}
|
||||
else // stencil two sided, note state all set up separately.
|
||||
{
|
||||
osg::State* state = renderInfo.getState();
|
||||
|
||||
state->disableAllVertexArrays();
|
||||
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
|
||||
|
||||
|
||||
glColor4f(0.5f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
glDrawArrays( GL_QUADS, 0, _vertices.size() );
|
||||
glDrawArrays( GL_QUADS, 0, _vertices.size() );
|
||||
}
|
||||
}
|
||||
|
||||
osg::BoundingBox ShadowVolumeGeometry::computeBound() const
|
||||
|
||||
Reference in New Issue
Block a user