Implemented basic ShadowMap technique
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#define OSGSHADOW_SHADOWEMAP 1
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <osgShadow/ShadowTechnique>
|
||||
|
||||
@@ -30,9 +31,35 @@ class OSGSHADOW_EXPORT ShadowMap : public ShadowTechnique
|
||||
|
||||
META_Object(osgShadow, ShadowMap);
|
||||
|
||||
/** Set the texture unit that the shadow texture will be applied on.*/
|
||||
void setTextureUnit(unsigned int unit);
|
||||
|
||||
/** Get the texture unit that the shadow texture will be applied on.*/
|
||||
unsigned int getTextureUnit() const { return _textureUnit; }
|
||||
|
||||
|
||||
/** initialize the ShadowedScene and local cached data structures.*/
|
||||
virtual void init();
|
||||
|
||||
/** run the update traversal of the ShadowedScene and update any loca chached data structures.*/
|
||||
virtual void update(osg::NodeVisitor& nv);
|
||||
|
||||
/** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/
|
||||
virtual void cull(osgUtil::CullVisitor& cv);
|
||||
|
||||
/** Clean scene graph from any shadow technique specific nodes, state and drawables.*/
|
||||
virtual void cleanSceneGraph();
|
||||
|
||||
|
||||
protected :
|
||||
|
||||
virtual ~ShadowMap() {}
|
||||
|
||||
osg::ref_ptr<osg::Camera> _camera;
|
||||
osg::ref_ptr<osg::TexGen> _texgen;
|
||||
osg::ref_ptr<osg::Texture2D> _texture;
|
||||
osg::ref_ptr<osg::StateSet> _stateset;
|
||||
unsigned int _textureUnit;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class OSGSHADOW_EXPORT ShadowedScene : public osg::Group
|
||||
{
|
||||
public:
|
||||
|
||||
ShadowedScene();
|
||||
ShadowedScene(ShadowTechnique* st=0);
|
||||
|
||||
ShadowedScene(const ShadowedScene& es, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
|
||||
|
||||
|
||||
@@ -12,16 +12,267 @@
|
||||
*/
|
||||
|
||||
#include <osgShadow/ShadowMap>
|
||||
#include <osgShadow/ShadowedScene>
|
||||
#include <osg/Notify>
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/io_utils>
|
||||
|
||||
using namespace osgShadow;
|
||||
|
||||
ShadowMap::ShadowMap()
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
//
|
||||
char fragmentShaderSource_noBaseTexture[] =
|
||||
"uniform sampler2DShadow shadowTexture; \n"
|
||||
"uniform vec2 ambientBias; \n"
|
||||
"\n"
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n"
|
||||
"}\n";
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
//
|
||||
char fragmentShaderSource_withBaseTexture[] =
|
||||
"uniform sampler2D baseTexture; \n"
|
||||
"uniform sampler2DShadow shadowTexture; \n"
|
||||
"uniform vec2 ambientBias; \n"
|
||||
"\n"
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n"
|
||||
" gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n"
|
||||
"}\n";
|
||||
|
||||
ShadowMap::ShadowMap():
|
||||
_textureUnit(1)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique not implemented yet."<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique is in development."<<std::endl;
|
||||
}
|
||||
|
||||
ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop):
|
||||
ShadowTechnique(copy,copyop)
|
||||
ShadowTechnique(copy,copyop),
|
||||
_textureUnit(copy._textureUnit)
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowMap::setTextureUnit(unsigned int unit)
|
||||
{
|
||||
_textureUnit = unit;
|
||||
}
|
||||
|
||||
void ShadowMap::init()
|
||||
{
|
||||
if (!_shadowedScene) return;
|
||||
|
||||
unsigned int tex_width = 1024;
|
||||
unsigned int tex_height = 1024;
|
||||
|
||||
_texture = new osg::Texture2D;
|
||||
_texture->setTextureSize(tex_width, tex_height);
|
||||
_texture->setInternalFormat(GL_DEPTH_COMPONENT);
|
||||
_texture->setShadowComparison(true);
|
||||
_texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
|
||||
_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
|
||||
_texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
|
||||
|
||||
// set up the render to texture camera.
|
||||
{
|
||||
// create the camera
|
||||
_camera = new osg::Camera;
|
||||
|
||||
_camera->setCullCallback(new CameraCullCallback(this));
|
||||
|
||||
_camera->setClearMask(GL_DEPTH_BUFFER_BIT);
|
||||
//_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
|
||||
_camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
|
||||
// set viewport
|
||||
_camera->setViewport(0,0,tex_width,tex_height);
|
||||
|
||||
// set the camera to render before the main camera.
|
||||
_camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
|
||||
// tell the camera to use OpenGL frame buffer object where supported.
|
||||
_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
//_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
|
||||
|
||||
// attach the texture and use it as the color buffer.
|
||||
_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
|
||||
|
||||
osg::StateSet* stateset = _camera->getOrCreateStateSet();
|
||||
|
||||
float factor = 0.0f;
|
||||
float units = 1.0f;
|
||||
|
||||
osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
|
||||
polygon_offset->setFactor(factor);
|
||||
polygon_offset->setUnits(units);
|
||||
stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
|
||||
cull_face->setMode(osg::CullFace::FRONT);
|
||||
stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
_stateset = new osg::StateSet;
|
||||
_stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
_stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
|
||||
_stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
|
||||
_stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
|
||||
_stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
|
||||
|
||||
_texgen = new osg::TexGen;
|
||||
|
||||
#if 1
|
||||
osg::Program* program = new osg::Program;
|
||||
_stateset->setAttribute(program);
|
||||
|
||||
if (_textureUnit==0)
|
||||
{
|
||||
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
|
||||
program->addShader(fragment_shader);
|
||||
|
||||
osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit);
|
||||
_stateset->addUniform(shadowTextureSampler);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture);
|
||||
program->addShader(fragment_shader);
|
||||
|
||||
osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
|
||||
_stateset->addUniform(baseTextureSampler);
|
||||
|
||||
osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit);
|
||||
_stateset->addUniform(shadowTextureSampler);
|
||||
}
|
||||
|
||||
osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f));
|
||||
_stateset->addUniform(ambientBias);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
|
||||
void ShadowMap::update(osg::NodeVisitor& nv)
|
||||
{
|
||||
_shadowedScene->osg::Group::traverse(nv);
|
||||
}
|
||||
|
||||
void ShadowMap::cull(osgUtil::CullVisitor& cv)
|
||||
{
|
||||
// record the traversal mask on entry so we can reapply it later.
|
||||
unsigned int traversalMask = cv.getTraversalMask();
|
||||
|
||||
osgUtil::RenderStage* orig_rs = cv.getRenderStage();
|
||||
|
||||
// do traversal of shadow recieving scene which does need to be decorated by the shadow map
|
||||
{
|
||||
cv.pushStateSet(_stateset.get());
|
||||
|
||||
_shadowedScene->osg::Group::traverse(cv);
|
||||
|
||||
cv.popStateSet();
|
||||
|
||||
}
|
||||
|
||||
// need to compute view frustum for RTT camera.
|
||||
// 1) get the light position
|
||||
// 2) get the center and extents of the view frustum
|
||||
|
||||
const osg::Light* selectLight = 0;
|
||||
osg::Vec4 lightpos;
|
||||
|
||||
osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
|
||||
for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
|
||||
itr != aml.end();
|
||||
++itr)
|
||||
{
|
||||
const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
|
||||
if (light)
|
||||
{
|
||||
osg::RefMatrix* matrix = itr->second.get();
|
||||
if (matrix) lightpos = light->getPosition() * (*matrix);
|
||||
else lightpos = light->getPosition();
|
||||
|
||||
selectLight = light;
|
||||
}
|
||||
}
|
||||
|
||||
osg::Matrix eyeToWorld;
|
||||
eyeToWorld.invert(cv.getModelViewMatrix());
|
||||
|
||||
lightpos = lightpos * eyeToWorld;
|
||||
|
||||
if (selectLight)
|
||||
{
|
||||
|
||||
// get the bounds of the model.
|
||||
osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
|
||||
cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());
|
||||
|
||||
_shadowedScene->osg::Group::traverse(cbbv);
|
||||
|
||||
osg::BoundingBox bb = cbbv.getBoundingBox();
|
||||
|
||||
if (lightpos[3]!=0.0)
|
||||
{
|
||||
osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
|
||||
|
||||
float centerDistance = (position-bb.center()).length();
|
||||
|
||||
float znear = centerDistance-bb.radius();
|
||||
float zfar = centerDistance+bb.radius();
|
||||
float zNearRatio = 0.001f;
|
||||
if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
|
||||
|
||||
float top = (bb.radius()/centerDistance)*znear;
|
||||
float right = top;
|
||||
|
||||
_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
_camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
|
||||
_camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f));
|
||||
|
||||
|
||||
// compute the matrix which takes a vertex from local coords into tex coords
|
||||
// will use this later to specify osg::TexGen..
|
||||
osg::Matrix MVPT = _camera->getViewMatrix() *
|
||||
_camera->getProjectionMatrix() *
|
||||
osg::Matrix::translate(1.0,1.0,1.0) *
|
||||
osg::Matrix::scale(0.5f,0.5f,0.5f);
|
||||
|
||||
_texgen->setMode(osg::TexGen::EYE_LINEAR);
|
||||
_texgen->setPlanesFromMatrix(MVPT);
|
||||
}
|
||||
|
||||
|
||||
cv.setTraversalMask( traversalMask &
|
||||
getShadowedScene()->getCastsShadowTraversalMask() );
|
||||
|
||||
// do RTT camera traversal
|
||||
_camera->accept(cv);
|
||||
|
||||
orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, &cv.getModelViewMatrix(), _texgen.get());
|
||||
}
|
||||
|
||||
|
||||
// reapply the original traversal mask
|
||||
cv.setTraversalMask( traversalMask );
|
||||
}
|
||||
|
||||
void ShadowMap::cleanSceneGraph()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ ShadowTexture::ShadowTexture(const ShadowTexture& copy, const osg::CopyOp& copyo
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowTexture::setTextureUnit(unsigned int unit)
|
||||
{
|
||||
_textureUnit = unit;
|
||||
}
|
||||
|
||||
void ShadowTexture::init()
|
||||
{
|
||||
if (!_shadowedScene) return;
|
||||
@@ -64,7 +69,7 @@ void ShadowTexture::init()
|
||||
|
||||
// tell the camera to use OpenGL frame buffer object where supported.
|
||||
_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
//_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
|
||||
_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
|
||||
|
||||
// attach the texture and use it as the color buffer.
|
||||
_camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
|
||||
|
||||
@@ -21,15 +21,27 @@
|
||||
|
||||
using namespace osgShadow;
|
||||
|
||||
ShadowedScene::ShadowedScene()
|
||||
ShadowedScene::ShadowedScene(ShadowTechnique* st):
|
||||
_recievesShadowTraversalMask(0xffffffff),
|
||||
_castsShadowTraversalMask(0xffffffff)
|
||||
{
|
||||
setNumChildrenRequiringUpdateTraversal(1);
|
||||
|
||||
if (st) setShadowTechnique(st);
|
||||
}
|
||||
|
||||
ShadowedScene::ShadowedScene(const ShadowedScene& copy, const osg::CopyOp& copyop):
|
||||
osg::Group(copy,copyop)
|
||||
osg::Group(copy,copyop),
|
||||
_recievesShadowTraversalMask(copy._recievesShadowTraversalMask),
|
||||
_castsShadowTraversalMask(copy._castsShadowTraversalMask)
|
||||
{
|
||||
setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
|
||||
setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
|
||||
|
||||
if (copy._shadowTechnique.valid())
|
||||
{
|
||||
setShadowTechnique( dynamic_cast<osgShadow::ShadowTechnique*>(copy._shadowTechnique->clone(copyop)) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ShadowedScene::~ShadowedScene()
|
||||
|
||||
Reference in New Issue
Block a user