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:
Robert Osfield
2007-01-18 22:32:18 +00:00
parent ba9e355550
commit ccc8a922a6
7 changed files with 514 additions and 65 deletions

View File

@@ -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
View 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;
}
}

View File

@@ -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